pax_global_header00006660000000000000000000000064145577570300014527gustar00rootroot0000000000000052 comment=0f62166098716e2de25b532018d50b364ff90cba pgtap-1.3.2/000077500000000000000000000000001455775703000126455ustar00rootroot00000000000000pgtap-1.3.2/Changes000066400000000000000000001411231455775703000141420ustar00rootroot00000000000000Revision history for pgTAP ========================== 1.3.2 2024-02-04T18:59:37Z -------------------------- * Replaced the C `parse_type()` function added in v1.3.1 with a PL/pgSQL function, eliminating the need for the the installing use to be a superuser. Aliases still work for all data types passed to `col_type_is()` except for intervals, which must be specified exactly as rendered by Postgres itself, without aliasing. Thanks to @spencerbryson for the report (#328) and to Erik Wienhold for the PL/pgSQL technique necessary to properly format type strings (#315). * Added tests to ensure that that the function-testing assertions also support procedures and noted the fact where appropriate in the documentation. Thanks to @hettie-d for the call-out (#329)! 1.3.1 2023-09-24T15:29:42Z -------------------------- * Revamped the handling of data type declarations in `col_type_is()` to always accurately normalize data type representations, whether using aliases, such as `varchar` for `character varying`, or more complicated types that failed to work in v1.3.0, such as `interval second(0)`. This is done by delegating the parsing of the type declaration to a core PostgresSQL function. Many thanks to Erik Wienhold for the report and for ultimately uncovering and implementing an SQL interface to the `parseTypeString()` core function (#315). * Removed the documentation for `pg_typeof()`, which was removed from pgTAP when support for PostgreSQL 8.3 was dropped, since the same function has been available in the PostgreSQL core since then. * Improved the support for type name aliases to the following functions: * `has_cast()` * `hasnt_cast()` * `cast_context_is()` * `domain_type_is()` * `domain_type_isnt()` * `has_operator()` * `hasnt_operator()` * Added the `has_pk( :schema, :table )` variant, which requires that `:table` be cast to `name` to avoid confusion with the `has_pk( :schema, :description )` variant. Thanks to Adrian Klaver for the report (#287)! 1.3.0 2023-08-14T22:14:20Z -------------------------- * Fixed an issue with xUnit tests where they would exit immediately on unexpected errors (aside from PL/pgSQL RAISE errors) rather than exit just the current test function. Thanks to @kzathey for the report and to @fjf2002 for the analysis. * Fixed a pluralization error reporting xUnit test failures to report "failed 1 test" instead of "failed 1 tests". * Removed the indentation for diagnostic comments at the start of subtests to make it easier to see where they start and end. This changes the output format, which will not affect tests run by `pg_prove`, but will break tests that depend on diffing files, as `pg_regress` does. Thanks to Matt DeLuco for highlighting the visual confusion of the indented diagnostic (#264). * Added variants of `col_is_pk()` with schema and without description (variants without schema or description already existed). Thanks to Luca Ferrari and Matteo Ferrando for the PRs (#178 & #199)! * Added a note on the use of temporary tables to the `fk_ok()` documentation, as well as a test to ensure the suggested expressions work. Thanks to Jim Nasby for highlighting the special treatment of the temporary schema (#109). * Removed redundant `DROP` statements from the 1.2.0 upgrade script that prevented upgrades from working properly. Thanks to @robins for the PR (#300)! * Fixed a test failure caused by the removal of support for select rules in postgres/postgres@b23cd18 (expected in Postgres 16). Thanks to @Deltaus for the report (#309)! * Fixed `LIKE` expression in `schemas_are()` to escape the underscore wildcard, making it `pg\_%` instead of `pg_%`. Thanks to Jehan-Guillaume (ioguix) de Rorthais for the PR (#311)! * Updated function-testing functions to allow short names for argument types, so that they can be specified as, e.g., `int` and `bool` rather than `integer` and `boolean`. The return value argument to `function_returns` and and data type tests such as `col_type_is` and `cast_context_is` must still use full type names. Thanks to @wphilips53 for the suggestion (#292). * Updated type-testing functions to allow short names for types, and updated function-testing functions to allow short names for argument types. This means that common aliases for standard types can be specified as, e.g., `int` and `bool` rather than `integer` and `boolean`. Thanks to @wphilips53 for the suggestion (#292). * Tweaked the installation docs for Docker, binary Linux distributions, and downloading the source from PGXN. Thanks to @jed-walker-icd (#275) and @machineghost (#301) for the suggestions! 1.2.0 2021-12-05T18:08:13Z -------------------------- * Made the description field optional in `has_view()` and `hasnt_view()` when specifying schema (#230). Thanks to Godwottery for the patch! * Added support for the date and time keywords `CURRENT_DATE`, `CURRENT_TIME`, `CURRENT_TIMESTAMP`, `LOCALTIME`, and `LOCALTIMESTAMP` to `col_default_is()`. Thanks to Kevin Brannen for the report (#244)! * Fixed failure to run tests on Postgres 13. Thanks to Christoph Berg for the report (#248). * Documented that mixed-case column names created with double quotes must be double-quoted when passed to `has_index()` or `is_indexed()`, sadly unlike other column arguments in pgTAP. Thanks to Keith Fiske for the report (#247). * Fixed test failures where the current username was not being quoted as an identifier. Thanks to Matt DeLuco for the report (#216) and pull request (#259)! * Fixed the `col_not_null()` drop statements in the uninstall script. Thanks to Kyle L. Jensen for the report (#252). * Removed straggler references to Postgres 9.0 and earlier, including conditional tests. * Updated all relevant URLs to use https instead of http. * Added instructions to install the extension on a host with PostgreSQL running and with the contrib modules installed. Thanks to F. Eugene Aumson for the report (#276). * Fixed test failures due to changes in PostgreSQL 14. Thanks to Christoph Berg for the report (#277). * Added `isnt_member_of()` (#38, #204). Thanks to Wolfgang Walther for the pull request (#249). * Added docker files for local test environment. Thanks to Wolfgang Walther for the pull request (#250). * Added `hasnt_operator()`, `hasnt_leftop()`, `hasnt_rightop()` (#38). Thanks to Wolfgang Walther for the pull request (#251). * Improved the output of `results_eq()` and `results_ne()` when the number of columns or their types are different (#37). Thanks to Wolfgang Walther for the pull request (#255). * Fixed testing issue where tests for unsupported features were not properly skipped on Postgres 9.6 and earlier. Only appeared when tests were run serially (#279). * Fixed an issue where tests might not run in parallel even when the server supported it (#279). 1.1.0 2019-11-25T19:05:38Z -------------------------- * Remove support for PostgreSQL older than 9.1. Note that some automated tests don't run on versions older than 9.4, so it's recommended you run PostgreSQL 9.4 at minimum. * Add a `throw_exception` argument to `finish()`. `finish(true)` will raise an exception if any tests failed. Thanks to Stephen Paul Weber for the idea (#80), and Rodolphe Quiédeville for most of the work (#104)! * Make description optional for `col_not_null()` (#221). * Fix syntax of test_user function example in the docs (#208). Thanks to PeteDevoy for the patch! * Fix issue with `pgtap-core` referencing `pg_proc.proisagg` on PostgreSQL 11+ (#197). * Add PostgreSQL 12.0 to automated tests (#223). * Fix `pgtap_version()`, which incorrectly returned 0.99 when upgrading from version 0.99.0 to 1.0.0 (#214). * Fix issue with using `pg_upgrade` to PostgreSQL 11+ with pgTAP installed (#201, #215). * Start using `DEFAULT` in functions. * Add automated testing of extension upgrade scripts (#128), as well as testing of `pg_upgrade` with pgTAP installed (#218, #222). 1.0.0 2019-02-21T22:39:42Z -------------------------- * Fixed uninstall script generation to properly emit `DROP TYPE` statements. Thanks to Kamen Naydenov for the PR (#181)! * Added policy test assertion functions for PostgreSQL 9.5 and higher: + `policies_are()` + `policy_roles_are()` + `policy_cmd_is()` Thanks to Kamen Naydenov for the PR (#185). * Fixed an issue with `has_function()` where a test would fail if arguments are schema-qualified even though the schema is in the search path. Thanks to Sandro Santilli for the bug report (#179) and PR (#180). * Added table inheritance testing functions: + `has_inherited_tables()` + `hasnt_inherited_tables()` + `is_ancestor_of()` + `isnt_ancestor_of()` + `is_descendent_of()` + `isnt_descendent_of()` Thanks to Luca Ferrari for the inspiration. * Fixed `col_default_is()` to properly report special SQL syntax functions like `CURRENT_USER` and `CURRENT_CATALOG` instead of evaluating them on PostgreSQL 10 and higher. * Changed the uninstall script to use `DROP IF EXISTS` rather than just `DROP` so that it works even with partial or failed installs. Thanks to Sandro Santilli for the PR (#194). * Officially end support for PostgreSQL 8.2 and older. 0.99.0 2018-09-16T20:55:41Z --------------------------- * Updated introductory documentation. A lot has changed over the years! * Added the "Secrets of the pgTAP Mavens" section of the documentation. Contributions wanted! * Fixed `pg_version_num()` to always return the value of `server_version_num` on PostgreSQL 8.3 and higher, thus fixing a test failure on 10.1. Thanks to Christoph Berg for the report (#148)! * Changed the diagnostic output of extra and missing values from the `*_are()` functions to sort the extra and missing values. Fixes a test failure on PostgreSQL 10, and generally makes the diagnostics more deterministic and easier to read. Thanks to Michael Glaesemann for the report (#158)! * Fixed an issue on PostgreSQL 11, where the `pg_class.relhaspkey` column has been removed. The primary key testing functions now refer to `pg_index.indisprimary`, instead. Thanks to Keith Fiske for the report (#174)! * Fixed an issue on PostgreSQL 11, where the `pg_proc.proisagg` column has been replaced with the more generically useful `pg_proc.prokind`. Thanks to Keith Fiske for the report (#174)! * Documented that a `RECORD` can be passed to `row_eq()` on PostgreSQL 11, and fixed the tests to match this new functionality. * Removed tests that only ran on 8.0, support for which was discontinued in v0.90.0. * Removed `test/sql/run*` tests, which intentionally fail, from the `test` target in the `Makefile`. It's not meaningful to test them via `pg_prove`; they must instead be tested by `make installcheck`, so their output can be compared against output that varies by PostgreSQL version. Thanks to Jim Nasby for the report (#172). * Fixed a bug where `have_fk()` would fail if the table had no primary key. Thanks to @bigmodem for the report! (#171). 0.98.0 2017-11-06T22:30:54Z --------------------------- * `make install` once again properly installs the versioned SQL file required by `CREATE EXTENSION`. Thanks to Keith Fiske for the reports (Issue #131, Issue #143) and Jim Nasby for the fix (Issue #132). * Removed references to the Epic test framework, since its domain (`epictest.org`) has expired and the project appears to no longer be available online. Thanks to Andreas Brekken for the report (#140). * Fix failing version tests on PostgreSQL v10. Thanks to Erik Rijkers for the patch. * Improved foreign tables test to account for varying message order for diagnostic output. Thanks to Erik Rijkers for the patch. * Clarified the use of the `:schema` parameter to the extension-testing functions in the documentation. Required since extensions do not belong to schemas, but their objects may be specifically created in a schema. Thanks to Jim Nasby for the report (#121)! * Updated the table-testing functions to also recognize partitioned tables: + `has_table()` + `hasnt_table()` + `tables_are()` + `table_owner_is()` * Added partition-testing assertion functions: + `is_partitioned()` + `isnt_partitioned()` + `is_partition_of()` + `partitions_are()` * Added the materialized view-testing assertion functions to the v0.95.0 upgrade script; they were inadvertently omitted in the v0.95.0 release. * Fixed failing tests on Postgres 8.1. * Added function type testing functions to complement `is_aggregate()` and `isnt_aggregate()`: + `is_normal_function()` + `isnt_normal_function()` + `is_window()` + `isnt_window()` + `is_procedure()` + `isnt_procedure()` * Made the diagnostic output of `is_aggregate()` and `isnt_aggregate()` consistent. Previously, when the function did not exist, some instances would generate diagnostic output and some would not. 0.97.0 2016-11-28T22:18:29Z --------------------------- * Fixed the default description for `hasnt_opclass()` to say "should not exist" instead of "should exist", thanks to Rodolphe Quiédeville (PR #99). * Added `is_indexed()`, which tests to see if specific table columns are indexed. It's effectively the same as `has_index()` except that it doesn't require an index name and does require one or more column names or index expressions. Thanks to Rodolphe Quiédeville (PR #103). * Fixed `pg_version_num()` to work with the new version format coming in PostgreSQL 10. * Fix `lives_ok()` and `throws_ok()` to also trap `ASSERT_FAILURE` (PR #119). * Add negation functions `isnt_aggregate()` and `isnt_definer()`, which return the opposite of `is_aggregate()` and `is_definer()`. Thanks to Rodolphe Quiédeville (PR #106). * Add `has_extension()` and `hasnt_extension()`. Thanks to Rodolphe Quiédeville (PR #101). 0.96.0 2016-05-16T20:53:57Z --------------------------- * Added an optional `:exclude_pattern` parameter to `findfuncs()` to prevent matching of some functions. This is useful to prevent matching startup/setup/teardown/shutdown functions. Patch from Jim Nasby. * Changed `runtests()` to use the new `:exclude_pattern` to prevent the running of startup/setup/teardown/shutdown functions as test functions. Patch from Jim Nasby. * Fixed `database_privs_are()`, `schema_privs_are()`, `tablespace_privs_are()` `fdw_privs_are()`, and `server_privs_are()` to properly handle case-sensitive object names. Thanks to Ingo for the report! * Updated the Makefile to handle the case when PGXS sets the PERL variable to `missing perl`. * Fixed a test failure due to the use of a hash index on PostgresSQL 9.5. * Added `extensions_are()`, prompted by a pull request from Grégoire HUBERT (Issue #98). * The `sql/unininstall_pgtap.sql` file is now generated by `make` from the `sql/pgtap.sql` file. This should make it much more up-to-date and accurate in the future. * Added full stack diagnostic output to the `lives_ok()` failures, as well as xUnit test function errors. Patch from Jim Nasby. 0.95.0 2015-03-20T20:31:41Z --------------------------- * Added materialized view-testing assertion functions: + `materialized_views_are()` + `has_materialized_view()` + `hasnt_materialized_view()` + `materialized_view_owner_is()` Thanks to Charly Batista for the contribution! * Added `performs_within()`, a function that tests the average performance of an SQL statement over a number of iterations. Contributed by Ryan Duryea. * Changed `is_member_of()` to work with roles instead of users. Patch from Jim Nasby. * Granted SELECT access to the views created by pgTAP to PUBLIC, to avoid permission errors when the tests are run by a user other than the owner of those views. Thanks to Jim Nasby for the report. * Added `foreign_tables_are()` functions. Thanks to Chad for the pull request! * Updated `enum_has_labels()` to properly sort labels added by `ALTER TYPE ADD VALUE`. * Added `diag_test_name()` to `pgtap-core`, since it's called by `_runner()` in that extension. Thanks to Jim Nasby for the spot. * Added `isnt_strict()` to complement `is_strict()`. Requested by Jim Nasby. * Added schema/table/column variations of `col_is_unique()`. Contributed by Jim Nasby. * The `runtests()` function now executes each test as a TAP subtest, with its own plan and test count. This allows each test function to function more independently of the others. It's easier to read the TAP, too. Users of xUnit-style tests with `pg_regress` will need to update their expected output files, however. * An exception thrown by a test no run by `runtests()` no longer halts execution. It is instead properly rolled back, reported as a subtest failure, and the error message emitted as a diagnostic message. Thanks to Vitaliy Kotov for the report. * Eliminated the temporary table `__tresults__`. Test results are no longer written to a table, but simply emitted. This elimination of unnecessary I/O should make tests run a bit faster. * Added missing functions `has_sequence(:schema, :sequence)` mentioned in the docs (Issue #58): 0.94.0 2014-01-07T01:32:36Z --------------------------- * Fixed the Makefile to allow `PG_CONFIG=/path/to/pg_config` to actually work. Patch from Aaron W. Swenson. * Eliminated superfluous tabs in the `Makefile` that could cause it to fail in some situations. Patch from Eric Neault. * Fixed `function_privs_are() to work with functions with long names and/or signatures. Thanks to Jörg Beyer for the detailed report. * Added missing functions mentioned in the docs (Issue #54): + `has_table(:schema, :table)` + `hasnt_table(:schema, :table)` + `has_foreign_table(:schema, :table)` + `hasnt_foreign_table(:schema, :table)` * Fixed the format of SKIP output to match the [TAP spec](https://testanything.org/tap-specification.html#skipping-tests). * Fixed incorrect handling of leading space when comparing diagnostic output in `check_test()`. * Fixed an installation issue on PostgreSQL 9.3.2. 0.93.0 2013-01-28T20:14:58Z --------------------------- * Added additional ownership-testing functions: + `tablespace_owner_is()` + `schema_owner_is()` + `index_owner_is()` + `language_owner_is()` + `opclass_owner_is()` + `type_owner_is()` * Fixed misselling of "constraint" in constraint test diagnostic output. * Fixed constraint, trigger, index, opclaass, and foreign key test functions so that they don't find objects outside the search path unless the schema is specified. * Fixed `col_type_is()` so that it won't report the column as not existing when the column's data type is not in the search path. * Removed `format_type()` and switched to the core PostgreSQL type formatting function so that type names always include the schema name if the schema is not in the search path. You might have to update data type tests to include the schema name if the type is not in the search path. * `ALTER EXTENSION` now properly updates the value returned by `pgtap_version()`. * Removed `CREATE EXTENSION` support for `pgtap-core` and `pgtap-control` (by deleting `pgtap-core.control` and `pgtap-schema.control`). There were never upgrade scripts for them, and upgrade scripts would be difficult to maintain anyway. These files are really designed for copying into other projects for inline testing support. 0.92.0 2013-01-16T00:41:07Z --------------------------- * Fixed some misspellings of `SELECT` in documentation examples. * Added note about the lack of typemods to the documentation for `has_cast()`. * Added check to ensure a table is visible in tests for column defaults. Thanks to Henk Enting for the report. * Added `has_relation()` and `hasnt_relation()`. * Added `has_foreign_table()` and `hasnt_foreign_table()`. * Added `has_composite()` and `hasnt_composite()`. * Added new ownership assertion functions: + `relation_owner_is()` + `table_owner_is()` + `view_owner_is()` + `sequence_owner_is()` + `composite_owner_is()` + `foreign_table_owner_is()` + `function_owner_is()` * Changed the uninformative error 'relation "__tcache__" does not exist' to the more useful 'You tried to run a test without a plan! Gotta have a plan'. Thanks to Steven Samuel Cole for [the report](https://github.com/theory/pgtap/issues/22). * Changed `triggers_are()` so that it ignores internal triggers on PostgreSQL 9.1 and higher. Thanks to Sherrylyn Branchaw for the report! * Changed the diagnostic output of `results_eq()` for data type differences to reduce confusion when the rows have the same values of different types. Thanks to Peter Eisentraut and Taylor Ralston for [the nudging](https://github.com/theory/pgtap/issues/15). * Added `isnt_empty()` to ensure that a query does not return the empty set. * Fixed `has_index()` to properly handle indexes composed of both columns and expressions. * Added new functions for testing a user's access to database objects: + `database_privs_are()` + `tablespace_privs_are()` + `schema_privs_are()` + `table_privs_are()` + `sequence_privs_are()` + `any_column_privs_are()` + `column_privs_are()` + `function_privs_are()` + `language_privs_are()` + `fdw_privs_are()` + `server_privs_are()` 0.91.1 2012-09-11T00:26:52Z --------------------------- * The OS name is restored to the call to `os_name()`. The `getos.sh` shell script was not getting called during `make`. Thanks to Peter Eisentraut for [the report](https://github.com/theory/pgtap/issues/16). * Noted `pg_prove --verbose` for showing test descriptions and fixed a few typos in the documentation. Thanks to Jay Levitt for the pull request! * Fixed broken examples in the `row_eq()` documentation. Thanks to @set5think for the report! * Fixed `has_tablespace()` to work on PostgreSQL 9.2, where its failure was preventing pgTAP from even being installed. 0.90.0 2011-12-03T20:18:16Z --------------------------- * Removed the "Supported Versions" section of the documentation. Suffice it to say that pgTAP supports PostgreSQL 8.1 or higher. * Added a build target to create a portable copy of pgTAP that can be included in any distribution and should just work for tesing on PostgreSQL 8.3+. The new files are `pgtap-core.sql`, which contains the core functionality, and `pgtap-schema.sql`, which depends on pgtap-core and adds in the schema testing assertion functions. * Added abstract to the `provides` section of `META.json`. * Removed use of `relistemp` column in an internal function, as it has been removed in PostgreSQL 9.1. As a bonus, it now works on PostgreSQL 8.3 and older without needing to be patched. Thanks to Tom Lane for the alternate syntax. * Added PostreSQL 9.1 `CREATE EXTENSION` support. * Removed `TAPSCHEMA` option to `make`. Use `PGOPTIONS=--search_path=tap` with `psql`, instead. * Added `db_owner_is()`. Based on a patch by Gerd Koenig. * Dropped support for PostgreSQL 8.0, as the new directory structure introduced in 0.25.0 is incompatible with the 8.0 version og `pg_regress`, making testing all but impossible. 8.0 has been EOLed for some time, so it's time for pgTAP to finally drop its support, too. 0.25.0 2011-02-02T03:21:55Z --------------------------- * Minor documentation tweaks. * The sequence created to keep track of test numbers is now a temporary sequence. This will prevent it from persisting beyond the current connection, which could lead to erorrs in future connections. Thanks to Richard Huxton for the report. * Fixed `is_superuser()` and `isnt_superuser()` so that they properly detect superuser roles as well as users. * Fixed examples of single-quoted string values stored in `psql` variables in `README.pgtap`. * Fixed a bug in `plan()` where a sequence wasn't getting created as a temporary sequence. This wasn't a problem if all testing was done inside a transaction, but if not, you could only run tests once without an error. * Fixed bug where `has_column()`, `col_type_is()`, `domain_type_is()`, `cast_exists()`, `cast_context_is()`, and `has_operator()`, were forcing the type argument to lowercase, which wasn't correct when the type is actually mixed case or uppercase (that is, named in double quotes when it was created). * The expected type passed to `index_is_type()` is no longer compared case-insensitively, since it might be possible in the future to create a type with mixed case by using double quotes when naming it. * Documented that double-quotes must be used for types created with double-quoted names in the strings passed to `casts_are()`. This should be the only part of the API that does require this sort of quoting. * Added `diag(anyelement)` (for 8.3 and higher) and `diag(VARIADIC anyarray)` (for 8.4 and higher) to make it easier to emit diagnostics for whatever data you have at hand. * The `_cleanup()` function now properly drops the temporary sequences as well as the temporary tables. These are usually automatically dropped when the tests finish and the client disconnects, but it's best to try to keep things tidy ourselves, too. Spotted by Peter Eisentraut. * Fixed a bug in `has_pk()` so that it properly checks that a table is visible in the search path when a schema is not specified, and doesn't check that when the schema *is* specified. Patch from Cédric Villemain. * Fixed a bug in `col_is_unique()` and `col_has_check()` where they considered *all* columns in a table that were unique or involved in a check constraint were assocated with only one constraint. Since one can have multiple unique or check constraints on a table, each using different columns, this was sub-optimal. Thanks to Cédric Villemain for the spot! * Removed `pg_prove` and `pg_tapgen` from the distribution. They must now be installed separately from CPAN. If it's not installed, the intaller will issue a warning. * Added `META.json` and distributed on [PGXN](https://pgxn.org/). * Rearranged the source directory layout to more closely match the [preferred PGXN layout](http://manager.pgxn.org/howto#new-order). 0.24 2010-05-24T23:33:22Z -------------------------- * Got `sql/artap.sql` tests passing again when building with `$TAPSCHEMA` set. * Changed to nicer source URL in `contrib/pgtap.spec`. * Fixed a bug in `has_member()` where it failed to confirm that users were actually members of a group. * Fixed a bug where `display_type()` would include the schema name in its output for types not found in the current path, despite its assertion that it wouldn't. * Changed the diagnostic output for row type mismatches from `set_eq()`, `set_ne()`, `bag_eq()`, and `bag_ne()` to include the schema name for types not found in the search path. * Fixed bug in the diagnostic output of `set_eq()`, `set_ne()`, `bag_eq()`, and `bag_ne()` where a column's type would not be displayed if the column was not in the search path. Thanks to Rod Taylor for the spot! * Made the implementation of `row_eq()` always return a value, even if the query it executes returns no rows. * Fixed bug in the default description for `col_type_is()` where the column name was listed as the type! * Updated the `Makefile` and the test suite to support PostgreSQL 9. * Removed the primary keys from the temporary tables used internally by pgTAP and thus eliminated the logging of NOTICEs to the PostgreSQL log when pgTAP creates those tables. * Eliminated the need to set `USE_PGXS=1` when building outsde the contrib directory of the PostgreSQL distribution. If `pg_config` isn't in the `$PATH` environment variable, one can simply set `PG_CONFIG` to point to it. If building inside the contrib directory, set `NO_PGXS=1`. * Fixed typo in the statement to drop the `tap_funky` view in `uninstall_pgtap.sql`. Thanks to Erik Rijkers. * Removed deprecated `can_ok()` functions. Use `has_function()`, instead. 0.23 2009-12-18T23:03:39Z ------------------------- * Fixed broken Perl detection in `Makefile`. * Copied OS detection from Perl's `Configure` script to new script, `getos.sh`. OS detection should now be much more accurate. * Fixed `pg_prove` to exit with non-zero status if tests failed, as it works better in automated testing environments and consistent with `prove` (fix by Darrell Fuhriman). * Updated documentation of supported environment variables in `bin/pg_prove`. * Fixed a bug in the function tests where the return value of a function was not always consistently formatted. For example, `function_returns()` would find "bool" instead of "boolean". * Added `isa_ok()`. * Added support for building against 8.5 [Dan Colish]. * Fixed failing test on alpha releases [Jonathan Leto] * Added `is_empty()` to test that a query returns an empty set (no results). * Added `collect_tap()`, which makes it easier to run multiple tests in a single `SELECT` statement in combination with `skip()`. * Added `throws_like()`, `throws_ilike()`, `throws_matching()`, and `throws_imatching()` to test that an SQL statement throws an error message matching a `LIKE` pattern or a regular expression. * Added `roles_are()`, `types_are()`, `domains_are()`, `enums_are()`, `triggers_are()`, `casts_are()`, `operators_are()`, and `columns_are()`. * Fixed the diagnostic output from `isnt()` and `col_isnt_pk()` when they fail. They now more closely matches what Test::More's `isnt()` outputs and makes much more sense. * Added `domain_type_is()` and `domain_type_isnt()`. Based on an implementation by Bob Lunney. * Added variants of `col_is_type()` to allow a schema name to be specified for the type. * Added `display_type()` and replaced all internal use of `format_type()` with it. This is so that schemas are always displayed properly. * Added `row_eq()`. It's a 90% solution that requires that `record` values be cast to existing composite values. But it should work well even at that. * Changed the default descriptions output by `has_operator()`, `has_leftop()`, and `has_rightop()` to format the operator names more like the display of `regoperator` types. * Fixed issue with using SET SESSION AUTHORIZATION among tests [Kevin Field] * Added `display_oper()` so that schemas are always displayed properly when comparing operators. 0.22 2009-07-31T00:26:16Z ------------------------- * Fixed failing test on 8.4rc2. * Added result set testing functions. These allow testers to write queries in pure SQL and check that their results are as expected. The new functions are: + `results_eq()` + `results_ne()` + `set_eq()` + `bag_eq()` + `set_ne()` + `bag_ne()` + `set_has()` + `bag_has()` + `set_hasnt()` + `bag_hasnt()` * Changed some internal queries to use explicit `JOIN`s. * Fixed capitalization of `TAP::Harness` in the `Makefile`. Thanks to Quinn Weaver. * Fixed a syntax error that caused `uninstall_pgtap.sql` to fail on older PostgreSQL versions (fix by Quinn Weaver). * Modified the summary documentation for the `--schema` and `--match` options to `pg_prove` to better reflect that they are for finding xUnit tests, not for finding pgTAP functions. 0.21 2009-05-29T00:04:31Z ------------------------- * Fixed a bug in the processing of the `--schema` and `--match` options that only shows up in Getopt::Long 2.38 or higher. * A few doc and test typos fixed thanks to Gabrielle Roth. * Fixed failing test on Solaris 10 on Intel thanks to Gabrielle Roth. * Fixed a failing test for the version number string on 8.4 beta. * Added `performs_ok()`. * Added `has_language()`, `hasnt_language()`, and `language_is_trusted()`. * Added `has_opclass()` and `hasnt_opclass()`. * Added `has_rule()`, `hasnt_rule()`, `rule_is_instead()`, and `rule_is_on()`. * Added `tablespaces_are()`, `schemas_are()`, `tables_are()`, `views_are()`, `sequences_are()`, `functions_are()`, `indexes_are()`, `users_are()`, `groups_are()`, `opclasses_are()`, `languages_are()`, and `rules_are()`. * Added a `has_trigger(table, trigger, description)`. Note that this means that if you were previously using `has_trigger(schema, table, trigger)`, you will need to cast the third argument to `NAME` to get it working again. * Changed `can_ok()` to `has_function()`, so that it's named like all of the other functions that check for the presence of database objects. The old `can_ok()` function is still available as an alias, but it emits a warning and will be removed in a future version of pgTAP. * Added `hasnt_trigger()`, `hasnt_index()`, and `hasnt_function()`. * Added `function_lang_is()`, `function_returns()`, `is_definer()`, `is_aggregate()`, `is_strict()`, and `volatility_is()`. 0.20 2009-03-29T19:05:40Z ------------------------- * Changed the names of the functions tested in `sql/do_tap.sql` and `sql/runtests.sql` so that they are less likely to be ordered differently given varying collation orders provided in different locales and by different vendors. Reported by Ingmar Brouns. * Added the `--formatter` and `--archive` options to `pg_prove`. * Fixed the typos in `pg_prove` where the output of `--help` listed `--test-match` and `--test-schema` instead of `--match` and `--schema`. * Added `has_cast()`, `hasnt_cast()`, and `cast_context_is()`. * Fixed a borked function signature in `has_trigger()`. * Added `has_operator()`, `has_leftop()`, and `has_rightop()`. * Fixed a bug where the order of columns found for multicolumn indexes by `has_index()` could be wrong. Reported by Jeff Wartes. Thanks to Andrew Gierth for help fixing the query. 0.19 2009-02-21T02:09:26Z ------------------------- * Added an alternate version of `col_default_is()` to better handle the common case when a default is specified as a string, such as a text or expression default. This means that you have to do a lot less casting of default values specified in the arguments to `col_default_is()`. It also restores the signature that 0.17 recommended be dropped. * Added `has_role()` and `isnt_role()`. * Added `has_user()`, `isnt_user()`, `is_superuser()`, and `isnt_superuser()`. * Added `has_group()`, `isnt_group()`, and `is_member_of()`. * Fixed syntax in the `Makefile` to make it compatible with older versions of `make`. Reported by Aaron Kangas. * Improved the documentation of `runtests()` to make it clearer that all tests it runs are run in transactions that are rolled back after each test. Suggested by Aaron Kangas. * Added the `--runtests`, `--schema`, and `--match` options to `pg_prove` so that it can be used to run xUnit-style test functions without an SQL script. * Fixed a bug in `can()` where it could sometimes report that functions were available in a schema when in fact they were not. * In the schema testing functions, removed the use of `quote_ident()` to compare all identifiers, such as table names, schema names, column names, etc, added in 0.17. This is because `quote_ident(a) = quote_ident(b)` can't give a different result than `a = b`, and besides, made things slower and prevented the use of indexes. Thanks to Andrew Gierth for the spot. * The output from `pg_prove` now includes a list of failing tests when it is not run with `--verbose`. When using TAP::Harness 3.17 and later, it also shows comments and diagnostics in the non-verbose output. Verbose output still outputs everything. 0.18 2009-02-06T20:06:00Z -------------------------- * Fixed `pg_version_num()`. It was broken in 0.16; sorry about that! * Fixed a bug in `col_type_is()` where it would die if it was looking for a type in a table that had dropped columns. Thanks to depesz and RhodiumToad on #postgresql for the help nailing that one down! * Fixed a test failure in `sql/coltap.sql` on PostgreSQL 8.3. * Fixed a bug in the `Makefile` where it did not properly point to `pg_config` when building from the `compat` directory in the PostgreSQL source tree. * Fixed a bug in the `Makefile` where the `test_setup.sql` file, which is required for tests, was not always getting created. 0.17 2009-02-06T17:51:52Z -------------------------- * Fixed `col_default_is()` so that it works properly in cases where the default value is `NULL`. * Fixed `col_default_is()` to gracefully handle different data types, columns without defaults, and nonexistent columns. * Fixed the three-argument form of `col_default_is()` to accept any data type for the default, not just text. *NOTE:* You must `DROP FUNCTION col_default_is ( NAME, NAME, TEXT );` if you have previous versions of this function installed, so as to eliminate the incompatible version. * Added `col_has_default()` and `col_hasnt_default()`. * Changed default descriptions for column testing functions to refer to the columns as the more SQL-standard `schema.table.column` instead of `schema.table(column)`. * Modified all diagnostic messages and test descriptions that reference database objects to use `quote_ident()` to quote the names of those objects, rather than emitting them with or without double-quotes in an ad-hoc way as had hitherto been the case. * Modified `col_not_null()`, `col_is_null()` and `col_type_is()` to emit diagnostics if they fail because the column in question does not exist. * Added `has_tablespace()` and `hasnt_tablespace()`. * Added `has_sequence()` and `hasnt_sequence()`. * Changed `has_index()` so that expressions are compared case- sensitively. * In the schema testing functions, now using `quote_ident()` to compare all identifiers, such as table names, schema names, column names, etc. It had been a mix of straight-forward string comparison, and case-insensitive matching. This means that tests should use only lowercase strings to specify object names, unless mixed case objects were created with double quote characters. * Added version of `todo()` with the `why` and `how_many` arguments reversed, so that I don't have to remember a specific order. 0.16 2009-02-03T17:37:03Z -------------------------- * Switched from a crazy trinary logic in `is()` and `isnt()` to the use of `IS NOT DISTINCT FROM` and `IS DISTINCT FROM`. Swiped from PGUnit. * Fixed documentation for the short version of `--help` in `pg_prove`. It's `-H`, not `-h`. * Fixed a bug in the makefile that prevented OS detection from working properly on many platforms (including Linux, and probably many others). This allows `os_name()` to actually work on those platforms. * The definition of the `pg_typeof()` function is removed when installing on PostgreSQL 8.4 and no C code is compiled, since the only C code is for this function. This is because `pg_typeof()` is included with PostgreSQL 8.4. * Added `has_schema()` and `hasnt_schema()`. * Added `has_type()`, `hasnt_type()`, `has_domain()`, `hasnt_domain()`, `has_enum()`, and `hasnt_enum()`. * Added `enum_has_labels()`. * Updated the `Makefile` to fix the shebang line in `pg_prove` if Perl is found, and to emit a warning if the `$PERL` variable is not set. - Updated the `Makefile` so that if `$PERL` is set and TAP::Harness is not installed, it warns the user to install it in order to use `pg_prove`. - Updated the `Makefile` to set the location of the `psql` binary to the bin directory specified for PostgreSQL when it was built. * Fixed `pg_version_num()` to work on PostgreSQL 8.4devel. * Fixed test failures on PostgreSQL 8.4devel. 0.15 2009-01-20T18:41:24Z -------------------------- * Changed `pg_typeof()` from immutable to stable, in compliance with its configuration in the forthcoming PostgreSQL 8.4. * Added `do_tap()`, which finds test functions and runs them, allowing tap tests to be embedded in functions and then executed all at once. * Added `runtests()`, which introduces xUnit-style test running, for those who prefer to put their tests in a slew of test functions and then run one function to run all of the test functions (plus startup, setup, teardown, and shutdown tests). * Added `findfuncs()`, which is used by `do_tap()` to find the functions to execute. * The `col_type_is()` function now requires that the type be visible in the search path when it is called without a schema argument. * The `plan()` function no longer resets the `client_min_messages` setting to its default value, but leaves it set to whatever it was set to before the function was called. * Fixed a typo in the documentation of the short version of the `--version` option to `pg_prove`, which is `-V`, not `-v`. * Added `pgtap_version()`. * Added the "html" make target to generate the HTML documentation for the Web site, including a table of contents and documentation for `pg_prove`. 0.14 2008-10-27T22:43:36Z -------------------------- * Added `SET search_path` statements to `uninstall_pgtap.sql.in` so that it will work properly when TAP is installed in its own schema. Thanks to Ben for the catch! * Added commands to drop `pg_version()` and `pg_version_num()` to`uninstall_pgtap.sql.in`. * Added `has_index()`, `index_is_unique()`, `index_is_primary()`, `is_clustered()`, and `index_is_type()`. * Added `os_name()`. This is somewhat experimental. If you have `uname`, it's probably correct, but assistance in improving OS detection in the `Makefile` would be greatly appreciated. Notably, it does not detect Windows. * Made `ok()` smarter when the test result is passed as `NULL`. It was dying, but now it simply fails and attaches a diagnostic message reporting that the test result was `NULL`. Reported by Jason Gordon. * Fixed an issue in `check_test()` where an extra character was removed from the beginning of the diagnostic output before testing it. * Fixed a bug comparing `name[]`s on PostgreSQL 8.2, previously hacked around. * Added `has_trigger()` and `trigger_is()`. * Switched to pure SQL implementations of the `pg_version()` and `pg_version_num()` functions, to simplify including pgTAP in module distributions. * Added a note to `README.pgtap` about the need to avoid `pg_typeof()` and `cmp_ok()` in tests run as part of a distribution. 0.13 2008-10-13T19:09:46Z -------------------------- * Added `pg_version()` and `pg_version_num()`. * Documented `pg_typeof()`. 0.12 2008-10-11T04:02:42Z -------------------------- * Updated `plan()` to disable warnings while it creates its tables. This means that `plan()` no longer send NOTICE messages when they run, although tests still might, depending on the setting of `client_min_messages`. * Added `hasnt_table()`, `hasnt_view()`, and `hasnt_column()`. * Added `hasnt_pk()`, `hasnt_fk()`, `col_isnt_pk()`, and `col_isnt_fk()`. * Added missing `DROP` statements to `uninstall_pgtap.sql.in`. 0.11 2008-09-24T20:41:42Z -------------------------- * Simplified the tests so that they now load `test_setup.sql` instead of setting a bunch of stuff themselves. Now only `test_setup.sql` needs to be created from `test_setup.sql.in`, and the other `.sql` files depend on it, meaning that one no longer has to specify `TAPSCHEMA` for any `make` target other than the default. * Eliminated all uses of `E''` in the tests, so that we don't have to process them for testing on 8.0. * Fixed the spelling of `ON_ROLLBACK` in the test setup. Can't believe I had it with one L in all of the test files before! Thanks to Curtis "Ovid" Poe for the spot. * Added a couple of variants of `todo()` and `skip()`, since I can never remember whether the numeric argument comes first or second. Thanks to PostgreSQL's functional polymorphism, I don't have to. Also, there are variants where the numeric value, if not passed, defaults to 1. * Updated the link to the pgTAP home page in `pgtap.sql.in`. * TODO tests can now nest. * Added `todo_start()`, `todo_end()`, and `in_todo()`. * Added variants of `throws_ok()` that test error messages as well as error codes. * Converted some more tests to use `check_test()`. * Added `can()` and `can_ok()`. * Fixed a bug in `check_test()` where the leading white space for diagnostic messages could be off by 1 or more characters. * Fixed the `installcheck` target so that it properly installs PL/pgSQL into the target database before the tests run. 0.10 2008-09-18T22:59:31Z -------------------------- * Changed `pg_prove` to set `QUIET=1` when it runs, so as to prevent the output of extraneous stuff. * Added some `GRANT` statements to `plan()` in order to make it easier to run tests using roles other than the one that called `plan()`. Patch from Rod Taylor. * Replaced a call to `lastval()` with a call to `currval()` in order to improve compatibility with PostgreSQL 8.0. Reported by David Westbrook. * Added support for TODO and SKIP tests. * Removed the few uses of named parameters and added alias names instead. This improves compatibility for versions of PostgreSQL prior to 8.0. Reported by David Westbrook. * Fixed the plural of "test" in the output from `finish()`. It was plural when there was one test and singular otherwise. So I reversed that. * Moved assignment to declared variables from the `DECLARE` block to the body of the functions. Improves compatibility with versions of PostgreSQL prior to 8.0. Reported by David Westbrook. * Eliminated passing the result of a function call to `RAISE` in order to better support older versions of PostgreSQL. Reported by David Westbrook. * Switched from using `FOUND` to `GET DIAGNOSTICS ROW_COUNT` because the former does not seem to be set for `EXECUTE` SQL in older versions of PostgreSQL. Reported by David Westbrook. * Added tests specifically targeting PostgreSQL 7.3. From David Westbrook. * Ported all the way back to PostgreSQL 8.0, thanks to some Makefile hackery and a patch file. All tests pass on 8.0, 8.1, 8.2, and 8.3. The only exception is `throws_ok()` and `lives_ok()`, which are not supported on 8.0. Versions of PostgreSQL lower than 8.0 are not yet supported, even though we have made some changes to simplify getting things to work in earlier versions. * Changed "got/expected" to "have/want", following Schwern's plans for Test::Builder 2. Also changed "caught/expected" to "caught/wanted" for nice parity when outputting diagnostics for exception testing. * Added the `has_table()`, `has_view()`, `has_column()`, `has_pk()`, `has_fk()`, `fk_ok()`, `has_unique()` and `has_check()` test functions. * Added the `col_not_null()` and `col_is_null()` test functions. * Added the `col_type_is()`, `col_default_is()`, `col_is_pk()`, `col_is_fk()`, `col_is_unique()`, and `col_has_check()` test functions. * Fixed `is()` and `isnt()` to better handle `NULL`s. * Added `cmp_ok()`. * Added the `--set ON_ERROR_STOP=1` option to the call to `psql` in `pg_prove`. * Renamed `drop_pgtap.sql.in` to `uninstall_pgtap.sql.in`, which is more in line with typical PostgreSQL contrib modules. * Removed verbose output of the `psql` command from `pg_prove`. Thanks to Andy Armstrong for the spot. * Divided the tests up into many separate test script files, so that things are a bit better organized and easier to maintain. * Added the `check_test()` function and started converting internal tests to use it instead of the hacked stuff they were doing before. * As in Test::Builder 0.81_01, changed the message for extra tests run to show the number of tests run rather than the number extra to avoid the user having to do mental math. * The regression test files are now processed by `make installcheck` and `make test` so that the schema can be properly set, if pgTAP is built with a schema. 0.02 2008-06-17T16:26:41Z -------------------------- * Converted the documentation to Markdown. * Added pg_prove, a Perl script that use TAP::Harness to run tests and report the results, just like the Perl program `prove`. * Fixed `no_plan()` so that it no longer emits a plan, which apparently was wrong. Now `finish()` outputs it when there's no plan. * Fixed the test script so that it now emits a proper plan. * Removed all of the configuration settings from `pgtap.sql`, as they're now handled by `pg_prove`. I've mentioned them in the README for reference. * Added `lives_ok()`. * Moved the creation of temporary tables into `plan()`, so that everything is properly self-contained. * Improved the handling of transactions. Test scripts are now assumed to be single transactions with a ROLLBACK at the end. This makes it so that test scripts don't have to include `drop_pgtap.sql`. * Updated `pg_prove` to rollback on an error, rather than just stop. This allows all test functions to be properly rolled back, too, in a test script that includes them but then encounters an unhandled exception. * Updated `pg_prove` to emit an appropriate error message if no test scripts are specified. * Added a Makefile. It uses the typical PostgreSQL installation procedures to install pgTAP. The SQL files have now been turned into `.in` templates that are processed by `make`. * Added support for schema qualification of test functions. Just set the `$TAPSCHEMA` environment variable when running `make`. * Added support for standard PostgreSQL-type regression testing by just copying the test script, setting some variables inside it, and providing an `expected/` directory. The test now lives in the `sql/` directory. * Changed all instances of `RETURN QUERY SELECT` to `RETURN NEXT`, which should allow pgtap to run on versions of PostgreSQL earlier than 8.3. Thanks to Neil Conway for the suggestion. 0.01 2008-06-07T05:24:27Z -------------------------- * Initial public release. Announcement at https://justatheory.com/2008/06/introducing-pgtap/ pgtap-1.3.2/META.json000066400000000000000000000032331455775703000142670ustar00rootroot00000000000000{ "name": "pgTAP", "abstract": "Unit testing for PostgreSQL", "description": "pgTAP is a suite of database functions that make it easy to write TAP-emitting unit tests in psql scripts or xUnit-style test functions.", "version": "1.3.2", "maintainer": [ "David E. Wheeler ", "pgTAP List " ], "license": { "PostgreSQL": "https://www.postgresql.org/about/licence" }, "prereqs": { "runtime": { "requires": { "plpgsql": 0, "PostgreSQL": "9.1.0" }, "recommends": { "PostgreSQL": "9.4.0" } } }, "provides": { "pgtap": { "abstract": "Unit testing for PostgreSQL", "file": "sql/pgtap.sql", "version": "1.3.2" }, "pgtap-core": { "abstract": "Unit testing for PostgreSQL", "file": "sql/pgtap-core.sql", "version": "1.3.2" }, "pgtap-schema": { "abstract": "Schema unit testing for PostgreSQL", "file": "sql/pgtap-schema.sql", "version": "1.3.2" } }, "resources": { "homepage": "https://pgtap.org/", "bugtracker": { "web": "https://github.com/theory/pgtap/issues" }, "repository": { "url": "https://github.com/theory/pgtap.git", "web": "https://github.com/theory/pgtap", "type": "git" } }, "generated_by": "David E. Wheeler", "meta-spec": { "version": "1.0.0", "url": "https://pgxn.org/meta/spec.txt" }, "tags": [ "testing", "unit testing", "tap", "tddd", "test driven database development" ] } pgtap-1.3.2/Makefile000066400000000000000000000477271455775703000143260ustar00rootroot00000000000000MAINEXT = pgtap EXTENSION = $(MAINEXT) EXTVERSION = $(shell grep default_version $(MAINEXT).control | \ sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") DISTVERSION = $(shell grep -m 1 '[[:space:]]\{3\}"version":' META.json | \ sed -e 's/[[:space:]]*"version":[[:space:]]*"\([^"]*\)",\{0,1\}/\1/') NUMVERSION = $(shell echo $(EXTVERSION) | sed -e 's/\([[:digit:]]*[.][[:digit:]]*\).*/\1/') VERSION_FILES = sql/$(MAINEXT)--$(EXTVERSION).sql sql/$(MAINEXT)-core--$(EXTVERSION).sql sql/$(MAINEXT)-schema--$(EXTVERSION).sql BASE_FILES = $(subst --$(EXTVERSION),,$(VERSION_FILES)) sql/uninstall_$(MAINEXT).sql _IN_FILES = $(wildcard sql/*--*.sql.in) _IN_PATCHED = $(_IN_FILES:.in=) EXTRA_CLEAN = $(VERSION_FILES) sql/pgtap.sql sql/uninstall_pgtap.sql sql/pgtap-core.sql sql/pgtap-schema.sql doc/*.html EXTRA_CLEAN += $(wildcard sql/*.orig) # These are files left behind by patch DOCS = doc/pgtap.mmd PG_CONFIG ?= pg_config # # Test configuration. This must be done BEFORE including PGXS # # If you need to, you can manually pass options to pg_regress with this variable REGRESS_CONF ?= # Set this to 1 to force serial test execution; otherwise it will be determined from Postgres max_connections PARALLEL_CONN ?= # This controls what version to upgrade FROM when running updatecheck. UPDATE_FROM ?= 0.95.0 # # Setup test variables # # We use the contents of test/sql to create a parallel test schedule. Note that # there is additional test setup below this; some variables must be set before # loading PGXS, some must be set afterwards. # # These are test files that need to end up in test/sql to make pg_regress # happy, but these should NOT be treated as regular regression tests SCHEDULE_TEST_FILES = $(wildcard test/schedule/*.sql) SCHEDULE_DEST_FILES = $(subst test/schedule,test/sql,$(SCHEDULE_TEST_FILES)) EXTRA_CLEAN += $(SCHEDULE_DEST_FILES) # The actual schedule files. Note that we'll build 2 additional files SCHEDULE_FILES = $(wildcard test/schedule/*.sch) # These are our actual regression tests TEST_FILES ?= $(filter-out $(SCHEDULE_DEST_FILES),$(wildcard test/sql/*.sql)) # Plain test names ALL_TESTS = $(notdir $(TEST_FILES:.sql=)) # Some tests fail when run in parallel SERIAL_TESTS ?= coltap hastap # Remove tests from SERIAL_TESTS that do not appear in ALL_TESTS SERIAL_TESTS := $(foreach test,$(SERIAL_TESTS),$(findstring $(test),$(ALL_TESTS))) # Some tests fail when run by pg_prove # TODO: The first 2 of these fail because they have tests that intentionally # fail, which makes pg_prove return a failure. Add a mode to these test files # that will disable the failure tests. PG_PROVE_EXCLUDE_TESTS = runjusttests runnotests runtests # This is a bit of a hack, but if REGRESS isn't set we can't installcheck, and # it must be set BEFORE including pgxs. Note this gets set again below REGRESS = --schedule $(TB_DIR)/run.sch # REMAINING TEST VARIABLES ARE DEFINED IN THE TEST SECTION # sort is necessary to remove dupes so install won't complain DATA = $(sort $(wildcard sql/*--*.sql) $(_IN_PATCHED)) # NOTE! This gets reset below! # Locate PGXS and pg_config ifdef NO_PGXS top_builddir = ../.. PG_CONFIG := $(top_builddir)/src/bin/pg_config/pg_config else # Run pg_config to get the PGXS Makefiles PGXS := $(shell $(PG_CONFIG) --pgxs) endif # We need to do various things with the PostgreSQL version. VERSION = $(shell $(PG_CONFIG) --version | awk '{print $$2}') $(info ) $(info GNUmake running against Postgres version $(VERSION), with pg_config located at $(shell dirname `command -v "$(PG_CONFIG)"`)) $(info ) # # Major version check # # TODO: update this # TODO9.1: update the $(TB_DIR) target below when de-supporting 9.1 ifeq ($(shell echo $(VERSION) | grep -qE "^([78][.]|9[.]0)" && echo yes || echo no),yes) $(error pgTAP requires PostgreSQL 9.1 or later. This is $(VERSION)) endif # Make sure we build these. EXTRA_CLEAN += $(_IN_PATCHED) all: $(_IN_PATCHED) sql/pgtap.sql sql/uninstall_pgtap.sql sql/pgtap-core.sql sql/pgtap-schema.sql # Add extension build targets on 9.1 and up. ifeq ($(shell echo $(VERSION) | grep -qE "^(8[.]|9[.]0)" && echo no || echo yes),yes) all: sql/$(MAINEXT)--$(EXTVERSION).sql sql/$(MAINEXT)-core--$(EXTVERSION).sql sql/$(MAINEXT)-schema--$(EXTVERSION).sql sql/$(MAINEXT)--$(EXTVERSION).sql: sql/$(MAINEXT).sql cp $< $@ sql/$(MAINEXT)-core--$(EXTVERSION).sql: sql/$(MAINEXT)-core.sql cp $< $@ sql/$(MAINEXT)-schema--$(EXTVERSION).sql: sql/$(MAINEXT)-schema.sql cp $< $@ # sort is necessary to remove dupes so install won't complain DATA = $(sort $(wildcard sql/*--*.sql) $(BASE_FILES) $(VERSION_FILES) $(_IN_PATCHED)) else # No extension support, just install the base files. DATA = $(BASE_FILES) endif # Load PGXS now that we've set all the variables it might need. ifdef NO_PGXS include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk else include $(PGXS) endif # # DISABLED TESTS # # Row security policy tests not supported by 9.4 and earlier. ifeq ($(shell echo $(VERSION) | grep -qE "^9[.][01234]|8[.]" && echo yes || echo no),yes) EXCLUDE_TEST_FILES += test/sql/policy.sql endif # Partition tests tests not supported by 9.x and earlier. ifeq ($(shell echo $(VERSION) | grep -qE "^[89][.]" && echo yes || echo no),yes) EXCLUDE_TEST_FILES += test/sql/partitions.sql endif # Stored procecures not supported prior to Postgres 11. ifeq ($(shell echo $(VERSION) | grep -qE "^([89]|10)[.]" && echo yes || echo no),yes) EXCLUDE_TEST_FILES += test/sql/proctap.sql endif # # Check for missing extensions # # NOTE! This currently MUST be after PGXS! The problem is that # $(DESTDIR)$(datadir) aren't being expanded. # EXTENSION_DIR = $(DESTDIR)$(datadir)/extension extension_control = $(shell file="$(EXTENSION_DIR)/$1.control"; [ -e "$$file" ] && echo "$$file") ifeq (,$(call extension_control,citext)) MISSING_EXTENSIONS += citext endif ifeq (,$(call extension_control,isn)) MISSING_EXTENSIONS += isn endif ifeq (,$(call extension_control,ltree)) MISSING_EXTENSIONS += ltree endif EXTENSION_TEST_FILES += test/sql/extension.sql ifneq (,$(MISSING_EXTENSIONS)) # NOTE: we emit a warning about this down below, but only when we're actually running a test. EXCLUDE_TEST_FILES += $(EXTENSION_TEST_FILES) endif # We need Perl. ifneq (,$(findstring missing,$(PERL))) PERL := $(shell command -v perl) else ifndef PERL PERL := $(shell command -v perl) endif endif # Is TAP::Parser::SourceHandler::pgTAP installed? ifdef PERL HAVE_HARNESS := $(shell $(PERL) -le 'eval { require TAP::Parser::SourceHandler::pgTAP }; print 1 unless $$@' ) endif ifndef HAVE_HARNESS $(warning To use pg_prove, TAP::Parser::SourceHandler::pgTAP Perl module) $(warning must be installed from CPAN. To do so, simply run:) $(warning cpan TAP::Parser::SourceHandler::pgTAP) endif # Use a build directory to avoid cluttering up the main repo. (Maybe should just switch to VPATH builds?) # WARNING! Not everything uses this! TODO: move all targets into $(B_DIR) B_DIR ?= .build # Determine the OS. Borrowed from Perl's Configure. OSNAME := $(shell $(SHELL) tools/getos.sh) .PHONY: test # TARGET uninstall-all: remove ALL installed versions of pgTap (rm pgtap*). # Unlike `make unintall`, this removes pgtap*, not just our defined targets. # Useful when testing multiple versions of pgtap. uninstall-all: rm -f $(EXTENSION_DIR)/pgtap* # TODO: switch this whole thing to a perl or shell script that understands the file naming convention and how to compare that to $VERSION. # VERSION = 9.1.0 # Uncomment to test all patches. sql/pgtap.sql: sql/pgtap.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][0123456]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/install-9.6.patch endif ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][01234]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/install-9.4.patch endif ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][012]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/install-9.2.patch endif ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][01]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/install-9.1.patch endif sed -e 's,MODULE_PATHNAME,$$libdir/pgtap,g' -e 's,__OS__,$(OSNAME),g' -e 's,__VERSION__,$(NUMVERSION),g' sql/pgtap.sql > sql/pgtap.tmp mv sql/pgtap.tmp sql/pgtap.sql # Ugly hacks for now... TODO: script that understands $VERSION and will apply all the patch files for that version EXTRA_CLEAN += sql/pgtap--0.99.0--1.0.0.sql sql/pgtap--0.99.0--1.0.0.sql: sql/pgtap--0.99.0--1.0.0.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][01234]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/9.4/pgtap--0.99.0--1.0.0.patch endif EXTRA_CLEAN += sql/pgtap--0.98.0--0.99.0.sql sql/pgtap--0.98.0--0.99.0.sql: sql/pgtap--0.98.0--0.99.0.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^([89]|10)[.]" && echo yes || echo no),yes) patch -p0 < compat/10/pgtap--0.98.0--0.99.0.patch endif EXTRA_CLEAN += sql/pgtap--0.97.0--0.98.0.sql sql/pgtap--0.97.0--0.98.0.sql: sql/pgtap--0.97.0--0.98.0.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^[89][.]" && echo yes || echo no),yes) patch -p0 < compat/9.6/pgtap--0.97.0--0.98.0.patch endif EXTRA_CLEAN += sql/pgtap--0.96.0--0.97.0.sql sql/pgtap--0.96.0--0.97.0.sql: sql/pgtap--0.96.0--0.97.0.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][01234]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/9.4/pgtap--0.96.0--0.97.0.patch endif EXTRA_CLEAN += sql/pgtap--0.95.0--0.96.0.sql sql/pgtap--0.95.0--0.96.0.sql: sql/pgtap--0.95.0--0.96.0.sql.in cp $< $@ ifeq ($(shell echo $(VERSION) | grep -qE "^(9[.][012]|8[.][1234])" && echo yes || echo no),yes) patch -p0 < compat/9.2/pgtap--0.95.0--0.96.0.patch endif sql/uninstall_pgtap.sql: sql/pgtap.sql test/setup.sql $(PERL) -e 'for (grep { /^CREATE /} reverse <>) { chomp; s/CREATE (OR REPLACE )?/DROP /; s/DROP (FUNCTION|VIEW|TYPE) /DROP $$1 IF EXISTS /; s/ (DEFAULT|=)[ ]+[a-zA-Z0-9]+//g; print "$$_;\n" }' $< > $@ # # Support for static install files # # The use of $@.tmp is to eliminate the possibility of leaving an invalid pgtap-static.sql in case the recipe fails part-way through. # TODO: the sed command needs the equivalent of bash's PIPEFAIL; should just replace this with some perl magic sql/pgtap-static.sql: sql/pgtap.sql.in cp $< $@.tmp @for p in `ls compat/install-*.patch | sort -rn`; do \ echo; echo '***' "Patching pgtap-static.sql with $$p"; \ sed -e 's#sql/pgtap.sql#sql/pgtap-static.sql.tmp#g' "$$p" | patch -p0; \ done sed -e 's#MODULE_PATHNAME#$$libdir/pgtap#g' -e 's#__OS__#$(OSNAME)#g' -e 's#__VERSION__#$(NUMVERSION)#g' $@.tmp > $@ EXTRA_CLEAN += sql/pgtap-static.sql sql/pgtap-static.sql.tmp sql/pgtap-core.sql: sql/pgtap-static.sql compat/gencore $(PERL) compat/gencore 0 sql/pgtap-static.sql > sql/pgtap-core.sql sql/pgtap-schema.sql: sql/pgtap-static.sql compat/gencore $(PERL) compat/gencore 1 sql/pgtap-static.sql > sql/pgtap-schema.sql $(B_DIR)/static/: $(B_DIR) mkdir -p $@ # We don't lump this in with the $(B_DIR)/static target because that would run the risk of a failure of the cp command leaving an empty directory behind $(B_DIR)/static/%/: %/ $(B_DIR)/static cp -R $< $@ # Make sure that we build the regression tests. installcheck: test/setup.sql html: multimarkdown doc/pgtap.mmd > doc/pgtap.html tools/tocgen doc/pgtap.html 2> doc/toc.html perl -MPod::Simple::XHTML -E "my \$$p = Pod::Simple::XHTML->new; \$$p->html_header_tags(''); \$$p->strip_verbatim_indent(sub { my \$$l = shift; (my \$$i = \$$l->[0]) =~ s/\\S.*//; \$$i }); \$$p->parse_from_file('`perldoc -l pg_prove`')" > doc/pg_prove.html # # Actual test targets # # TARGET regress: run installcheck then print any diffs from expected output. .PHONY: regress regress: installcheck_deps $(MAKE) installcheck || ([ -e regression.diffs ] && $${PAGER:-cat} regression.diffs; exit 1) # TARGET updatecheck: install an older version of pgTap from PGXN (controlled by $UPDATE_FROM; 0.95.0 by default), update to the current version via ALTER EXTENSION, then run installcheck. .PHONY: updatecheck updatecheck: updatecheck_deps install $(MAKE) updatecheck_run || ([ -e regression.diffs ] && $${PAGER:-cat} regression.diffs; exit 1) # General dependencies for installcheck. Note that several other places add themselves as dependencies. .PHONY: installcheck_deps installcheck_deps: $(SCHEDULE_DEST_FILES) extension_check set_parallel_conn # More dependencies below # In addition to installcheck, one can also run the tests through pg_prove. .PHONY: test-serial test-serial: extension_check @echo Running pg_prove on SERIAL tests pg_prove --pset tuples_only=1 \ $(PG_PROVE_SERIAL_FILES) .PHONY: test-parallel test-parallel: extension_check set_parallel_conn @echo Running pg_prove on PARALLEL tests pg_prove --pset tuples_only=1 \ -j $(PARALLEL_CONN) \ $(PG_PROVE_PARALLEL_FILES) .PHONY: test test: test-serial test-parallel @echo @echo WARNING: these tests are EXCLUDED from pg_prove testing: $(PG_PROVE_EXCLUDE_TESTS) # # General test support # # In order to support parallel testing, we need to have a test schedule file, # which we build dynamically. Instead of cluttering the test directory, we use # a test build directiory ($(TB_DIR)). We also use $(TB_DIR) to drop some # additional artifacts, so that we can automatically determine if certain # dependencies (such as excluded tests) have changed since the last time we # ran. TB_DIR = test/build GENERATED_SCHEDULE_DEPS = $(TB_DIR)/all_tests $(TB_DIR)/exclude_tests REGRESS = --schedule $(TB_DIR)/run.sch # Set this again just to be safe REGRESS_OPTS = --inputdir=test --max-connections=$(PARALLEL_CONN) --schedule $(SETUP_SCH) $(REGRESS_CONF) SETUP_SCH = test/schedule/main.sch # schedule to use for test setup; this can be forcibly changed by some targets! IGNORE_TESTS = $(notdir $(EXCLUDE_TEST_FILES:.sql=)) PARALLEL_TESTS = $(filter-out $(IGNORE_TESTS),$(filter-out $(SERIAL_TESTS),$(ALL_TESTS))) SERIAL_SCHEDULE_TESTS = $(filter-out $(IGNORE_TESTS),$(ALL_TESTS)) PG_PROVE_PARALLEL_TESTS = $(filter-out $(PG_PROVE_EXCLUDE_TESTS),$(PARALLEL_TESTS)) PG_PROVE_SERIAL_TESTS = $(filter-out $(PG_PROVE_EXCLUDE_TESTS),$(SERIAL_TESTS)) PG_PROVE_PARALLEL_FILES = $(call get_test_file,$(PG_PROVE_PARALLEL_TESTS)) PG_PROVE_SERIAL_FILES = $(call get_test_file,$(PG_PROVE_SERIAL_TESTS)) GENERATED_SCHEDULES = $(TB_DIR)/serial.sch $(TB_DIR)/parallel.sch # Convert test name to file name get_test_file = $(addprefix test/sql/,$(addsuffix .sql,$(1))) installcheck: $(TB_DIR)/run.sch installcheck_deps # Parallel tests will use $(PARALLEL_TESTS) number of connections if we let it, # but max_connections may not be set that high. You can set this manually to 1 # for no parallelism # # This can be a bit expensive if we're not testing, so set it up as a # dependency of installcheck .PHONY: set_parallel_conn set_parallel_conn: $(eval PARALLEL_CONN = $(shell tools/parallel_conn.sh $(PARALLEL_CONN))) @[ -n "$(PARALLEL_CONN)" ] @echo "Using $(PARALLEL_CONN) parallel test connections" # Have to do this as a separate task to ensure the @[ -n ... ] test in set_parallel_conn actually runs $(TB_DIR)/which_schedule: $(TB_DIR)/ set_parallel_conn $(eval SCHEDULE = $(shell [ $(PARALLEL_CONN) -gt 1 ] && echo $(TB_DIR)/parallel.sch || echo $(TB_DIR)/serial.sch)) @[ -n "$(SCHEDULE)" ] @[ "`cat $@ 2>/dev/null`" = "$(SCHEDULE)" ] || (echo "Schedule changed to $(SCHEDULE)"; echo "$(SCHEDULE)" > $@) # Generated schedule files, one for serial one for parallel .PHONY: $(TB_DIR)/all_tests # Need this target to force schedule rebuild if $(ALL_TESTS) changes $(TB_DIR)/all_tests: $(TB_DIR)/ @[ "`cat $@ 2>/dev/null`" = "$(ALL_TESTS)" ] || (echo "Rebuilding $@"; echo "$(ALL_TESTS)" > $@) .PHONY: $(TB_DIR)/exclude_tests # Need this target to force schedule rebuild if $(EXCLUDE_TEST) changes $(TB_DIR)/exclude_tests: $(TB_DIR)/ $(TB_DIR)/all_tests @[ "`cat $@ 2>/dev/null`" = "$(EXCLUDE_TEST)" ] || (echo "Rebuilding $@"; echo "$(EXCLUDE_TEST)" > $@) $(TB_DIR)/serial.sch: $(GENERATED_SCHEDULE_DEPS) @( \ for f in $(IGNORE_TESTS); do echo "ignore: $$f"; done; \ for f in $(SERIAL_SCHEDULE_TESTS); do echo "test: $$f"; done \ ) > $@ $(TB_DIR)/parallel.sch: $(GENERATED_SCHEDULE_DEPS) @( \ for f in $(SERIAL_TESTS); do echo "test: $$f"; done; \ ([ -z "$(IGNORE_TESTS)" ] || echo "ignore: $(IGNORE_TESTS)"); \ ([ -z "$(PARALLEL_TESTS)" ] || echo "test: $(PARALLEL_TESTS)") \ ) > $@ $(TB_DIR)/run.sch: $(TB_DIR)/which_schedule $(GENERATED_SCHEDULES) cp `cat $<` $@ # Don't generate noise if we're not running tests... .PHONY: extension_check extension_check: @tools/missing_extensions.sh "$(MISSING_EXTENSIONS)" "$(EXTENSION_TEST_FILES)" # These tests have specific dependencies test/sql/build.sql: sql/pgtap.sql test/sql/create.sql test/sql/update.sql: pgtap-version-$(EXTVERSION) test/sql/%.sql: test/schedule/%.sql @(echo '\unset ECHO'; echo '-- GENERATED FILE! DO NOT EDIT!'; echo "-- Original file: $<"; cat $< ) > $@ # Prior to 9.2, EXTRA_CLEAN just does rm -f, which obviously won't work with a directory. # TODO9.1: switch back to EXTRA_CLEAN when removing support for 9.1 #EXTRA_CLEAN += $(TB_DIR)/ clean: clean_tb_dir .PHONY: clean_tb_dir clean_tb_dir: @rm -rf $(TB_DIR) $(TB_DIR)/: @mkdir -p $@ clean: clean_b_dir .PHONY: clean_b_dir clean_b_dir: @rm -rf $(B_DIR) $(B_DIR)/: @mkdir -p $@ # # Update test support # # If the specified version of pgtap doesn't exist, install it. Note that the # real work is done by the $(EXTENSION_DIR)/pgtap--%.sql rule below. pgtap-version-%: $(EXTENSION_DIR)/pgtap--%.sql @true # Necessary to have a fake action here # CI/CD workflow might complain if we reinstall too quickly, so don't run make # install unless actually necessary. $(EXTENSION_DIR)/pgtap--$(EXTVERSION).sql: sql/pgtap--$(EXTVERSION).sql $(MAKE) install # Install an old version of pgTap via pgxn. NOTE! This rule works in # conjunction with the rule above, which handles installing our version. # # Note that we need to capture the test failure so the rule doesn't abort; # that's why the test is written with || and not &&. $(EXTENSION_DIR)/pgtap--%.sql: @ver=$(@:$(EXTENSION_DIR)/pgtap--%.sql=%); [ "$$ver" = "$(EXTVERSION)" ] || (echo Installing pgtap version $$ver from pgxn; pgxn install --pg_config=$(PG_CONFIG) pgtap=$$ver) # This is separated out so it can be called before calling updatecheck_run .PHONY: updatecheck_deps updatecheck_deps: pgtap-version-$(UPDATE_FROM) test/sql/update.sql # We do this as a separate step to change SETUP_SCH before the main updatecheck # recipe calls installcheck (which depends on SETUP_SCH being set correctly). .PHONY: updatecheck_setup # pg_regress --launcher not supported prior to 9.1 # There are some other failures in 9.1 and 9.2 (see https://travis-ci.org/decibel/pgtap/builds/358206497). # TODO: find something that can generically compare majors (ie: GE91 from # https://github.com/decibel/pgxntool/blob/0.1.10/base.mk). updatecheck_setup: updatecheck_deps @if echo $(VERSION) | grep -qE "8[.]|9[.][012]"; then echo "updatecheck is not supported prior to 9.3"; exit 1; fi $(eval SETUP_SCH = test/schedule/update.sch) $(eval REGRESS_OPTS += --launcher "tools/psql_args.sh -v 'old_ver=$(UPDATE_FROM)' -v 'new_ver=$(EXTVERSION)'") @echo @echo "###################" @echo "Testing upgrade from $(UPDATE_FROM) to $(EXTVERSION)" @echo "###################" @echo .PHONY: updatecheck_run updatecheck_run: updatecheck_setup installcheck latest-changes.md: Changes perl -e 'while (<>) {last if /^(v?\Q${DISTVERSION}\E)/; } print "Changes for v${DISTVERSION}\n"; while (<>) { last if /^\s*$$/; s/\s+$$//; if (/^\s*[*]/) { print "\n" } else { s/^\s+/ / } print } print "\n"' $< > $@ # # STOLEN FROM pgxntool # # TARGET results: runs `make test` and copies all result files to # test/expected/. Use for basic test changes with the latest version of # Postgres, but be aware that alternate `_n.out` files will not be updated. # DO NOT RUN THIS UNLESS YOU'RE CERTAIN ALL YOUR TESTS ARE PASSING! .PHONY: results results: $(MAKE) installcheck || true rsync -rlpgovP results/ test/expected # To use this, do make print-VARIABLE_NAME print-% : ; $(info $* is $(flavor $*) variable set to "$($*)") @true pgtap-1.3.2/README.md000066400000000000000000000076611455775703000141360ustar00rootroot00000000000000pgTAP 1.3.2 ============ [pgTAP](https://pgtap.org) is a unit testing framework for PostgreSQL written in PL/pgSQL and PL/SQL. It includes a comprehensive collection of [TAP](https://testanything.org)-emitting assertion functions, as well as the ability to integrate with other TAP-emitting test frameworks. It can also be used in the xUnit testing style. For detailed documentation, see the documentation in `doc/pgtap.mmd` or [online](https://pgtap.org/documentation.html "Complete pgTAP Documentation"). [![PGXN version](https://badge.fury.io/pg/pgtap.svg)](https://badge.fury.io/pg/pgtap) [![🐘 Postgres](https://github.com/theory/pgtap/actions/workflows/test.yml/badge.svg)](https://github.com/theory/pgtap/actions/workflows/test.yml) pgTAP must be installed on a host with PostgreSQL server running; it cannot be installed remotely. To build it, just do this: make make install make installcheck If you encounter an error such as: "Makefile", line 8: Need an operator You need to use GNU make, which may well be installed on your system as `gmake`: gmake gmake install gmake installcheck If you encounter an error such as: make: pg_config: Command not found Or: Makefile:52: *** pgTAP requires PostgreSQL 9.1 or later. This is . Stop. Be sure that you have `pg_config` installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the `-devel` package is also installed. If necessary tell the build process where to find it: env PG_CONFIG=/path/to/pg_config make && make install && make installcheck And finally, if all that fails, copy the entire distribution directory to the `contrib/` subdirectory of the PostgreSQL source tree and try it there without `pg_config`: env NO_PGXS=1 make && make install && make installcheck If you encounter an error such as: ERROR: must be owner of database regression You need to run the test suite using a super user, such as the default "postgres" super user: make installcheck PGUSER=postgres If you encounter an error such as: ERROR: Missing extensions required for testing: citext isn ltree Install the PostgreSQL [Additional Supplied Modules](https://www.postgresql.org/docs/current/contrib.html), which are required to run the tests. If you used a package management system such as RPM to install PostgreSQL, install the `-contrib` package. Once pgTAP is installed, you can add it to a database by connecting as a super user and running: CREATE EXTENSION pgtap; If you've upgraded your cluster to PostgreSQL 9.1 and already had pgTAP installed, you can upgrade it to a properly packaged extension with: CREATE EXTENSION pgtap FROM unpackaged; If you want to install pgTAP and all of its supporting objects into a specific schema, use the `SCHEMA` clause to specify the schema, like so: CREATE EXTENSION pgtap SCHEMA tap; Dependencies ------------ pgTAP requires PostgreSQL 9.1 or higher. Copyright and License --------------------- Copyright (c) 2008-2023 David E. Wheeler. Some rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL DAVID E. WHEELER BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DAVID E. WHEELER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. DAVID E. WHEELER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND DAVID E. WHEELER HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. pgtap-1.3.2/compat/000077500000000000000000000000001455775703000141305ustar00rootroot00000000000000pgtap-1.3.2/compat/10/000077500000000000000000000000001455775703000143505ustar00rootroot00000000000000pgtap-1.3.2/compat/10/pgtap--0.98.0--0.99.0.patch000066400000000000000000000012341455775703000201230ustar00rootroot00000000000000--- sql/pgtap--0.98.0--0.99.0.sql +++ sql/pgtap--0.98.0--0.99.0.sql @@ -134,6 +134,7 @@ ); $$ LANGUAGE sql; +DROP VIEW tap_funky; CREATE OR REPLACE VIEW tap_funky AS SELECT p.oid AS oid, n.nspname AS schema, @@ -144,7 +144,7 @@ CREATE OR REPLACE VIEW tap_funky || p.prorettype::regtype AS returns, p.prolang AS langoid, p.proisstrict AS is_strict, - p.prokind AS kind, + CASE proisagg WHEN true THEN 'a' WHEN false THEN 'f' END AS kind, p.prosecdef AS is_definer, p.proretset AS returns_set, p.provolatile::char AS volatility, pgtap-1.3.2/compat/9.2/000077500000000000000000000000001455775703000144405ustar00rootroot00000000000000pgtap-1.3.2/compat/9.2/pgtap--0.95.0--0.96.0.patch000066400000000000000000000142451455775703000202130ustar00rootroot00000000000000--- sql/pgtap--0.95.0--0.96.0.sql +++ sql/pgtap--0.95.0--0.96.0.sql @@ -233,183 +233,3 @@ CREATE OR REPLACE FUNCTION _error_diag( ), ''); $$ LANGUAGE sql IMMUTABLE; --- lives_ok( sql, description ) -CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) -RETURNS TEXT AS $$ -DECLARE - code TEXT := _query($1); - descr ALIAS FOR $2; - detail text; - hint text; - context text; - schname text; - tabname text; - colname text; - chkname text; - typname text; -BEGIN - EXECUTE code; - RETURN ok( TRUE, descr ); -EXCEPTION WHEN OTHERS THEN - -- There should have been no exception. - GET STACKED DIAGNOSTICS - detail = PG_EXCEPTION_DETAIL, - hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT, - schname = SCHEMA_NAME, - tabname = TABLE_NAME, - colname = COLUMN_NAME, - chkname = CONSTRAINT_NAME, - typname = PG_DATATYPE_NAME; - RETURN ok( FALSE, descr ) || E'\n' || diag( - ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) - ); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) -RETURNS SETOF TEXT AS $$ -DECLARE - startup ALIAS FOR $1; - shutdown ALIAS FOR $2; - setup ALIAS FOR $3; - teardown ALIAS FOR $4; - tests ALIAS FOR $5; - tap TEXT; - tfaild INTEGER := 0; - ffaild INTEGER := 0; - tnumb INTEGER := 0; - fnumb INTEGER := 0; - tok BOOLEAN := TRUE; -BEGIN - BEGIN - -- No plan support. - PERFORM * FROM no_plan(); - FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; - EXCEPTION - -- Catch all exceptions and simply rethrow custom exceptions. This - -- will roll back everything in the above block. - WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; - END; - - -- Record how startup tests have failed. - tfaild := num_failed(); - - FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP - - -- What subtest are we running? - RETURN NEXT ' ' || diag_test_name('Subtest: ' || tests[i]); - - -- Reset the results. - tok := TRUE; - tnumb := COALESCE(_get('curr_test'), 0); - - IF tnumb > 0 THEN - EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; - PERFORM _set('curr_test', 0); - PERFORM _set('failed', 0); - END IF; - - DECLARE - errstate text; - errmsg text; - detail text; - hint text; - context text; - schname text; - tabname text; - colname text; - chkname text; - typname text; - BEGIN - BEGIN - -- Run the setup functions. - FOR tap IN SELECT * FROM _runem(setup, false) LOOP - RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); - END LOOP; - - -- Run the actual test function. - FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP - RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); - END LOOP; - - -- Run the teardown functions. - FOR tap IN SELECT * FROM _runem(teardown, false) LOOP - RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); - END LOOP; - - -- Emit the plan. - fnumb := COALESCE(_get('curr_test'), 0); - RETURN NEXT ' 1..' || fnumb; - - -- Emit any error messages. - IF fnumb = 0 THEN - RETURN NEXT ' # No tests run!'; - tok = false; - ELSE - -- Report failures. - ffaild := num_failed(); - IF ffaild > 0 THEN - tok := FALSE; - RETURN NEXT ' ' || diag( - 'Looks like you failed ' || ffaild || ' test' || - CASE tfaild WHEN 1 THEN '' ELSE 's' END - || ' of ' || fnumb - ); - END IF; - END IF; - - EXCEPTION WHEN raise_exception THEN - -- Something went wrong. Record that fact. - errstate := SQLSTATE; - errmsg := SQLERRM; - GET STACKED DIAGNOSTICS - detail = PG_EXCEPTION_DETAIL, - hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT, - schname = SCHEMA_NAME, - tabname = TABLE_NAME, - colname = COLUMN_NAME, - chkname = CONSTRAINT_NAME, - typname = PG_DATATYPE_NAME; - END; - - -- Always raise an exception to rollback any changes. - RAISE EXCEPTION '__TAP_ROLLBACK__'; - - EXCEPTION WHEN raise_exception THEN - IF errmsg IS NOT NULL THEN - -- Something went wrong. Emit the error message. - tok := FALSE; - RETURN NEXT regexp_replace( diag('Test died: ' || _error_diag( - errstate, errmsg, detail, hint, context, schname, tabname, colname, chkname, typname - )), '^', ' ', 'gn'); - errmsg := NULL; - END IF; - END; - - -- Restore the sequence. - EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; - PERFORM _set('curr_test', tnumb); - PERFORM _set('failed', tfaild); - - -- Record this test. - RETURN NEXT ok(tok, tests[i]); - IF NOT tok THEN tfaild := tfaild + 1; END IF; - - END LOOP; - - -- Run the shutdown functions. - FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; - - -- Finish up. - FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP - RETURN NEXT tap; - END LOOP; - - -- Clean up and return. - PERFORM _cleanup(); - RETURN; -END; -$$ LANGUAGE plpgsql; - pgtap-1.3.2/compat/9.4/000077500000000000000000000000001455775703000144425ustar00rootroot00000000000000pgtap-1.3.2/compat/9.4/pgtap--0.96.0--0.97.0.patch000066400000000000000000000047271455775703000202230ustar00rootroot00000000000000--- sql/pgtap--0.96.0--0.97.0.sql +++ sql/pgtap--0.96.0--0.97.0.sql @@ -298,78 +298,3 @@ 'Extension ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; --- https://github.com/theory/pgtap/pull/119 - --- throws_ok ( sql, errcode, errmsg, description ) -CREATE OR REPLACE FUNCTION throws_ok ( TEXT, CHAR(5), TEXT, TEXT ) -RETURNS TEXT AS $$ -DECLARE - query TEXT := _query($1); - errcode ALIAS FOR $2; - errmsg ALIAS FOR $3; - desctext ALIAS FOR $4; - descr TEXT; -BEGIN - descr := COALESCE( - desctext, - 'threw ' || errcode || ': ' || errmsg, - 'threw ' || errcode, - 'threw ' || errmsg, - 'threw an exception' - ); - EXECUTE query; - RETURN ok( FALSE, descr ) || E'\n' || diag( - ' caught: no exception' || - E'\n wanted: ' || COALESCE( errcode, 'an exception' ) - ); -EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN - IF (errcode IS NULL OR SQLSTATE = errcode) - AND ( errmsg IS NULL OR SQLERRM = errmsg) - THEN - -- The expected errcode and/or message was thrown. - RETURN ok( TRUE, descr ); - ELSE - -- This was not the expected errcode or errmsg. - RETURN ok( FALSE, descr ) || E'\n' || diag( - ' caught: ' || SQLSTATE || ': ' || SQLERRM || - E'\n wanted: ' || COALESCE( errcode, 'an exception' ) || - COALESCE( ': ' || errmsg, '') - ); - END IF; -END; -$$ LANGUAGE plpgsql; - --- lives_ok( sql, description ) -CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) -RETURNS TEXT AS $$ -DECLARE - code TEXT := _query($1); - descr ALIAS FOR $2; - detail text; - hint text; - context text; - schname text; - tabname text; - colname text; - chkname text; - typname text; -BEGIN - EXECUTE code; - RETURN ok( TRUE, descr ); -EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN - -- There should have been no exception. - GET STACKED DIAGNOSTICS - detail = PG_EXCEPTION_DETAIL, - hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT, - schname = SCHEMA_NAME, - tabname = TABLE_NAME, - colname = COLUMN_NAME, - chkname = CONSTRAINT_NAME, - typname = PG_DATATYPE_NAME; - RETURN ok( FALSE, descr ) || E'\n' || diag( - ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) - ); -END; -$$ LANGUAGE plpgsql; - pgtap-1.3.2/compat/9.4/pgtap--0.99.0--1.0.0.patch000066400000000000000000000206301455775703000201160ustar00rootroot00000000000000--- sql/pgtap--0.99.0--1.0.0.sql +++ sql/pgtap--0.99.0--1.0.0.sql @@ -11,233 +11,6 @@ RETURNS text AS $$ ), $2); $$ LANGUAGE SQL immutable; --- policies_are( schema, table, policies[], description ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policies', - ARRAY( - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = $1 - AND c.relname = $2 - EXCEPT - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - ), - ARRAY( - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - EXCEPT - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = $1 - AND c.relname = $2 - ), - $4 - ); -$$ LANGUAGE SQL; - --- policies_are( schema, table, policies[] ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policies_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct policies' ); -$$ LANGUAGE SQL; - --- policies_are( table, policies[], description ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policies', - ARRAY( - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE c.relname = $1 - AND n.nspname NOT IN ('pg_catalog', 'information_schema') - EXCEPT - SELECT $2[i] - FROM generate_series(1, array_upper($2, 1)) s(i) - ), - ARRAY( - SELECT $2[i] - FROM generate_series(1, array_upper($2, 1)) s(i) - EXCEPT - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - AND n.nspname NOT IN ('pg_catalog', 'information_schema') - ), - $3 - ); -$$ LANGUAGE SQL; - --- policies_are( table, policies[] ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policies_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct policies' ); -$$ LANGUAGE SQL; - --- policy_roles_are( schema, table, policy, roles[], description ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policy roles', - ARRAY( - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - EXCEPT - SELECT $4[i] - FROM generate_series(1, array_upper($4, 1)) s(i) - ), - ARRAY( - SELECT $4[i] - FROM generate_series(1, array_upper($4, 1)) s(i) - EXCEPT - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - ), - $5 - ); -$$ LANGUAGE SQL; - --- policy_roles_are( schema, table, policy, roles[] ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policy_roles_are( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct roles' ); -$$ LANGUAGE SQL; - --- policy_roles_are( table, policy, roles[], description ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policy roles', - ARRAY( - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - EXCEPT - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - ), - ARRAY( - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - EXCEPT - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - ), - $4 - ); -$$ LANGUAGE SQL; - --- policy_roles_are( table, policy, roles[] ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policy_roles_are( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should have the correct roles' ); -$$ LANGUAGE SQL; - --- policy_cmd_is( schema, table, policy, command, description ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text, text ) -RETURNS TEXT AS $$ -DECLARE - cmd text; -BEGIN - SELECT - CASE pp.polcmd WHEN 'r' THEN 'SELECT' - WHEN 'a' THEN 'INSERT' - WHEN 'w' THEN 'UPDATE' - WHEN 'd' THEN 'DELETE' - ELSE 'ALL' - END - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - INTO cmd; - - RETURN is( cmd, upper($4), $5 ); -END; -$$ LANGUAGE plpgsql; - --- policy_cmd_is( schema, table, policy, command ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text ) -RETURNS TEXT AS $$ - SELECT policy_cmd_is( - $1, $2, $3, $4, - 'Policy ' || quote_ident($3) - || ' for table ' || quote_ident($1) || '.' || quote_ident($2) - || ' should apply to ' || upper($4) || ' command' - ); -$$ LANGUAGE sql; - --- policy_cmd_is( table, policy, command, description ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text, text ) -RETURNS TEXT AS $$ -DECLARE - cmd text; -BEGIN - SELECT - CASE pp.polcmd WHEN 'r' THEN 'SELECT' - WHEN 'a' THEN 'INSERT' - WHEN 'w' THEN 'UPDATE' - WHEN 'd' THEN 'DELETE' - ELSE 'ALL' - END - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - INTO cmd; - - RETURN is( cmd, upper($3), $4 ); -END; -$$ LANGUAGE plpgsql; - --- policy_cmd_is( table, policy, command ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text ) -RETURNS TEXT AS $$ - SELECT policy_cmd_is( - $1, $2, $3, - 'Policy ' || quote_ident($2) - || ' for table ' || quote_ident($1) - || ' should apply to ' || upper($3) || ' command' - ); -$$ LANGUAGE sql; - CREATE OR REPLACE FUNCTION _funkargs ( NAME[] ) RETURNS TEXT AS $$ BEGIN pgtap-1.3.2/compat/9.6/000077500000000000000000000000001455775703000144445ustar00rootroot00000000000000pgtap-1.3.2/compat/9.6/pgtap--0.97.0--0.98.0.patch000066400000000000000000000111001455775703000202060ustar00rootroot00000000000000--- sql/pgtap--0.97.0--0.98.0.sql +++ sql/pgtap--0.97.0--0.98.0.sql @@ -309,133 +309,3 @@ 'Table ' || quote_ident($1) || ' should not be partitioned' ); $$ LANGUAGE sql; - --- _partof( child_schema, child_table, parent_schema, parent_table ) -CREATE OR REPLACE FUNCTION _partof ( NAME, NAME, NAME, NAME ) -RETURNS BOOLEAN AS $$ - SELECT EXISTS( - SELECT true - FROM pg_catalog.pg_namespace cn - JOIN pg_catalog.pg_class cc ON cn.oid = cc.relnamespace - JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid - JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid - JOIN pg_catalog.pg_namespace pn ON pc.relnamespace = pn.oid - WHERE cn.nspname = $1 - AND cc.relname = $2 - AND cc.relispartition - AND pn.nspname = $3 - AND pc.relname = $4 - AND pc.relkind = 'p' - ) -$$ LANGUAGE sql; - --- _partof( child_table, parent_table ) -CREATE OR REPLACE FUNCTION _partof ( NAME, NAME ) -RETURNS BOOLEAN AS $$ - SELECT EXISTS( - SELECT true - FROM pg_catalog.pg_class cc - JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid - JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid - WHERE cc.relname = $1 - AND cc.relispartition - AND pc.relname = $2 - AND pc.relkind = 'p' - AND pg_catalog.pg_table_is_visible(cc.oid) - AND pg_catalog.pg_table_is_visible(pc.oid) - ) -$$ LANGUAGE sql; - --- is_partition_of( child_schema, child_table, parent_schema, parent_table, description ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME, TEXT ) -RETURNS TEXT AS $$ - SELECT ok( _partof($1, $2, $3, $4), $5); -$$ LANGUAGE sql; - --- is_partition_of( child_schema, child_table, parent_schema, parent_table ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME ) -RETURNS TEXT AS $$ - SELECT ok( - _partof($1, $2, $3, $4), - 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be a partition of ' - || quote_ident($3) || '.' || quote_ident($4) - ); -$$ LANGUAGE sql; - --- is_partition_of( child_table, parent_table, description ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, TEXT ) -RETURNS TEXT AS $$ - SELECT ok( _partof($1, $2), $3); -$$ LANGUAGE sql; - --- is_partition_of( child_table, parent_table ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME ) -RETURNS TEXT AS $$ - SELECT ok( - _partof($1, $2), - 'Table ' || quote_ident($1) || ' should be a partition of ' || quote_ident($2) - ); -$$ LANGUAGE sql; - --- _parts(schema, table) -CREATE OR REPLACE FUNCTION _parts( NAME, NAME ) -RETURNS SETOF NAME AS $$ - SELECT i.inhrelid::regclass::name - FROM pg_catalog.pg_namespace n - JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace - JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent - WHERE n.nspname = $1 - AND c.relname = $2 - AND c.relkind = 'p' -$$ LANGUAGE SQL; - --- _parts(table) -CREATE OR REPLACE FUNCTION _parts( NAME ) -RETURNS SETOF NAME AS $$ - SELECT i.inhrelid::regclass::name - FROM pg_catalog.pg_class c - JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent - WHERE c.relname = $1 - AND c.relkind = 'p' - AND pg_catalog.pg_table_is_visible(c.oid) -$$ LANGUAGE SQL; - --- partitions_are( schema, table, partitions, description ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'partitions', - ARRAY(SELECT _parts($1, $2) EXCEPT SELECT unnest($3)), - ARRAY(SELECT unnest($3) EXCEPT SELECT _parts($1, $2)), - $4 - ); -$$ LANGUAGE SQL; - --- partitions_are( schema, table, partitions ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT partitions_are( - $1, $2, $3, - 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct partitions' - ); -$$ LANGUAGE SQL; - --- partitions_are( table, partitions, description ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'partitions', - ARRAY(SELECT _parts($1) EXCEPT SELECT unnest($2)), - ARRAY(SELECT unnest($2) EXCEPT SELECT _parts($1)), - $3 - ); -$$ LANGUAGE SQL; - --- partitions_are( table, partitions ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT partitions_are( - $1, $2, - 'Table ' || quote_ident($1) || ' should have the correct partitions' - ); -$$ LANGUAGE SQL; pgtap-1.3.2/compat/gencore000066400000000000000000000046011455775703000154760ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; use warnings; my $invert = shift; my %keep = map { chomp; $_ => 1 } ; my ($name, $type) = $invert ? ('Schema', 'schema-testing') : ('Core', 'assertion'); print qq{ -- This file defines pgTAP $name, a portable collection of $type -- functions for TAP-based unit testing on PostgreSQL 9.1 or higher. It is -- distributed under the revised FreeBSD license. The home page for the pgTAP -- project is: -- -- https://pgtap.org/ -- }; print "-- Requires pgtap-core.sql\n--\n" if $invert; my $print = 0; while (<>) { if (/^CREATE OR REPLACE \w+ (\w+)/) { if ($1 eq 'os_name' || $1 eq 'pg_typeof') { # Never keep this one. $print = 0; } elsif ($invert ? !$keep{$1} : $keep{$1}) { $print = 1; print; } else { $print = 0; } } else { print if $print; } } __DATA__ pg_version pg_version_num pgtap_version plan no_plan _get _get_latest _get_note _set _add add_result num_failed _finish finish diag diag_test_name ok is isnt _alike matches imatches alike ialike _unalike doesnt_match doesnt_imatch unalike unialike cmp_ok pass fail todo todo_start in_todo todo_end _todo skip _query throws_ok lives_ok performs_ok performs_within _time_trial_type _time_trials _ident_array_to_string _prokind tap_funky _funkargs _got_func has_function hasnt_function _pg_sv_type_array can _has_type has_type hasnt_type has_domain hasnt_domain has_enum hasnt_enum enum_has_labels display_type _cmp_types _cast_exists has_cast hasnt_cast _expand_context _get_context cast_context_is _op_exists has_operator has_leftop has_rightop _is_trusted has_language hasnt_language language_is_trusted _opc_exists has_opclass hasnt_opclass _nosuch _func_compare _lang function_lang_is _returns function_returns _definer is_definer isnt_definer _type_func is_aggregate isnt_aggregate is_normal_function isnt_normal_function is_window isnt_window is_procedure isnt_procedure _strict is_strict isnt_strict _expand_vol _refine_vol _vol volatility_is findfuncs _runem _is_verbose do_tap _currtest _cleanup _runner runtests _temptable _temptypes _docomp _relcomp set_eq bag_eq _do_ne _relne set_ne bag_ne set_has bag_has set_hasnt bag_hasnt results_eq results_ne isa_ok is_empty collect_tap _tlike throws_like throws_ilike throws_matching throws_imatching _dexists _get_dtype domain_type_is domain_type_isnt row_eq _error_diag pgtap-1.3.2/compat/install-9.1.patch000066400000000000000000000031731455775703000171300ustar00rootroot00000000000000--- sql/pgtap.sql +++ sql/pgtap.sql @@ -781,10 +781,6 @@ RETURN ok( TRUE, descr ); EXCEPTION WHEN OTHERS THEN -- There should have been no exception. - GET STACKED DIAGNOSTICS - detail = PG_EXCEPTION_DETAIL, - hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT; RETURN ok( FALSE, descr ) || E'\n' || diag( ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) ); @@ -6688,10 +6684,6 @@ -- Something went wrong. Record that fact. errstate := SQLSTATE; errmsg := SQLERRM; - GET STACKED DIAGNOSTICS - detail = PG_EXCEPTION_DETAIL, - hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT; END; -- Always raise an exception to rollback any changes. @@ -7159,7 +7151,6 @@ RETURN ok( true, $3 ); EXCEPTION WHEN datatype_mismatch THEN - GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || @@ -7313,7 +7304,6 @@ RETURN ok( false, $3 ); EXCEPTION WHEN datatype_mismatch THEN - GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || pgtap-1.3.2/compat/install-9.2.patch000066400000000000000000000022411455775703000171240ustar00rootroot00000000000000--- sql/pgtap.sql +++ sql/pgtap.sql @@ -784,12 +784,7 @@ GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT, - schname = SCHEMA_NAME, - tabname = TABLE_NAME, - colname = COLUMN_NAME, - chkname = CONSTRAINT_NAME, - typname = PG_DATATYPE_NAME; + context = PG_EXCEPTION_CONTEXT; RETURN ok( FALSE, descr ) || E'\n' || diag( ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) ); @@ -6696,12 +6691,7 @@ GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, - context = PG_EXCEPTION_CONTEXT, - schname = SCHEMA_NAME, - tabname = TABLE_NAME, - colname = COLUMN_NAME, - chkname = CONSTRAINT_NAME, - typname = PG_DATATYPE_NAME; + context = PG_EXCEPTION_CONTEXT; END; -- Always raise an exception to rollback any changes. pgtap-1.3.2/compat/install-9.4.patch000066400000000000000000000220271455775703000171320ustar00rootroot00000000000000--- sql/pgtap.sql +++ sql/pgtap.sql @@ -675,7 +675,7 @@ ' caught: no exception' || E'\n wanted: ' || COALESCE( errcode, 'an exception' ) ); -EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN +EXCEPTION WHEN OTHERS THEN IF (errcode IS NULL OR SQLSTATE = errcode) AND ( errmsg IS NULL OR SQLERRM = errmsg) THEN @@ -779,7 +779,7 @@ BEGIN EXECUTE code; RETURN ok( TRUE, descr ); -EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN +EXCEPTION WHEN OTHERS THEN -- There should have been no exception. GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, @@ -10240,233 +10240,6 @@ ), $2); $$ LANGUAGE SQL immutable; --- policies_are( schema, table, policies[], description ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policies', - ARRAY( - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = $1 - AND c.relname = $2 - EXCEPT - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - ), - ARRAY( - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - EXCEPT - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = $1 - AND c.relname = $2 - ), - $4 - ); -$$ LANGUAGE SQL; - --- policies_are( schema, table, policies[] ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policies_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct policies' ); -$$ LANGUAGE SQL; - --- policies_are( table, policies[], description ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policies', - ARRAY( - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE c.relname = $1 - AND n.nspname NOT IN ('pg_catalog', 'information_schema') - EXCEPT - SELECT $2[i] - FROM generate_series(1, array_upper($2, 1)) s(i) - ), - ARRAY( - SELECT $2[i] - FROM generate_series(1, array_upper($2, 1)) s(i) - EXCEPT - SELECT p.polname - FROM pg_catalog.pg_policy p - JOIN pg_catalog.pg_class c ON c.oid = p.polrelid - JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - AND n.nspname NOT IN ('pg_catalog', 'information_schema') - ), - $3 - ); -$$ LANGUAGE SQL; - --- policies_are( table, policies[] ) -CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policies_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct policies' ); -$$ LANGUAGE SQL; - --- policy_roles_are( schema, table, policy, roles[], description ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policy roles', - ARRAY( - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - EXCEPT - SELECT $4[i] - FROM generate_series(1, array_upper($4, 1)) s(i) - ), - ARRAY( - SELECT $4[i] - FROM generate_series(1, array_upper($4, 1)) s(i) - EXCEPT - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - ), - $5 - ); -$$ LANGUAGE SQL; - --- policy_roles_are( schema, table, policy, roles[] ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policy_roles_are( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct roles' ); -$$ LANGUAGE SQL; - --- policy_roles_are( table, policy, roles[], description ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'policy roles', - ARRAY( - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - EXCEPT - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - ), - ARRAY( - SELECT $3[i] - FROM generate_series(1, array_upper($3, 1)) s(i) - EXCEPT - SELECT pr.rolname - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - ), - $4 - ); -$$ LANGUAGE SQL; - --- policy_roles_are( table, policy, roles[] ) -CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT policy_roles_are( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should have the correct roles' ); -$$ LANGUAGE SQL; - --- policy_cmd_is( schema, table, policy, command, description ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text, text ) -RETURNS TEXT AS $$ -DECLARE - cmd text; -BEGIN - SELECT - CASE pp.polcmd WHEN 'r' THEN 'SELECT' - WHEN 'a' THEN 'INSERT' - WHEN 'w' THEN 'UPDATE' - WHEN 'd' THEN 'DELETE' - ELSE 'ALL' - END - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pn.nspname = $1 - AND pc.relname = $2 - AND pp.polname = $3 - INTO cmd; - - RETURN is( cmd, upper($4), $5 ); -END; -$$ LANGUAGE plpgsql; - --- policy_cmd_is( schema, table, policy, command ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text ) -RETURNS TEXT AS $$ - SELECT policy_cmd_is( - $1, $2, $3, $4, - 'Policy ' || quote_ident($3) - || ' for table ' || quote_ident($1) || '.' || quote_ident($2) - || ' should apply to ' || upper($4) || ' command' - ); -$$ LANGUAGE sql; - --- policy_cmd_is( table, policy, command, description ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text, text ) -RETURNS TEXT AS $$ -DECLARE - cmd text; -BEGIN - SELECT - CASE pp.polcmd WHEN 'r' THEN 'SELECT' - WHEN 'a' THEN 'INSERT' - WHEN 'w' THEN 'UPDATE' - WHEN 'd' THEN 'DELETE' - ELSE 'ALL' - END - FROM pg_catalog.pg_policy AS pp - JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid - JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace - WHERE pc.relname = $1 - AND pp.polname = $2 - AND pn.nspname NOT IN ('pg_catalog', 'information_schema') - INTO cmd; - - RETURN is( cmd, upper($3), $4 ); -END; -$$ LANGUAGE plpgsql; - --- policy_cmd_is( table, policy, command ) -CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text ) -RETURNS TEXT AS $$ - SELECT policy_cmd_is( - $1, $2, $3, - 'Policy ' || quote_ident($2) - || ' for table ' || quote_ident($1) - || ' should apply to ' || upper($3) || ' command' - ); -$$ LANGUAGE sql; - /******************** INHERITANCE ***********************************************/ /* * Internal function to test whether the specified table in the specified schema pgtap-1.3.2/compat/install-9.6.patch000066400000000000000000000111421455775703000171300ustar00rootroot00000000000000--- sql/pgtap.sql +++ sql/pgtap.sql @@ -10222,136 +10222,6 @@ ); $$ LANGUAGE sql; --- _partof( child_schema, child_table, parent_schema, parent_table ) -CREATE OR REPLACE FUNCTION _partof ( NAME, NAME, NAME, NAME ) -RETURNS BOOLEAN AS $$ - SELECT EXISTS( - SELECT true - FROM pg_catalog.pg_namespace cn - JOIN pg_catalog.pg_class cc ON cn.oid = cc.relnamespace - JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid - JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid - JOIN pg_catalog.pg_namespace pn ON pc.relnamespace = pn.oid - WHERE cn.nspname = $1 - AND cc.relname = $2 - AND cc.relispartition - AND pn.nspname = $3 - AND pc.relname = $4 - AND pc.relkind = 'p' - ) -$$ LANGUAGE sql; - --- _partof( child_table, parent_table ) -CREATE OR REPLACE FUNCTION _partof ( NAME, NAME ) -RETURNS BOOLEAN AS $$ - SELECT EXISTS( - SELECT true - FROM pg_catalog.pg_class cc - JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid - JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid - WHERE cc.relname = $1 - AND cc.relispartition - AND pc.relname = $2 - AND pc.relkind = 'p' - AND pg_catalog.pg_table_is_visible(cc.oid) - AND pg_catalog.pg_table_is_visible(pc.oid) - ) -$$ LANGUAGE sql; - --- is_partition_of( child_schema, child_table, parent_schema, parent_table, description ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME, TEXT ) -RETURNS TEXT AS $$ - SELECT ok( _partof($1, $2, $3, $4), $5); -$$ LANGUAGE sql; - --- is_partition_of( child_schema, child_table, parent_schema, parent_table ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME ) -RETURNS TEXT AS $$ - SELECT ok( - _partof($1, $2, $3, $4), - 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be a partition of ' - || quote_ident($3) || '.' || quote_ident($4) - ); -$$ LANGUAGE sql; - --- is_partition_of( child_table, parent_table, description ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, TEXT ) -RETURNS TEXT AS $$ - SELECT ok( _partof($1, $2), $3); -$$ LANGUAGE sql; - --- is_partition_of( child_table, parent_table ) -CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME ) -RETURNS TEXT AS $$ - SELECT ok( - _partof($1, $2), - 'Table ' || quote_ident($1) || ' should be a partition of ' || quote_ident($2) - ); -$$ LANGUAGE sql; - --- _parts(schema, table) -CREATE OR REPLACE FUNCTION _parts( NAME, NAME ) -RETURNS SETOF NAME AS $$ - SELECT i.inhrelid::regclass::name - FROM pg_catalog.pg_namespace n - JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace - JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent - WHERE n.nspname = $1 - AND c.relname = $2 - AND c.relkind = 'p' -$$ LANGUAGE SQL; - --- _parts(table) -CREATE OR REPLACE FUNCTION _parts( NAME ) -RETURNS SETOF NAME AS $$ - SELECT i.inhrelid::regclass::name - FROM pg_catalog.pg_class c - JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent - WHERE c.relname = $1 - AND c.relkind = 'p' - AND pg_catalog.pg_table_is_visible(c.oid) -$$ LANGUAGE SQL; - --- partitions_are( schema, table, partitions, description ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'partitions', - ARRAY(SELECT _parts($1, $2) EXCEPT SELECT unnest($3)), - ARRAY(SELECT unnest($3) EXCEPT SELECT _parts($1, $2)), - $4 - ); -$$ LANGUAGE SQL; - --- partitions_are( schema, table, partitions ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT partitions_are( - $1, $2, $3, - 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct partitions' - ); -$$ LANGUAGE SQL; - --- partitions_are( table, partitions, description ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[], TEXT ) -RETURNS TEXT AS $$ - SELECT _are( - 'partitions', - ARRAY(SELECT _parts($1) EXCEPT SELECT unnest($2)), - ARRAY(SELECT unnest($2) EXCEPT SELECT _parts($1)), - $3 - ); -$$ LANGUAGE SQL; - --- partitions_are( table, partitions ) -CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[] ) -RETURNS TEXT AS $$ - SELECT partitions_are( - $1, $2, - 'Table ' || quote_ident($1) || ' should have the correct partitions' - ); -$$ LANGUAGE SQL; - CREATE OR REPLACE FUNCTION _ident_array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( pgtap-1.3.2/contrib/000077500000000000000000000000001455775703000143055ustar00rootroot00000000000000pgtap-1.3.2/contrib/pgtap.spec000066400000000000000000000061141455775703000162760ustar00rootroot00000000000000Summary: Unit testing suite for PostgreSQL Name: pgtap Version: 1.3.2 Release: 1%{?dist} Group: Applications/Databases License: PostgreSQL URL: https://pgtap.org/ Source0: https://api.pgxn.org/dist/pgtap/%{version}/pgtap-%{version}.zip BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root Provides: %{name} Provides: %{name}-core Provides: %{name}-schema %description pgTAP is a unit testing framework for PostgreSQL written in PL/pgSQL and PL/SQL. It includes a comprehensive collection of TAP-emitting assertion functions, as well as the ability to integrate with other TAP-emitting test frameworks. It can also be used in the xUnit testing style. %define postgresver %(pg_config --version|awk '{print $2}'| cut -d. -f1,2) Requires: postgresql-server = %{postgresver}, perl-Test-Harness >= 3.0 Requires: perl(TAP::Parser::SourceHandler::pgTAP) BuildRequires: postgresql-devel = %{postgresver} %prep %setup -q %build make %install %{__rm} -rf %{buildroot} make install USE_PGXS=1 DESTDIR=%{buildroot} %clean %{__rm} -rf %{buildroot} %files %defattr(-,root,root,-) %{_datadir}/pgsql/contrib/* %{_docdir}/pgsql/contrib/README.pgtap %changelog * Sun Feb 4 2024 David E. Wheeler 1.3.2-1 - Update to 1.3.2 * Sun Sep 24 2023 David E. Wheeler 1.3.1-1 - Update to 1.3.1 * Mon Aug 14 2023 David E. Wheeler 1.3.0-1 - Update to 1.3.0 * Sun Dec 5 2021 David E. Wheeler 1.2.0-1 - Update to 1.2.0 * Sat Oct 24 2020 Jim Nasby 1.1.0-2 - Remove last vestiges of pre-PostgreSQL 9.1 - Use https for URLs * Mon Nov 25 2019 Jim Nasby 1.1.0-1 - Update to 1.1.0 - Remove support for PostgreSQL prior to 9.1 * Thu Feb 21 2019 Jim Nasby 1.0.0-1 - Update to 1.0.0 * Sun Sep 16 2018 David E. Wheeler 0.99.0-1 - Update to v0.99.0. * Mon Nov 6 2017 David E. Wheeler 0.98.0-1 - Update to v0.98.0. - Added pgTAP harness Perl module requirement. - Added explicit list of provided features. * Mon Jan 28 2013 David Wheeler 0.93.0 - Upgraded to pgTAP 0.93.0 * Tue Jan 15 2013 David E. Wheeler 0.92.0-1 - Upgraded to pgTAP 0.92.0 * Tue Aug 23 2011 David Wheeler 0.91.0 - Removed USE_PGXS from Makefile; it has not been supported in some time. - Removed TAPSCHEMA from Makefile; use PGOPTIONS=--search_path=tap with psql instead. * Tue Feb 01 2011 David Wheeler 0.25.0 - Removed pg_prove and pg_tapgen, which are now distributed via CPAN. * Sun Mar 01 2010 Darrell Fuhriman 0.24-2 - Make install work where the pgtap.so library is needed. * Sun Dec 27 2009 David Wheeler 0.24-1 - Updated Source URL to a more predictable format. * Mon Aug 24 2009 David Fetter 0.23-1 - Got corrected .spec from Devrim GUNDUZ - Bumped version to 0.23. * Wed Aug 19 2009 Darrell Fuhriman 0.22-1 - initial RPM pgtap-1.3.2/doc/000077500000000000000000000000001455775703000134125ustar00rootroot00000000000000pgtap-1.3.2/doc/pgtap.mmd000066400000000000000000010347631455775703000152420ustar00rootroot00000000000000pgTAP 1.3.2 ============ pgTAP is a unit testing framework for PostgreSQL written in PL/pgSQL and PL/SQL. It includes a comprehensive collection of [TAP](https://testanything.org)-emitting assertion functions, as well as the ability to integrate with other TAP-emitting test frameworks. It can also be used in the xUnit testing style. Synopsis ======== CREATE EXTENSION IF NOT EXISTS pgtap; SELECT plan( 23 ); -- or SELECT * from no_plan(); -- Various ways to say "ok" SELECT ok( :have = :want, :test_description ); SELECT is( :have, :want, :test_description ); SELECT isnt( :have, :want, :test_description ); -- Rather than \echo # here's what went wrong SELECT diag( 'here''s what went wrong' ); -- Compare values with LIKE or regular expressions. SELECT alike( :have, :like_expression, :test_description ); SELECT unalike( :have, :like_expression, :test_description ); SELECT matches( :have, :regex, :test_description ); SELECT doesnt_match( :have, :regex, :test_description ); SELECT cmp_ok(:have, '=', :want, :test_description ); -- Skip tests based on runtime conditions. SELECT CASE WHEN :some_feature THEN collect_tap( ok( foo(), :test_description), is( foo(42), 23, :test_description) ) ELSE skip(:why, :how_many ) END; -- Mark some tests as to-do tests. SELECT todo(:why, :how_many); SELECT ok( foo(), :test_description); SELECT is( foo(42), 23, :test_description); -- Simple pass/fail. SELECT pass(:test_description); SELECT fail(:test_description); Installation ============ pgTAP must be installed on a host with PostgreSQL server running; it cannot be installed remotely. If you're using PostgreSQL in Docker, you need to install pgTAP inside the Docker container. If you are using Linux, you may (depending on your distribution) be able to use you distribution's package management system to install pgTAP. For instance, on Debian, Ubuntu, or Linux Mint pgTAP can be installed with the command: sudo apt-get install pgtap On other systems pgTAP has to be downloaded and built. First, download pgTAP [from PGXN](https://pgxn.org/dist/pgtap/) (click the green download button in the upper-right). Extract the downloaded zip file, and (at the command line) navigate to the extracted folder. To build pgTAP and install it into a PostgreSQL database, run the following commands: make make install make installcheck Potential Issues ---------------- If you encounter an error such as: "Makefile", line 8: Need an operator You need to use GNU make, which may well be installed on your system as `gmake`: gmake gmake install gmake installcheck If you encounter an error such as: make: pg_config: Command not found Or: Makefile:52: *** pgTAP requires PostgreSQL 9.1 or later. This is . Stop. Be sure that you have `pg_config` installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the `-devel` package is also installed. If necessary tell the build process where to find it: env PG_CONFIG=/path/to/pg_config make && make install && make installcheck And finally, if all that fails, copy the entire distribution directory to the `contrib/` subdirectory of the PostgreSQL source tree and try it there without `pg_config`: env NO_PGXS=1 make && make install && make installcheck If you encounter an error such as: ERROR: must be owner of database regression You need to run the test suite using a super user, such as the default "postgres" super user: make installcheck PGUSER=postgres If you encounter an error such as: ERROR: Missing extensions required for testing: citext isn ltree Install the PostgreSQL [Additional Supplied Modules](https://www.postgresql.org/docs/current/contrib.html), which are required to run the tests. If you used a package management system such as RPM to install PostgreSQL, install the `-contrib` package. Once pgTAP is installed, you can add it to a database by connecting as a super user and running: CREATE EXTENSION pgtap; If you've upgraded your cluster to PostgreSQL 9.1 and already had pgTAP installed, you can upgrade it to a properly packaged extension with: CREATE EXTENSION pgtap FROM unpackaged; If you want to install pgTAP and all of its supporting objects into a specific schema, use the `PGOPTIONS` environment variable to specify the schema, like so: PGOPTIONS=--search_path=tap psql -d mydb -f pgTAP.sql If you want to install pgTAP and all of its supporting objects into a specific schema, use the `SCHEMA` clause to specify the schema, like so: CREATE EXTENSION pgtap SCHEMA tap; Testing pgTAP with pgTAP ------------------------ In addition to the PostgreSQL-standard `installcheck` target, the `test` target uses the `pg_prove` Perl program to do its testing, which needs to be installed separately from [TAP::Parser::SourceHandler::pgTAP](https://metacpan.org/module/TAP::Parser::SourceHandler::pgTAP) CPAN distribution. You'll need to make sure that you use a database with PL/pgSQL loaded, or else the tests won't work. `pg_prove` supports a number of environment variables that you might need to use, including all the usual PostgreSQL client environment variables: * `$PGDATABASE` * `$PGHOST` * `$PGPORT` * `$PGUSER` You can use it to run the test suite as a database super user like so: make test PGUSER=postgres To run the tests in a local docker environment using the latest version of PostgreSQL, run: cd test docker compose build test # start the postgres server in a docker container in the background docker compose up -d test # run the regression tests docker compose exec test make install installcheck # run the tests with pg_prove # "run" builds and installs pgTAP, runs "CREATE EXTENSION" # and then runs make test docker compose exec test run # Shut down the postgres container docker compose down To test with a different version of PostgreSQL, set the environment variable `$pgtag` to one of the [PostgreSQL Docker](https://hub.docker.com/_/postgres) tags: export pgtag=12-alpine Then run the above commands. Adding pgTAP to a Database -------------------------- Once pgTAP is installed, you can add it to a database. If you're running PostgreSQL 9.1.0 or greater, it's a simple as connecting to a database as a super user and running: CREATE EXTENSION IF NOT EXISTS pgtap; If you've upgraded your cluster to PostgreSQL 9.1 and already had pgTAP installed, you can upgrade it to a properly packaged extension with: CREATE EXTENSION pgtap FROM unpackaged; If you want pgTAP to be available to all new databases, install it into the "template1" database: psql -d template1 -C "CREATE EXTENSION pgtap" To uninstall pgTAP, use `DROP EXTENSION`: DROP EXTENSION IF EXISTS pgtap; For versions of PostgreSQL less than 9.1.0, you'll need to run the installation script: psql -d mydb -f /path/to/pgsql/share/contrib/pgtap.sql If you want to install pgTAP and all of its supporting objects into a specific schema, use the `PGOPTIONS` environment variable to specify the schema, like so: PGOPTIONS=--search_path=tap psql -d mydb -f pgTAP.sql If you want to remove pgTAP from a database, run the `uninstall_pgtap.sql` script: psql -d dbname -f uninstall_pgtap.sql Both scripts will also be installed in the `contrib` directory under the directory output by `pg_config --sharedir`. So you can always do this: psql -d template1 -f `pg_config --sharedir`/contrib/pgtap.sql But do be aware that, if you've specified a schema using `$TAPSCHEMA`, that schema will always be created and the pgTAP functions placed in it. pgTAP Test Scripts ================== You can distribute `pgtap.sql` with any PostgreSQL distribution, such as a custom data type. For such a case, if your users want to run your test suite using PostgreSQL's standard `installcheck` make target, just be sure to set variables to keep the tests quiet, start a transaction, load the functions in your test script, and then rollback the transaction at the end of the script. Here's an example: \unset ECHO \set QUIET 1 -- Turn off echo and keep things quiet. -- Format the output for nice TAP. \pset format unaligned \pset tuples_only true \pset pager off -- Revert all changes on failure. \set ON_ERROR_ROLLBACK 1 \set ON_ERROR_STOP true -- Load the TAP functions. BEGIN; \i pgtap.sql -- Plan the tests. SELECT plan(1); -- Run the tests. SELECT pass( 'My test passed, w00t!' ); -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; Now you're ready to run your test script! % psql -d try -Xf test.sql 1..1 ok 1 - My test passed, w00t! You'll need to have all of those variables in the script to ensure that the output is proper TAP and that all changes are rolled back -- including the loading of the test functions -- in the event of an uncaught exception. Using `pg_prove` ---------------- Or save yourself some effort -- and run a batch of tests scripts or all of your xUnit test functions at once -- by using `pg_prove`, available in the [TAP::Parser::SourceHandler::pgTAP](https://metacpan.org/module/TAP::Parser::SourceHandler::pgTAP) CPAN distribution. If you're not relying on `installcheck`, your test scripts can be a lot less verbose; you don't need to set all the extra variables, because `pg_prove` takes care of that for you: -- Start transaction and plan the tests. BEGIN; SELECT plan(1); -- Run the tests. SELECT pass( 'My test passed, w00t!' ); -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; Now run the tests. Here's what it looks like when the pgTAP tests are run with `pg_prove`: % pg_prove -U postgres sql/*.sql sql/coltap.....ok sql/hastap.....ok sql/moretap....ok sql/pg73.......ok sql/pktap......ok All tests successful. Files=5, Tests=216, 1 wallclock secs ( 0.06 usr 0.02 sys + 0.08 cusr 0.07 csys = 0.23 CPU) Result: PASS If you're using xUnit tests and just want to have `pg_prove` run them all through the `runtests()` function, just tell it to do so: % pg_prove -d myapp --runtests Yep, that's all there is to it. Call `pg_prove --verbose` to see the individual test descriptions, `pg_prove --help` to see other supported options, and `pg_prove --man` to see its entire documentation. Using pgTAP =========== The purpose of pgTAP is to provide a wide range of testing utilities that output TAP. TAP, or the "Test Anything Protocol", is a standard for representing the output from unit tests. It owes its success to its format as a simple text-based interface that allows for practical machine parsing and high legibility for humans. TAP started life as part of the test harness for Perl but now has implementations in C/C++, Python, PHP, JavaScript, Perl, and, of course, PostgreSQL. There are two ways to use pgTAP: 1) In simple test scripts that use a plan to describe the tests in the script; or 2) In xUnit-style test functions that you install into your database and run all at once in the PostgreSQL client of your choice. I love it when a plan comes together ------------------------------------ Before anything else, you need a testing plan. This basically declares how many tests your script is going to run to protect against premature failure. The preferred way to do this is to declare a plan by calling the `plan()` function: SELECT plan(42); There are rare cases when you will not know beforehand how many tests your script is going to run. In this case, you can declare that you have no plan. (Try to avoid using this as it weakens your test.) SELECT * FROM no_plan(); Often, though, you'll be able to calculate the number of tests, like so: SELECT plan( COUNT(*) ) FROM foo; At the end of your script, you should always tell pgTAP that the tests have completed, so that it can output any diagnostics about failures or a discrepancy between the planned number of tests and the number actually run: SELECT * FROM finish(); If you need to throw an exception if some test failed, you can pass an option to `finish()`. SELECT * FROM finish(true); What a sweet unit! ------------------ If you're used to xUnit testing frameworks, you can collect all of your tests into database functions and run them all at once with `runtests()`. This is similar to how [PGUnit](http://en.dklab.ru/lib/dklab_pgunit/) works. The `runtests()` function does all the work of finding and running your test functions in individual transactions. It even supports setup and teardown functions. To use it, write your unit test functions so that they return a set of text results, and then use the pgTAP assertion functions to return TAP values. Here's an example, testing a hypothetical `users` table: CREATE OR REPLACE FUNCTION setup_insert( ) RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT is( MAX(nick), NULL, 'Should have no users') FROM users; INSERT INTO users (nick) VALUES ('theory'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION test_user( ) RETURNS SETOF TEXT AS $$ SELECT is( nick, 'theory', 'Should have nick') FROM users; $$ LANGUAGE sql; See below for details on the pgTAP assertion functions. Once you've defined your unit testing functions, you can run your tests at any time using the `runtests()` function: SELECT * FROM runtests(); Each test function will run within its own transaction, and rolled back when the function completes (or after any teardown functions have run). The TAP results will be sent to your client. Test Descriptions ----------------- By convention, each test is assigned a number in order. This is largely done automatically for you. However, it's often very useful to describe each test. Would you rather see this? ok 4 not ok 5 ok 6 Or this? ok 4 - basic multi-variable not ok 5 - simple exponential ok 6 - force == mass * acceleration The latter gives you some idea of what failed. It also makes it easier to find the test in your script, simply search for "simple exponential". All test functions take a description argument. It's optional, but highly suggested that you use it. ### xUnit Function Names ### Sometimes it's useful to extract xUnit test function names from TAP output, especially when using xUnit style with Continuous Integration Server like Hudson or TeamCity. By default pgTAP displays these names as comments, but you're able to change this behavior by overriding the function `diag_test_name`. For example: CREATE OR REPLACE FUNCTION diag_test_name(TEXT) RETURNS TEXT AS $$ SELECT diag('test: ' || $1 ); $$ LANGUAGE SQL; This will show # test: my_example_test_function_name instead of # my_example_test_function_name() This simplifies parsing test names from TAP comments. I'm ok, you're not ok --------------------- The basic purpose of pgTAP---and of any TAP-emitting test framework, for that matter---is to print out either "ok #" or "not ok #", depending on whether a given test succeeded or failed. Everything else is just gravy. All of the following functions return "ok" or "not ok" depending on whether the test succeeded or failed. ### `ok()` ### SELECT ok( :boolean, :description ); SELECT ok( :boolean ); **Parameters** `:boolean` : A boolean value indicating success or failure. `:description` : A short description of the test. This function simply evaluates any boolean expression and uses it to determine if the test succeeded or failed. A true expression passes, a false one fails. Very simple. For example: SELECT ok( 9 ^ 2 = 81, 'simple exponential' ); SELECT ok( 9 < 10, 'simple comparison' ); SELECT ok( 'foo' ~ '^f', 'simple regex' ); SELECT ok( active = true, name || widget active' ) FROM widgets; (Mnemonic: "This is ok.") The `:description` is a very short description of the test that will be printed out. It makes it very easy to find a test in your script when it fails and gives others an idea of your intentions. The description is optional, but we *very* strongly encourage its use. Should an `ok()` fail, it will produce some diagnostics: not ok 18 - sufficient mucus # Failed test 18: "sufficient mucus" Furthermore, should the boolean test result argument be passed as a `NULL` rather than `true` or `false`, `ok()` will assume a test failure and attach an additional diagnostic: not ok 18 - sufficient mucus # Failed test 18: "sufficient mucus" # (test result was NULL) ### `is()` ### ### `isnt()` ### SELECT is( :have, :want, :description ); SELECT is( :have, :want ); SELECT isnt( :have, :want, :description ); SELECT isnt( :have, :want ); **Parameters** `:have` : Value to test. `:want` : Value that `:have` is expected to be. Must be the same data type. `:description` : A short description of the test. Similar to `ok()`, `is()` and `isnt()` compare their two arguments with `IS NOT DISTINCT FROM` (`=`) AND `IS DISTINCT FROM` (`<>`) respectively and use the result of that to determine if the test succeeded or failed. So these: -- Is the ultimate answer 42? SELECT is( ultimate_answer(), 42, 'Meaning of Life' ); -- foo() doesn't return empty SELECT isnt( foo(), '', 'Got some foo' ); are similar to these: SELECT ok( ultimate_answer() = 42, 'Meaning of Life' ); SELECT ok( foo() <> '', 'Got some foo' ); (Mnemonic: "This is that." "This isn't that.") *Note:* Thanks to the use of the `IS [ NOT ] DISTINCT FROM` construct, `NULL`s are not treated as unknowns by `is()` or `isnt()`. That is, if `:have` and `:want` are both `NULL`, the test will pass, and if only one of them is `NULL`, the test will fail. So why use these test functions? They produce better diagnostics on failure. `ok()` cannot know what you are testing for (beyond the description), but `is()` and `isnt()` know what the test was and why it failed. For example this test: \set foo '\'waffle\'' \set bar '\'yarblokos\'' SELECT is( :foo::text, :bar::text, 'Is foo the same as bar?' ); Will produce something like this: # Failed test 17: "Is foo the same as bar?" # have: waffle # want: yarblokos So you can figure out what went wrong without re-running the test. You are encouraged to use `is()` and `isnt()` over `ok()` where possible. You can even use them to compare records: SELECT is( users.*, ROW(1, 'theory', true)::users ) FROM users WHERE nick = 'theory'; ### `matches()` ### SELECT matches( :have, :regex, :description ); SELECT matches( :have, :regex ); **Parameters** `:have` : Value to match. `:regex` : A regular expression. `:description` : A short description of the test. Similar to `ok()`, `matches()` matches `:have` against the regex `:regex`. So this: SELECT matches( :this, '^that', 'this is like that' ); is similar to: SELECT ok( :this ~ '^that', 'this is like that' ); (Mnemonic "This matches that".) Its advantages over `ok()` are similar to that of `is()` and `isnt()`: Better diagnostics on failure. ### `imatches()` ### SELECT imatches( :have, :regex, :description ); SELECT imatches( :have, :regex ); **Parameters** `:have` : Value to match. `:regex` : A regular expression. `:description` : A short description of the test. Just like `matches()` except that the regular expression is compared to `:have` case-insensitively. ### `doesnt_match()` ### ### `doesnt_imatch()` ### SELECT doesnt_match( :have, :regex, :description ); SELECT doesnt_match( :have, :regex ); SELECT doesnt_imatch( :have, :regex, :description ); SELECT doesnt_imatch( :have, :regex ); **Parameters** `:have` : Value to match. `:regex` : A regular expression. `:description` : A short description of the test. These functions work exactly as `matches()` and `imatches()` do, only they check if `:have` *does not* match the given pattern. ### `alike()` ### ### `ialike()` ### SELECT alike( :this, :like, :description ); SELECT alike( :this, :like ); SELECT ialike( :this, :like, :description ); SELECT ialike( :this, :like ); **Parameters** `:have` : Value to match. `:like` : A SQL `LIKE` pattern. `:description` : A short description of the test. Similar to `matches()`, `alike()` matches `:have` against the SQL `LIKE` pattern `:like`. `ialike()` matches case-insensitively. So this: SELECT ialike( :have, 'that%', 'this is alike that' ); is similar to: SELECT ok( :have ILIKE 'that%', 'this is like that' ); (Mnemonic "This is like that".) Its advantages over `ok()` are similar to that of `is()` and `isnt()`: Better diagnostics on failure. ### `unalike()` ### ### `unialike()` ### SELECT unalike( :this, :like, :description ); SELECT unalike( :this, :like ); SELECT unialike( :this, :like, :description ); SELECT unialike( :this, :like ); **Parameters** `:have` : Value to match. `:like` : A SQL `LIKE` pattern. `:description` : A short description of the test. Works exactly as `alike()`, only it checks if `:have` *does not* match the given pattern. ### `cmp_ok()` ### SELECT cmp_ok( :have, :op, :want, :description ); SELECT cmp_ok( :have, :op, :want ); **Parameters** `:have` : Value to compare. `:op` : An SQL operator specified as a string. `:want` : Value to compare to `:have` using the `:op` operator. `:description` : A short description of the test. Halfway between `ok()` and `is()` lies `cmp_ok()`. This function allows you to compare two arguments using any binary operator. -- ok( :have = :want ); SELECT cmp_ok( :have, '=', :want, 'this = that' ); -- ok( :have >= :want ); SELECT cmp_ok( :have, '>=', :want, 'this >= that' ); -- ok( :have && :want ); SELECT cmp_ok( :have, '&&', :want, 'this && that' ); Its advantage over `ok()` is that when the test fails you'll know what `:have` and `:want` were: not ok 1 # Failed test 1: # '23' # && # NULL Note that if the value returned by the operation is `NULL`, the test will be considered to have failed. This may not be what you expect if your test was, for example: SELECT cmp_ok( NULL, '=', NULL ); But in that case, you should probably use `is()`, instead. ### `pass()` ### ### `fail()` ### SELECT pass( :description ); SELECT pass( ); SELECT fail( :description ); SELECT fail( ); **Parameters** `:description` : A short description of the test. Sometimes you just want to say that the tests have passed. Usually the case is you've got some complicated condition that is difficult to wedge into an `ok()`. In this case, you can simply use `pass()` (to declare the test ok) or `fail()` (for not ok). They are synonyms for `ok(1)` and `ok(0)`. Use these functions very, very, very sparingly. ### `isa_ok()` ### SELECT isa_ok( :have, :regtype, :name ); SELECT isa_ok( :have, :regtype ); **Parameters** `:have` : Value to check the type of. `:regtype` : Name of an SQL data type. `:name` : A name for the value being compared. Checks to see if the given value is of a particular type. The description and diagnostics of this test normally just refer to "the value". If you'd like them to be more specific, you can supply a `:name`. For example you might say "the return value" when you're examining the result of a function call: SELECT isa_ok( length('foo'), 'integer', 'The return value from length()' ); In which case the description will be "The return value from length() isa integer". In the event of a failure, the diagnostic message will tell you what the type of the value actually is: not ok 12 - the value isa integer[] # the value isn't a "integer[]" it's a "boolean" Pursuing Your Query =================== Sometimes, you've just gotta test a query. I mean the results of a full blown query, not just the scalar assertion functions we've seen so far. pgTAP provides a number of functions to help you test your queries, each of which takes one or two SQL statements as arguments. For example: SELECT throws_ok('SELECT divide_by(0)'); Yes, as strings. Of course, you'll often need to do something complex in your SQL, and quoting SQL in strings in what is, after all, an SQL application, is an unnecessary PITA. Each of the query-executing functions in this section thus support an alternative to make your tests more SQLish: using prepared statements. [Prepared statements](https://www.postgresql.org/docs/current/static/sql-prepare.html) allow you to just write SQL and simply pass the prepared statement names to test functions. For example, the above example can be rewritten as: PREPARE mythrow AS SELECT divide_by(0); SELECT throws_ok('mythrow'); pgTAP assumes that an SQL argument without space characters or starting with a double quote character is a prepared statement and simply `EXECUTE`s it. If you need to pass arguments to a prepared statement, perhaps because you plan to use it in multiple tests to return different values, just `EXECUTE` it yourself. Here's an example with a prepared statement with a space in its name, and one where arguments need to be passed: PREPARE "my test" AS SELECT * FROM active_users() WHERE name LIKE 'A%'; PREPARE expect AS SELECT * FROM users WHERE active = $1 AND name LIKE $2; SELECT results_eq( '"my test"', 'EXECUTE expect( true, ''A%'' )' ); Since "my test" was declared with double quotes, it must be passed with double quotes. And since the call to "expect" included spaces (to keep it legible), the `EXECUTE` keyword was required. You can also use a `VALUES` statement, both in the query string or in a prepared statement. A useless example: PREPARE myvals AS VALUES (1, 2), (3, 4); SELECT set_eq( 'myvals', 'VALUES (1, 2), (3, 4)' ); Here's a bonus if you need to check the results from a query that returns a single column: for those functions that take two query arguments, the second can be an array. Check it out: SELECT results_eq( 'SELECT * FROM active_user_ids()', ARRAY[ 2, 3, 4, 5] ); The first query *must* return only one column of the same type as the values in the array. If you need to test more columns, you'll need to use two queries. Keeping these techniques in mind, read on for all of the query-testing goodness. To Error is Human ----------------- Sometimes you just want to know that a particular query will trigger an error. Or maybe you want to make sure a query *does not* trigger an error. For such cases, we provide a couple of test functions to make sure your queries are as error-prone as you think they should be. ### `throws_ok()` ### SELECT throws_ok( :sql, :errcode, :ermsg, :description ); SELECT throws_ok( :sql, :errcode, :ermsg ); SELECT throws_ok( :sql, :errcode ); SELECT throws_ok( :sql, :errmsg, :description ); SELECT throws_ok( :sql, :errmsg ); SELECT throws_ok( :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:errcode` : A [PostgreSQL error code](https://www.postgresql.org/docs/current/static/errcodes-appendix.html "Appendix A. PostgreSQL Error Codes") `:errmsg` : An error message. `:description` : A short description of the test. When you want to make sure that an exception is thrown by PostgreSQL, use `throws_ok()` to test for it. The first argument should be the name of a prepared statement or else a string representing the query to be executed (see the [summary](#Pursuing+Your+Query) for query argument details). `throws_ok()` will use the PL/pgSQL `EXECUTE` statement to execute the query and catch any exception. The second argument should be an exception error code, which is a five-character string (if it happens to consist only of numbers and you pass it as an integer, it will still work). If this value is not `NULL`, `throws_ok()` will check the thrown exception to ensure that it is the expected exception. For a complete list of error codes, see [Appendix A.](https://www.postgresql.org/docs/current/static/errcodes-appendix.html "Appendix A. PostgreSQL Error Codes") in the [PostgreSQL documentation](https://www.postgresql.org/docs/current/static/). The third argument is an error message. This will be most useful for functions you've written that raise exceptions, so that you can test the exception message that you've thrown. Otherwise, for core errors, you'll need to be careful of localized error messages. One trick to get around localized error messages is to pass NULL as the third argument. This allows you to still pass a description as the fourth argument. The fourth argument is of course a brief test description. Here's a useful example: PREPARE my_thrower AS INSERT INTO try (id) VALUES (1); SELECT throws_ok( 'my_thrower', '23505', 'duplicate key value violates unique constraint "try_pkey"', 'We should get a unique violation for a duplicate PK' ); For the two- and three-argument forms of `throws_ok()`, if the second argument is exactly five bytes long, it is assumed to be an error code and the optional third argument is the error message. Otherwise, the second argument is assumed to be an error message and the third argument is a description. If for some reason you need to test an error message that is five bytes long, use the four-argument form. A failing `throws_ok()` test produces an appropriate diagnostic message. For example: # Failed test 81: "This should die a glorious death" # caught: 23505: duplicate key value violates unique constraint "try_pkey" # wanted: 23502: null value in column "id" violates not-null constraint Idea borrowed from the Test::Exception Perl module. ### `throws_like()` ### ### `throws_ilike()` ### SELECT throws_like( :sql, :like, :description ); SELECT throws_like( :sql, :like ); SELECT throws_ilike( :sql, :like, :description ); SELECT throws_ilike( :sql, :like ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:like` : An SQL `LIKE` pattern. `:description` : A short description of the test. Like `throws_ok()`, but tests that an exception error message matches an SQL `LIKE` pattern. The `throws_ilike()` variant matches case-insensitively. An example: PREPARE my_thrower AS INSERT INTO try (tz) VALUES ('America/Moscow'); SELECT throws_like( 'my_thrower', '%"timezone_check"', 'We should error for invalid time zone' ); A failing `throws_like()` test produces an appropriate diagnostic message. For example: # Failed test 85: "We should error for invalid time zone" # error message: 'value for domain timezone violates check constraint "tz_check"' # doesn't match: '%"timezone_check"' ### `throws_matching()` ### ### `throws_imatching()` ### SELECT throws_matching( :sql, :regex, :description ); SELECT throws_matching( :sql, :regex ); SELECT throws_imatching( :sql, :regex, :description ); SELECT throws_imatching( :sql, :regex ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:regex` : A regular expression. `:description` : A short description of the test. Like `throws_ok()`, but tests that an exception error message matches a regular expression. The `throws_imatching()` variant matches case-insensitively. An example: PREPARE my_thrower AS INSERT INTO try (tz) VALUES ('America/Moscow'); SELECT throws_matching( 'my_thrower', '.+"timezone_check"', 'We should error for invalid time zone' ); A failing `throws_matching()` test produces an appropriate diagnostic message. For example: # Failed test 85: "We should error for invalid time zone" # error message: 'value for domain timezone violates check constraint "tz_check"' # doesn't match: '.+"timezone_check"' ### `lives_ok()` ### SELECT lives_ok( :sql, :description ); SELECT lives_ok( :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. The inverse of `throws_ok()`, `lives_ok()` ensures that an SQL statement does *not* throw an exception. Pass in the name of a prepared statement or string of SQL code (see the [summary](#Pursuing+Your+Query) for query argument details). The optional second argument is the test description. An example: SELECT lives_ok( 'INSERT INTO try (id) VALUES (1)', 'We should not get a unique violation for a new PK' ); A failing `lives_ok()` test produces an appropriate diagnostic message. For example: # Failed test 85: "don't die, little buddy!" # died: 23505: duplicate key value violates unique constraint "try_pkey" Idea borrowed from the Test::Exception Perl module. ### `performs_ok()` ### SELECT performs_ok( :sql, :milliseconds, :description ); SELECT performs_ok( :sql, :milliseconds ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:milliseconds` : Number of milliseconds. `:description` : A short description of the test. This function makes sure that an SQL statement performs well. It does so by timing its execution and failing if execution takes longer than the specified number of milliseconds. An example: PREPARE fast_query AS SELECT id FROM try WHERE name = 'Larry'; SELECT performs_ok( 'fast_query', 250, 'A select by name should be fast' ); The first argument should be the name of a prepared statement or a string representing the query to be executed (see the [summary](#Pursuing+Your+Query) for query argument details). `performs_ok()` will use the PL/pgSQL `EXECUTE` statement to execute the query. The second argument is the maximum number of milliseconds it should take for the SQL statement to execute. This argument is numeric, so you can even use fractions of milliseconds if it floats your boat. The third argument is the usual description. If not provided, `performs_ok()` will generate the description "Should run in less than $milliseconds ms". You'll likely want to provide your own description if you have more than a couple of these in a test script or function. Should a `performs_ok()` test fail it produces appropriate diagnostic messages. For example: # Failed test 19: "The lookup should be fast!" # runtime: 200.266 ms # exceeds: 200 ms *Note:* There is a little extra time included in the execution time for the the overhead of PL/pgSQL's `EXECUTE`, which must compile and execute the SQL string. You will want to account for this and pad your estimates accordingly. It's best to think of this as a brute force comparison of runtimes, in order to ensure that a query is not *really* slow (think seconds). ### `performs_within()` ### SELECT performs_within( :sql, :average_milliseconds, :within, :iterations, :description ); SELECT performs_within( :sql, :average_milliseconds, :within, :description ); SELECT performs_within( :sql, :average_milliseconds, :within, :iterations); SELECT performs_within( :sql, :average_milliseconds, :within); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:average_milliseconds` : Number of milliseconds the query should take on average. `:within` : The number of milliseconds that the average is allowed to vary. `:iterations` : The number of times to run the query. `:description` : A short description of the test. This function makes sure that an SQL statement, on average, performs within an expected window. It does so by running the query a default of 10 times. It throws out the top and bottom 10% of runs, and averages the middle 80% of the runs it made. If the average execution time is outside the range specified by `within`, the test will fails. An example: PREPARE fast_query AS SELECT id FROM try WHERE name = 'Larry'; SELECT performs_within( 'fast_query', 250, 10, 100, 'A select by name should be fast' ); The first argument should be the name of a prepared statement or a string representing the query to be executed (see the [summary](#Pursuing+Your+Query) for query argument details). `performs_within()` will use the PL/pgSQL `EXECUTE` statement to execute the query. The second argument is the average number of milliseconds it should take for the SQL statement to execute. This argument is numeric, so you can even use fractions of milliseconds if it floats your boat. The third argument is the number of milliseconds the query is allowed to vary around the average and still still pass the test. If the query's average is falls outside this window, either too fast or too slow, it will fail. The fourth argument is either the number of iterations or the usual description. If not provided, `performs_within()` will execute 10 runs of the query and will generate the description "Should run in $average_milliseconds +/- $within ms". You'll likely want to provide your own description if you have more than a couple of these in a test script or function. The fifth argument is the usual description as described above, assuming you've also specified the number of iterations. Should a `performs_within()` test fail it produces appropriate diagnostic messages. For example: # Failed test 19: "The lookup should be fast!" # average runtime: 210.266 ms # desired average: 200 +/- 10 ms *Note:* There is a little extra time included in the execution time for the the overhead of PL/pgSQL's `EXECUTE`, which must compile and execute the SQL string. You will want to account for this and pad your estimates accordingly. It's best to think of this as a brute force comparison of runtimes, in order to ensure that a query is not *really* slow (think seconds). Can You Relate? --------------- So you've got your basic scalar comparison functions, what about relations? Maybe you have some pretty hairy `SELECT` statements in views or functions to test? We've got your relation-testing functions right here. ### `results_eq()` ### SELECT results_eq( :sql, :sql, :description ); SELECT results_eq( :sql, :sql ); SELECT results_eq( :sql, :array, :description ); SELECT results_eq( :sql, :array ); SELECT results_eq( :cursor, :cursor, :description ); SELECT results_eq( :cursor, :cursor ); SELECT results_eq( :sql, :cursor, :description ); SELECT results_eq( :sql, :cursor ); SELECT results_eq( :cursor, :sql, :description ); SELECT results_eq( :cursor, :sql ); SELECT results_eq( :cursor, :array, :description ); SELECT results_eq( :cursor, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:cursor` : A PostgreSQL `refcursor` value representing a named cursor. `:description` : A short description of the test. There are three ways to test result sets in pgTAP. Perhaps the most intuitive is to do a direct row-by-row comparison of results to ensure that they are exactly what you expect, in the order you expect. Coincidentally, this is exactly how `results_eq()` behaves. Here's how you use it: simply pass in two SQL statements or prepared statement names (or some combination; (see the [summary](#Pursuing+Your+Query) for query argument details) and an optional description. Yep, that's it. It will do the rest. For example, say that you have a function, `active_users()`, that returns a set of rows from the users table. To make sure that it returns the rows you expect, you might do something like this: SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); Tip: If you want to hard-code the values to compare, use a `VALUES` statement instead of a query, like so: SELECT results_eq( 'SELECT * FROM active_users()', $$VALUES ( 42, 'Anna'), (19, 'Strongrrl'), (39, 'Theory')$$, 'active_users() should return active users' ); If the results returned by the first argument consist of a single column, the second argument may be an array: SELECT results_eq( 'SELECT * FROM active_user_ids()', ARRAY[ 2, 3, 4, 5] ); In general, the use of prepared statements is highly recommended to keep your test code SQLish (you can even use `VALUES` in prepared statements). But note that, because `results_eq()` does a row-by-row comparison, the results of the two query arguments must be in exactly the same order, with exactly the same data types, in order to pass. In practical terms, it means that you must make sure that your results are never unambiguously ordered. For example, say that you want to compare queries against a `persons` table. The simplest way to sort is by `name`, as in: try=# select * from people order by name; name | age --------+----- Damian | 19 Larry | 53 Tom | 44 Tom | 35 (4 rows) But a different run of the same query could have the rows in different order: try=# select * from people order by name; name | age --------+----- Damian | 19 Larry | 53 Tom | 35 Tom | 44 (4 rows) Notice how the two "Tom" rows are reversed. The upshot is that you must ensure that your queries are always fully ordered. In a case like the above, it means sorting on both the `name` column and the `age` column. If the sort order of your results isn't important, consider using `set_eq()` or `bag_eq()` instead. Internally, `results_eq()` turns your SQL statements into cursors so that it can iterate over them one row at a time. Conveniently, this behavior is directly available to you, too. Rather than pass in some arbitrary SQL statement or the name of a prepared statement, simply create a cursor and pass *it* in, like so: DECLARE cwant CURSOR FOR SELECT * FROM active_users(); DECLARE chave CURSOR FOR SELECT * FROM users WHERE active ORDER BY name; SELECT results_eq( 'cwant'::refcursor, 'chave'::refcursor, 'Gotta have those active users!' ); The key is to ensure that the cursor names are passed as `refcursor`s. This allows `results_eq()` to disambiguate them from prepared statements. And of course, you can mix and match cursors, prepared statements, and SQL as much as you like. Here's an example using a prepared statement and a (reset) cursor for the expected results: PREPARE users_test AS SELECT * FROM active_users(); MOVE BACKWARD ALL IN chave; SELECT results_eq( 'users_test', 'chave'::refcursor, 'Gotta have those active users!' ); Regardless of which types of arguments you pass, in the event of a test failure, `results_eq()` will offer a nice diagnostic message to tell you at what row the results differ, something like: # Failed test 146 # Results differ beginning at row 3: # have: (1,Anna) # want: (22,Betty) If there are different numbers of rows in each result set, a non-existent row will be represented as "NULL": # Failed test 147 # Results differ beginning at row 5: # have: (1,Anna) # want: NULL If the number of columns varies between result sets, or if results are of different data types, you'll get diagnostics like so: # Failed test 148 # Number of columns or their types differ between the queries: # have: (1) # want: (foo,1) ### `results_ne()` ### SELECT results_ne( :sql, :sql, :description ); SELECT results_ne( :sql, :sql ); SELECT results_ne( :sql, :array, :description ); SELECT results_ne( :sql, :array ); SELECT results_ne( :cursor, :cursor, :description ); SELECT results_ne( :cursor, :cursor ); SELECT results_ne( :sql, :cursor, :description ); SELECT results_ne( :sql, :cursor ); SELECT results_ne( :cursor, :sql, :description ); SELECT results_ne( :cursor, :sql ); SELECT results_ne( :cursor, :array, :description ); SELECT results_ne( :cursor, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:cursor` : A PostgreSQL `refcursor` value representing a named cursor. `:description` : A short description of the test. The inverse of `results_eq()`, this function tests that query results are not equivalent. Note that, like `results_ne()`, order matters, so you can actually have the same sets of results in the two query arguments and the test will pass if they're merely in a different order. More than likely what you really want is `results_eq()` or `set_ne()`. But this function is included for completeness and is kind of cute, so enjoy. If a `results_ne()` test fails, however, there will be no diagnostics, because, well, the results will be the same! ### `set_eq()` ### SELECT set_eq( :sql, :sql, :description ); SELECT set_eq( :sql, :sql ); SELECT set_eq( :sql, :array, :description ); SELECT set_eq( :sql, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:description` : A short description of the test. Sometimes you don't care what order query results are in, or if there are duplicates. In those cases, use `set_eq()` to do a simple set comparison of your result sets. As long as both queries return the same records, regardless of duplicates or ordering, a `set_eq()` test will pass. The SQL arguments can be the names of prepared statements or strings containing an SQL query (see the [summary](#Pursuing+Your+Query) for query argument details), or even one of each. If the results returned by the first argument consist of a single column, the second argument may be an array: SELECT set_eq( 'SELECT * FROM active_user_ids()', ARRAY[ 2, 3, 4, 5] ); In whatever case you choose to pass arguments, a failing test will yield useful diagnostics, such as: # Failed test 146 # Extra records: # (87,Jackson) # (1,Jacob) # Missing records: # (44,Anna) # (86,Angelina) In the event that you somehow pass queries that return rows with different types of columns, pgTAP will tell you that, too: # Failed test 147 # Columns differ between queries: # have: (integer,text) # want: (text,integer) This of course extends to sets with different numbers of columns: # Failed test 148 # Columns differ between queries: # have: (integer) # want: (text,integer) ### `set_ne()` ### SELECT set_ne( :sql, :sql, :description ); SELECT set_ne( :sql, :sql ); SELECT set_ne( :sql, :array, :description ); SELECT set_ne( :sql, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:description` : A short description of the test. The inverse of `set_eq()`, this function tests that the results of two queries are *not* the same. The two queries can as usual be the names of prepared statements or strings containing an SQL query (see the [summary](#Pursuing+Your+Query) for query argument details), or even one of each. The two queries, however, must return results that are directly comparable --- that is, with the same number and types of columns in the same orders. If it happens that the query you're testing returns a single column, the second argument may be an array. ### `set_has()` ### SELECT set_has( :sql, :sql, :description ); SELECT set_has( :sql, :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. When you need to test that a query returns at least some subset of records, `set_has()` is the hammer you're looking for. It tests that the the results of a query contain at least the results returned by another query, if not more. That is, the test passes if the second query's results are a subset of the first query's results. The second query can even return an empty set, in which case the test will pass no matter what the first query returns. Not very useful perhaps, but set-theoretically correct. As with `set_eq()`. the SQL arguments can be the names of prepared statements or strings containing an SQL query (see the [summary](#Pursuing+Your+Query) for query argument details), or one of each. If it happens that the query you're testing returns a single column, the second argument may be an array. In whatever case, a failing test will yield useful diagnostics just like: # Failed test 122 # Missing records: # (44,Anna) # (86,Angelina) As with `set_eq()`, `set_has()` will also provide useful diagnostics when the queries return incompatible columns. Internally, it uses an `EXCEPT` query to determine if there any any unexpectedly missing results. ### `set_hasnt()` ### SELECT set_hasnt( :sql, :sql, :description ); SELECT set_hasnt( :sql, :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. This test function is the inverse of `set_has()`: the test passes when the results of the first query have none of the results of the second query. Diagnostics are similarly useful: # Failed test 198 # Extra records: # (44,Anna) # (86,Angelina) Internally, the function uses an `INTERSECT` query to determine if there is any unexpected overlap between the query results. ### `bag_eq()` ### SELECT bag_eq( :sql, :sql, :description ); SELECT bag_eq( :sql, :sql ); SELECT bag_eq( :sql, :array, :description ); SELECT bag_eq( :sql, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:description` : A short description of the test. The `bag_eq()` function is just like `set_eq()`, except that it considers the results as bags rather than as sets. A bag is a set that allows duplicates. In practice, it mean that you can use `bag_eq()` to test result sets where order doesn't matter, but duplication does. In other words, if a two rows are the same in the first result set, the same row must appear twice in the second result set. Otherwise, this function behaves exactly like `set_eq()`, including the utility of its diagnostics. ### `bag_ne()` ### SELECT bag_ne( :sql, :sql, :description ); SELECT bag_ne( :sql, :sql ); SELECT bag_ne( :sql, :array, :description ); SELECT bag_ne( :sql, :array ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:array` : An array of values representing a single-column row values. `:description` : A short description of the test. The inverse of `bag_eq()`, this function tests that the results of two queries are *not* the same, including duplicates. The two queries can as usual be the names of prepared statements or strings containing an SQL query (see the [summary](#Pursuing+Your+Query) for query argument details), or even one of each. The two queries, however, must return results that are directly comparable --- that is, with the same number and types of columns in the same orders. If it happens that the query you're testing returns a single column, the second argument may be an array. ### `bag_has()` ### SELECT bag_has( :sql, :sql, :description ); SELECT bag_has( :sql, :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. The `bag_has()` function is just like `set_has()`, except that it considers the results as bags rather than as sets. A bag is a set with duplicates. What practice this means that you can use `bag_has()` to test result sets where order doesn't matter, but duplication does. Internally, it uses an `EXCEPT ALL` query to determine if there any any unexpectedly missing results. ### `bag_hasnt()` ### SELECT bag_hasnt( :sql, :sql, :description ); SELECT bag_hasnt( :sql, :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. This test function is the inverse of `bag_hasnt()`: the test passes when the results of the first query have none of the results of the second query. Diagnostics are similarly useful: # Failed test 198 # Extra records: # (44,Anna) # (86,Angelina) Internally, the function uses an `INTERSECT ALL` query to determine if there is any unexpected overlap between the query results. This means that a duplicate row in the first query will appear twice in the diagnostics if it is also duplicated in the second query. ### `is_empty()` ### SELECT is_empty( :sql, :description ); SELECT is_empty( :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. The `is_empty()` function takes a single query string or prepared statement name as its first argument, and tests that said query returns no records. Internally it simply executes the query and if there are any results, the test fails and the results are displayed in the failure diagnostics, like so: # Failed test 494: "Should have no inactive users" # Records returned: # (1,Jacob,false) # (2,Emily,false) ### `isnt_empty()` ### SELECT isnt_empty( :sql, :description ); SELECT isnt_empty( :sql ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:description` : A short description of the test. This function is the inverse of `is_empty()`. The test passes if the specified query, when executed, returns at least one row. If it returns no rows, the test fails. ### `row_eq()` ### SELECT row_eq( :sql, :record, :description ); SELECT row_eq( :sql, :record ); **Parameters** `:sql` : An SQL statement or the name of a prepared statement, passed as a string. `:record` : A row or value, also known as a [composite type](https://www.postgresql.org/docs/current/static/rowtypes.html). `:description` : A short description of the test. Compares the contents of a single row to a record. On PostgreSQL 11 and later, a bare `RECORD` value may be passed: SELECT row_eq( $$ SELECT 1, 'foo' $$, ROW(1, 'foo') ); Due to the limitations of non-C functions in earlier versions of PostgreSQL, a bare `RECORD` value cannot be passed to the function. You must instead pass in a valid composite type value, and cast the record argument (the second argument) to the same type. Both explicitly created composite types and table types are supported. Thus, you can do this: CREATE TYPE sometype AS ( id INT, name TEXT ); SELECT row_eq( $$ SELECT 1, 'foo' $$, ROW(1, 'foo')::sometype ); And, of course, this: CREATE TABLE users ( id INT, name TEXT ); INSERT INTO users VALUES (1, 'theory'); PREPARE get_user AS SELECT * FROM users LIMIT 1; SELECT row_eq( 'get_user', ROW(1, 'theory')::users ); Compatible types can be compared, though. So if the `users` table actually included an `active` column, for example, and you only wanted to test the `id` and `name`, you could do this: SELECT row_eq( $$ SELECT id, name FROM users $$, ROW(1, 'theory')::sometype ); Note the use of the `sometype` composite type for the second argument. The upshot is that you can create composite types in your tests explicitly for comparing the return values of your queries, if such queries don't return an existing valid type. Hopefully someday in the future we'll be able to support arbitrary `record` arguments. In the meantime, this is the 90% solution. Diagnostics on failure are similar to those from `is()`: # Failed test 322 # have: (1,Jacob) # want: (1,Larry) The Schema Things ================= Need to make sure that your database is designed just the way you think it should be? Use these test functions and rest easy. A note on comparisons: pgTAP uses a simple equivalence test (`=`) to compare all SQL identifiers, such as the names of tables, schemas, functions, indexes, and columns (but not data types). So in general, you should always use lowercase strings when passing identifier arguments to the functions below. Use mixed case strings only when the objects were declared in your schema using double-quotes. For example, if you created a table like so: CREATE TABLE Foo (id integer); Then you *must* test for it using only lowercase characters (if you want the test to pass): SELECT has_table('foo'); If, however, you declared the table using a double-quoted string, like so: CREATE TABLE "Foo" (id integer); Then you'd need to test for it using exactly the same string, including case, like so: SELECT has_table('Foo'); In general, this should not be an issue, as mixed-case objects are created only rarely. So if you just stick to lowercase-only arguments to these functions, you should be in good shape. I Object! --------- In a busy development environment, you might have a number of users who make changes to the database schema. Sometimes you have to really work to keep these folks in line. For example, do they add objects to the database without adding tests? Do they drop objects that they shouldn't? These assertions are designed to help you ensure that the objects in the database are exactly the objects that should be in the database, no more, no less. Each tests tests that all of the objects in the database are only the objects that *should* be there. In other words, given a list of objects, say tables in a call to `tables_are()`, this assertion will fail if there are tables that are not in the list, or if there are tables in the list that are missing from the database. It can also be useful for testing replication and the success or failure of schema change deployments. If you're more interested in the specifics of particular objects, skip to the next section. ### `tablespaces_are()` ### SELECT tablespaces_are( :tablespaces, :description ); SELECT tablespaces_are( :tablespaces ); **Parameters** `:tablespaces` : An array of tablespace names. `:description` : A short description of the test. This function tests that all of the tablespaces in the database only the tablespaces that *should* be there. Example: SELECT tablespaces_are(ARRAY[ 'dbspace', 'indexspace' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing tablespaces, like so: # Failed test 121: "There should be the correct tablespaces" # Extra tablespaces: # trigspace # Missing tablespaces: # indexspace ### `schemas_are()` ### SELECT schemas_are( :schemas, :description ); SELECT schemas_are( :schemas ); **Parameters** `:schemas` : An array of schema names. `:description` : A short description of the test. This function tests that all of the schemas in the database only the schemas that *should* be there, excluding system schemas and `information_schema`. Example: SELECT schemas_are(ARRAY[ 'public', 'contrib', 'tap' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing schemas, like so: # Failed test 106: "There should be the correct schemas" # Extra schemas: # __howdy__ # Missing schemas: # someschema ### `tables_are()` ### SELECT tables_are( :schema, :tables, :description ); SELECT tables_are( :schema, :tables ); SELECT tables_are( :tables, :description ); SELECT tables_are( :tables ); **Parameters** `:schema` : Name of a schema in which to find tables. `:tables` : An array of table names. `:description` : A short description of the test. This function tests that all of the tables in the named schema, or that are visible in the search path, are only the tables that *should* be there. If the `:schema` argument is omitted, tables will be sought in the search path, excluding `pg_catalog` and `information_schema` If the description is omitted, a generally useful default description will be generated. Example: SELECT tables_are( 'myschema', ARRAY[ 'users', 'widgets', 'gadgets', 'session' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing tables, like so: # Failed test 91: "Schema public should have the correct tables" # Extra tables: # mallots # __test_table # Missing tables: # users # widgets ### `partitions_are()` ### SELECT partitions_are( :schema, :table, :partitions :description ); SELECT partitions_are( :schema, :table, :partitions ); SELECT partitions_are( :table, :partitions :description ); SELECT partitions_are( :table, :partitions ); **Parameters** `:schema` : Name of a schema in which to find the partitioned table. `:table` : Name of a partitioned table. `:partitions` : An array of partition table names. `:description` : A short description of the test. This function tests that the named table has all of the specified partitions, and those are its only partitions. The test casts partition names to the `regclass` type; therefore, partition names should be specified relative to the search path. Those in the search path should not be schema-qualified, while those outside the search path should be schema-qualified. Partition names and schemas should be appropriately quoted as identifiers where appropriate. If the `:schema` argument is omitted, the partitioned table must be visible the search path. If the description is omitted, a generally useful default description will be generated. Example: SELECT partitions_are( 'myschema', 'mylog', ARRAY[ 'log1', 'log2', 'log3', 'log4' ] ); Example for partitions outside the search path and requiring identifier-quoting: SELECT partitions_are( 'myschema', 'MyLog', ARRAY[ 'hidden."Log 1"', 'hidden."Log 2"' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing partitions, like so: # Failed test 12: "Table myschema should have the correct partitions" # Extra partitions: # part4 # hidden."Part 5" # Missing partitions: # part5 # part6 ### `foreign_tables_are()` ### SELECT foreign_tables_are( :schema, :foreign_tables, :description ); SELECT foreign_tables_are( :schema, :foreign_tables ); SELECT foreign_tables_are( :foreign_tables, :description ); SELECT foreign_tables_are( :foreign_tables ); **Parameters** `:schema` : Name of a schema in which to find foreign tables. `:foreign_tables` : An array of foreign table names. `:description` : A short description of the test. This function tests that all of the foreign tables in the named schema, or that are visible in the search path, are only the foreign tables that *should* be there. If the `:schema` argument is omitted, foreign tables will be sought in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT foreign_tables_are( 'myschema', ARRAY[ 'users', 'widgets', 'gadgets', 'session' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing foreign tables, like so: # Failed test 91: "Schema public should have the correct foreign tables" # Extra foreign tables: # mallots # __test_table # Missing foreign tables: # users # widgets ### `views_are()` ### SELECT views_are( :schema, :views, :description ); SELECT views_are( :schema, :views ); SELECT views_are( :views, :description ); SELECT views_are( :views ); **Parameters** `:schema` : Name of a schema in which to find views. `:views` : An array of view names. `:description` : A short description of the test. This function tests that all of the views in the named schema, or that are visible in the search path, are only the views that *should* be there. If the `:schema` argument is omitted, views will be sought in the search path, excluding `pg_catalog` and `information_schema` If the description is omitted, a generally useful default description will be generated. Example: SELECT views_are( 'myschema', ARRAY[ 'users', 'widgets', 'gadgets', 'session' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing views, like so: # Failed test 92: "Schema public should have the correct views" # Extra views: # v_userlog_tmp # __test_view # Missing views: # v_userlog # eated ### `materialized_views_are()` ### SELECT materialized_views_are( :schema, :materialized_views, :description ); SELECT materialized_views_are( :schema, :materialized_views ); SELECT materialized_views_are( :materialized_views, :description ); SELECT materialized_views_are( :materialized_views ); **Parameters** `:schema` : Name of a schema in which to find materialized views. `:materialized_views` : An array of materialized view names. `:description` : A short description of the test. This function tests that all of the materialized views in the named schema, or that are visible in the search path, are only the materialized views that *should* be there. If the `:schema` argument is omitted, materialized views will be sought in the search path, excluding `pg_catalog` and `information_schema` If the description is omitted, a generally useful default description will be generated. Example: SELECT materialized_views_are( 'myschema', ARRAY[ 'users', 'widgets', 'gadgets', 'session' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing materialized views, like so: # Failed test 92: "Schema public should have the correct materialized views" # Extra materialized views: # v_userlog_tmp # __test_view # Missing materialized views: # v_userlog # eated ### `sequences_are()` ### SELECT sequences_are( :schema, :sequences, :description ); SELECT sequences_are( :schema, :sequences ); SELECT sequences_are( :sequences, :description ); SELECT sequences_are( :sequences ); **Parameters** `:schema` : Name of a schema in which to find sequences. `:sequences` : An array of sequence names. `:description` : A short description of the test. This function tests that all of the sequences in the named schema, or that are visible in the search path, are only the sequences that *should* be there. If the `:schema` argument is omitted, sequences will be sought in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT sequences_are( 'myschema', ARRAY[ 'users', 'widgets', 'gadgets', 'session' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing sequences, like so: # Failed test 93: "Schema public should have the correct sequences" # These are extra sequences: # seq_mallots # __test_table_seq # These sequences are missing: # users_seq # widgets_seq ### `columns_are()` ### SELECT columns_are( :schema, :table, :columns, :description ); SELECT columns_are( :schema, :table, :columns ); SELECT columns_are( :table, :columns, :description ); SELECT columns_are( :table, :columns ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table in which to find columns. `:columns` : An array of column names. `:description` : A short description of the test. This function tests that all of the columns on the named table are only the columns that *should* be on that table. If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT columns_are( 'myschema', 'atable', ARRAY[ 'id', 'name', 'rank', 'sn' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing columns, like so: # Failed test 183: "Table users should have the correct columns" # Extra columns: # given_name # surname # Missing columns: # name ### `indexes_are()` ### SELECT indexes_are( :schema, :table, :indexes, :description ); SELECT indexes_are( :schema, :table, :indexes ); SELECT indexes_are( :table, :indexes, :description ); SELECT indexes_are( :table, :indexes ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table in which to find indexes. `:indexes` : An array of index names. `:description` : A short description of the test. This function tests that all of the indexes on the named table are only the indexes that *should* be on that table. If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT indexes_are( 'myschema', 'atable', ARRAY[ 'atable_pkey', 'idx_atable_name' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing indexes, like so: # Failed test 180: "Table fou should have the correct indexes" # Extra indexes: # fou_pkey # Missing indexes: # idx_fou_name ### `triggers_are()` ### SELECT triggers_are( :schema, :table, :triggers, :description ); SELECT triggers_are( :schema, :table, :triggers ); SELECT triggers_are( :table, :triggers, :description ); SELECT triggers_are( :table, :triggers ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table in which to find triggers. `:triggers` : An array of trigger names. `:description` : A short description of the test. This function tests that all of the triggers on the named table are only the triggers that *should* be on that table. If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT triggers_are( 'myschema', 'atable', ARRAY[ 'atable_pkey', 'idx_atable_name' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing triggers, like so: # Failed test 180: "Table fou should have the correct triggers" # Extra triggers: # set_user_pass # Missing triggers: # set_users_pass ### `functions_are()` ### SELECT functions_are( :schema, :functions, :description ); SELECT functions_are( :schema, :functions ); SELECT functions_are( :functions, :description ); SELECT functions_are( :functions ); **Parameters** `:schema` : Name of a schema in which to find functions. `:functions` : An array of function and/or procedure names. `:description` : A short description of the test. This function tests that all of the functions or procedures in the named schema, or that are visible in the search path, are only the functions that *should* be there. If the `:schema` argument is omitted, functions will be sought in the search path, excluding `pg_catalog` and `information_schema` If the description is omitted, a generally useful default description will be generated. Example: SELECT functions_are( 'myschema', ARRAY[ 'foo', 'bar', 'frobnitz' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing functions, like so: # Failed test 150: "Schema someschema should have the correct functions" # Extra functions: # schnauzify # Missing functions: # frobnitz ### `roles_are()` ### SELECT roles_are( :roles, :description ); SELECT roles_are( :roles ); **Parameters** `:roles` : An array of role names. `:description` : A short description of the test. This function tests that all of the roles in the database only the roles that *should* be there. Example: SELECT roles_are(ARRAY[ 'postgres', 'someone', 'root' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing roles, like so: # Failed test 195: "There should be the correct roles" # Extra roles: # root # Missing roles: # bobby ### `users_are()` ### SELECT users_are( :users, :description ); SELECT users_are( :users ); **Parameters** `:users` : An array of user names. `:description` : A short description of the test. This function tests that all of the users in the database only the users that *should* be there. Example: SELECT users_are(ARRAY[ 'postgres', 'someone', 'root' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing users, like so: # Failed test 195: "There should be the correct users" # Extra users: # root # Missing users: # bobby ### `groups_are()` ### SELECT groups_are( :groups, :description ); SELECT groups_are( :groups ); **Parameters** `:groups` : An array of group names. `:description` : A short description of the test. This function tests that all of the groups in the database only the groups that *should* be there. Example: SELECT groups_are(ARRAY[ 'postgres', 'admins, 'l0s3rs' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing groups, like so: # Failed test 210: "There should be the correct groups" # Extra groups: # meanies # Missing groups: # __howdy__ ### `languages_are()` ### SELECT languages_are( :languages, :description ); SELECT languages_are( :languages ); **Parameters** `:languages` : An array of language names. `:description` : A short description of the test. This function tests that all of the languages in the database only the languages that *should* be there. Example: SELECT languages_are(ARRAY[ 'plpgsql', 'plperl', 'pllolcode' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing languages, like so: # Failed test 225: "There should be the correct procedural languages" # Extra languages: # pllolcode # Missing languages: # plpgsql ### `opclasses_are()` ### SELECT opclasses_are( :schema, :opclasses, :description ); SELECT opclasses_are( :schema, :opclasses ); SELECT opclasses_are( :opclasses, :description ); SELECT opclasses_are( :opclasses ); **Parameters** `:schema` : Name of a schema in which to find opclasses. `:opclasses` : An array of opclass names. `:description` : A short description of the test. This function tests that all of the operator classes in the named schema, or that are visible in the search path, are only the opclasses that *should* be there. If the `:schema` argument is omitted, opclasses will be sought in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT opclasses_are( 'myschema', ARRAY[ 'foo', 'bar', 'frobnitz' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing opclasses, like so: # Failed test 251: "Schema public should have the correct operator classes" # Extra operator classes: # goofy_ops # Missing operator classes: # custom_ops ### `rules_are()` ### SELECT rules_are( :schema, :table, :rules, :description ); SELECT rules_are( :schema, :table, :rules ); SELECT rules_are( :table, :rules, :description ); SELECT rules_are( :table, :rules ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table in which to find rules. `:rules` : An array of rule names. `:description` : A short description of the test. This function tests that all of the rules on the named relation are only the rules that *should* be on that relation (a table, view or a materialized view). If the `:schema` argument is omitted, the rules must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT rules_are( 'myschema', 'atable', ARRAY[ 'on_insert', 'on_update', 'on_delete' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing rules, like so: # Failed test 281: "Relation public.users should have the correct rules" # Extra rules: # on_select # Missing rules: # on_delete ### `types_are()` ### SELECT types_are( :schema, :types, :description ); SELECT types_are( :schema, :types ); SELECT types_are( :types, :description ); SELECT types_are( :types ); **Parameters** `:schema` : Name of a schema in which to find types. `:types` : An array of data type names. `:description` : A short description of the test. Tests that all of the types in the named schema are the only types in that schema, including base types, composite types, domains, enums, and pseudo-types. If the `:schema` argument is omitted, the types must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT types_are('myschema', ARRAY[ 'timezone', 'state' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing types, like so: # Failed test 307: "Schema someschema should have the correct types" # Extra types: # sometype # Missing types: # timezone ### `domains_are()` ### SELECT domains_are( :schema, :domains, :description ); SELECT domains_are( :schema, :domains ); SELECT domains_are( :domains, :description ); SELECT domains_are( :domains ); **Parameters** `:schema` : Name of a schema in which to find domains. `:domains` : An array of data domain names. `:description` : A short description of the test. Tests that all of the domains in the named schema are the only domains in that schema. If the `:schema` argument is omitted, the domains must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT domains_are('myschema', ARRAY[ 'timezone', 'state' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing domains, like so: # Failed test 327: "Schema someschema should have the correct domains" # Extra domains: # somedomain # Missing domains: # timezone ### `enums_are()` ### SELECT enums_are( :schema, :enums, :description ); SELECT enums_are( :schema, :enums ); SELECT enums_are( :enums, :description ); SELECT enums_are( :enums ); **Parameters** `:schema` : Name of a schema in which to find enums. `:enums` : An array of enum data type names. `:description` : A short description of the test. Tests that all of the enums in the named schema are the only enums in that schema. If the `:schema` argument is omitted, the enums must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT enums_are('myschema', ARRAY[ 'timezone', 'state' ]); In the event of a failure, you'll see diagnostics listing the extra and/or missing enums, like so: # Failed test 333: "Schema someschema should have the correct enums" # Extra enums: # someenum # Missing enums: # bug_status ### `casts_are()` ### SELECT casts_are( :casts, :description ); SELECT casts_are( :casts ); **Parameters** `:casts` : An array of cast names. `:description` : A short description of the test. This function tests that all of the casts in the database are only the casts that *should* be in that database. Casts are specified as strings in a syntax similarly to how they're declared via `CREATE CAST`. The pattern is `:source_type AS :target_type`. If either type was created with double-quotes to force mixed case or special characters, then you must use double quotes in the cast strings. Example: SELECT casts_are(ARRAY[ 'integer AS "myInteger"', 'integer AS double precision', 'integer AS reltime', 'integer AS numeric', ]); If the description is omitted, a generally useful default description will be generated. In the event of a failure, you'll see diagnostics listing the extra and/or missing casts, like so: # Failed test 302: "There should be the correct casts" # Extra casts: # lseg AS point # Missing casts: # lseg AS integer ### `operators_are()` ### SELECT operators_are( :schema, :operators, :description ); SELECT operators_are( :schema, :operators ); SELECT operators_are( :operators, :description ); SELECT operators_are( :operators ); **Parameters** `:schema` : Name of a schema in which to find operators. `:operators` : An array of operators. `:description` : A short description of the test. Tests that all of the operators in the named schema are the only operators in that schema. If the `:schema` argument is omitted, the operators must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. The `:operators` argument is specified as an array of strings in which each operator is defined similarly to the display of the `:regoperator` type. The format is `:op(:leftop,:rightop) RETURNS :return_type`. For left operators the left argument type should be `NONE`. For right operators, the right argument type should be `NONE`. The example above shows one one of each of the operator types. `=(citext,citext)` is an infix operator, `-(bigint,NONE)` is a left operator, and `!(NONE,bigint)` is a right operator. Example: SELECT operators_are( 'public', ARRAY[ '=(citext,citext) RETURNS boolean', '-(NONE,bigint) RETURNS bigint', '!(bigint,NONE) RETURNS numeric' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing operators, like so: # Failed test 453: "Schema public should have the correct operators" # Extra operators: # +(integer,integer) RETURNS integer # Missing enums: # +(integer,text) RETURNS text ### `extensions_are()` ### SELECT extensions_are( :schema, :extensions, :description ); SELECT extensions_are( :schema, :extensions ); SELECT extensions_are( :extensions, :description ); SELECT extensions_are( :extensions ); **Parameters** `:schema` : Name of a schema associated with the extensions. `:extensions` : An array of extension names. `:description` : A short description of the test. This function tests all of the extensions that should be present. If `:schema` is specified, it will test only for extensions associated the named schema (via the `schema` parameter in the extension's control file, ov the `WITH SCHEMA` clause of the [CREATE EXTENSION](https://www.postgresql.org/docs/current/static/extend-extensions.html) statement). Otherwise it will check for all extension in the database, including pgTAP itself. If the description is omitted, a generally useful default description will be generated. Example: SELECT extensions_are( 'myschema', ARRAY[ 'citext', 'isn', 'plpgsql' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing extensions, like so: # Failed test 91: "Schema public should have the correct extensions" # Extra extensions: # pgtap # ltree # Missing extensions: # citext # isn To Have or Have Not ------------------- Perhaps you're not so concerned with ensuring the [precise correlation of database objects](#I+Object! "I Object!"). Perhaps you just need to make sure that certain objects exist (or that certain objects *don't* exist). You've come to the right place. ### `has_tablespace()` ### SELECT has_tablespace( :tablespace, :location, :description ); SELECT has_tablespace( :tablespace, :description ); SELECT has_tablespace( :tablespace ); **Parameters** `:tablespace` : Name of a tablespace. `:location` : The tablespace's Location on disk. `:description` : A short description of the test. This function tests whether or not a tablespace exists in the database. The first argument is a tablespace name. The second is either the a file system path for the database or a test description. If you specify a location path, you must pass a description as the third argument; otherwise, if you omit the test description, it will be set to "Tablespace `:tablespace` should exist". Example: SELECT has_tablespace('sometablespace', '/data/dbs'); ### `hasnt_tablespace()` ### SELECT hasnt_tablespace( :tablespace, :description ); SELECT hasnt_tablespace( :tablespace ); **Parameters** `:tablespace` : Name of a tablespace. `:description` : A short description of the test. This function is the inverse of `has_tablespace()`. The test passes if the specified tablespace does *not* exist. ### `has_schema()` ### SELECT has_schema( :schema, :description ); SELECT has_schema( :schema ); **Parameters** `:schema` : Name of a schema. `:description` : A short description of the test. This function tests whether or not a schema exists in the database. The first argument is a schema name and the second is the test description. If you omit the test description, it will be set to "Schema `:schema` should exist". ### `hasnt_schema()` ### SELECT hasnt_schema( 'someschema', 'There should be no schema someschema' ); **Parameters** `:schema` : Name of a schema. `:description` : A short description of the test. This function is the inverse of `has_schema()`. The test passes if the specified schema does *not* exist. ### `has_relation()` ### SELECT has_relation( :schema, :relation, :description ); SELECT has_relation( :relation, :description ); SELECT has_relation( :relation ); **Parameters** `:schema` : Name of a schema in which to find the relation. `:relation` : Name of a relation. `:description` : A short description of the test. This function tests whether or not a relation exists in the database. Relations are tables, views, materialized views, sequences, composite types, foreign tables, and toast tables. The first argument is a schema name, the second is a relation name, and the third is the test description. If you omit the schema, the relation must be visible in the search path. Example: SELECT has_relation('myschema', 'somerelation'); If you omit the test description, it will be set to "Relation `:relation` should exist". ### `hasnt_relation()` ### SELECT hasnt_relation( :schema, :relation, :description ); SELECT hasnt_relation( :relation, :description ); SELECT hasnt_relation( :relation ); **Parameters** `:schema` : Name of a schema in which to find the relation. `:relation` : Name of a relation. `:description` : A short description of the test. This function is the inverse of `has_relation()`. The test passes if the specified relation does *not* exist. ### `has_table()` ### SELECT has_table( :schema, :table, :description ); SELECT has_table( :schema, :table ); SELECT has_table( :table, :description ); SELECT has_table( :table ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. This function tests whether or not a table exists in the database. The first argument is a schema name, the second is a table name, and the third is the test description. If you omit the schema, the table must be visible in the search path. Example: SELECT has_table('myschema'::name, 'sometable'::name); If you omit the test description, it will be set to "Table `:table` should exist". Note that this function will not recognize foreign tables; use `has_foreign_table()` to test for the presence of foreign tables. ### `hasnt_table()` ### SELECT hasnt_table( :schema, :table, :description ); SELECT hasnt_table( :schema, :table ); SELECT hasnt_table( :table, :description ); SELECT hasnt_table( :table ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. This function is the inverse of `has_table()`. The test passes if the specified table does *not* exist. ### `has_view()` ### SELECT has_view( :schema, :view, :description ); SELECT has_view( :schema, :view ); SELECT has_view( :view, :description ); SELECT has_view( :view ); **Parameters** `:schema` : Name of a schema in which to find the view. `:view` : Name of a view. `:description` : A short description of the test. This function tests whether or not a view exists in the database. The first argument is a schema name, the second is a view name, and the third is the test description. If you omit the schema, the view must be visible in the search path. Example: SELECT has_view('myschema', 'someview'); If you omit the test description, it will be set to "View `:view` should exist". ### `hasnt_view()` ### SELECT hasnt_view( :schema, :view, :description ); SELECT hasnt_view( :schema, :view ); SELECT hasnt_view( :view, :description ); SELECT hasnt_view( :view ); **Parameters** `:schema` : Name of a schema in which to find the view. `:view` : Name of a view. `:description` : A short description of the test. This function is the inverse of `has_view()`. The test passes if the specified view does *not* exist. ### `has_materialized_view()` ### SELECT has_materialized_view( :schema, :materialized_view, :description ); SELECT has_materialized_view( :materialized_view, :description ); SELECT has_materialized_view( :materialized_view ); **Parameters** `:schema` : Name of a schema in which to find the materialized view. `:materialized_view` : Name of a materialized view. `:description` : A short description of the test. This function tests whether or not a materialized view exists in the database. The first argument is a schema name, the second is a materialized view name, and the third is the test description. If you omit the schema, the materialized view must be visible in the search path. Example: SELECT has_materialized_view('myschema', 'some_materialized_view'); If you omit the test description, it will be set to "Materialized view `:materialized_view` should exist". ### `hasnt_materialized_view()` ### SELECT hasnt_materialized_view( :schema, :materialized_view, :description ); SELECT hasnt_materialized_view( :materialized_view, :description ); SELECT hasnt_materialized_view( :materialized_view ); **Parameters** `:schema` : Name of a schema in which to find the materialized view. `:materialized_view` : Name of a materialized view. `:description` : A short description of the test. This function is the inverse of `has_view()`. The test passes if the specified materialized view does *not* exist. ### `has_inherited_tables()` SELECT has_inherited_tables( :schema, :table, :description ); SELECT has_inherited_tables( :schema, :table ); SELECT has_inherited_tables( :table, :description ); SELECT has_inherited_tables( :table ); **Parameters** `:schema` : Name of a schema in which to search for the table that has children. `:table` : Name of the table that must have children. `:description` : A description of the test. This function checks that the specified table has other tables that inherit from it. If you find that the function call confuses the table name for a description, cast the table to the `NAME` type: SELECT has_inherited_tables('myschema', 'sometable'::NAME); ### `hasnt_inherited_tables()` SELECT hasnt_inherited_tables( :schema, :table, :description ); SELECT hasnt_inherited_tables( :schema, :table ); SELECT hasnt_inherited_tables( :table, :description ); SELECT hasnt_inherited_tables( :table ); **Parameters** `:schema` : Name of a schema in which to search for the table that must not have children. `:table` : Name of the table that must not have children. `:description` : A description of the test. This function checks that the specified table has no tables inheriting from it. It is the opposite of the function `has_inherited_tables()`. If you find that the function call confuses the table name for a description, cast the table to the `NAME` type: SELECT hasnt_inherited_tables('myschema', 'sometable'::NAME); ### `is_ancestor_of()` SELECT is_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :depth, :description ); SELECT is_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :depth ); SELECT is_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :description ); SELECT is_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table ); SELECT is_ancestor_of( :ancestor_table, :descendent_table, :depth, :description ); SELECT is_ancestor_of( :ancestor_table, :descendent_table, :depth ); SELECT is_ancestor_of( :ancestor_table, :descendent_table, :description ); SELECT is_ancestor_of( :ancestor_table, :descendent_table ); **Parameters** `:ancestor_schema` : Name of the schema in which the ancestor table must be found. `:ancestor_table` : Name of the ancestor table. `:descendent_schema` : Name of the schema in which the descendent table must be found. `:descendent_table` : Name of the descendent table. `:depth` : The inheritance distance between the two tables. `:description` : Description of the test. This function checks if the table marked as "ancestor" is effectively a table from which the "descendent" table inherits --- that there is an inheritance chain between the two tables. The optional depth argument specifies the length of the inheritance chain between the tables; if not specified, the inheritance distance may be of any length. If the `:description` is omitted, a reasonable substitute will be created. If you find that the function call seems to be getting confused, cast the sequence to the `NAME` type: SELECT is_ancestor_of('myschema', 'ancestor', 'myschema', 'descendent'::NAME); ### `isnt_ancestor_of()` SELECT isnt_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :depth, :description ); SELECT isnt_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :depth ); SELECT isnt_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table, :description ); SELECT isnt_ancestor_of( :ancestor_schema, :ancestor_table, :descendent_schema, :descendent_table ); SELECT isnt_ancestor_of( :ancestor_table, :descendent_table, :depth, :description ); SELECT isnt_ancestor_of( :ancestor_table, :descendent_table, :depth ); SELECT isnt_ancestor_of( :ancestor_table, :descendent_table, :description ); SELECT isnt_ancestor_of( :ancestor_table, :descendent_table ); **Parameters** `:ancestor_schema` : Name of the schema in which the ancestor table must be found. `:ancestor_table` : Name of the ancestor table. `:descendent_schema` : Name of the schema in which the descendent table must be found. `:descendent_table` : Name of the descendent table. `:depth` : The inheritance distance between the two tables. `:description` : Description of the test. This function ensures that the table marked as "ancestor" is not a table from which "descendent" inherits --- that there is no inheritance chain between the two tables. If the optional depth argument is passed, the test enbsures only that the two tablesa are not related at that distance; they still might be an inheritance relationship between them. If the `:description` is omitted, a reasonable substitute will be created. If you find that the function call seems to be getting confused, cast the sequence to the `NAME` type: SELECT isnt_ancestor_of('myschema', 'ancestor', 'myschema', 'descendent'::NAME); ### `is_descendent_of()` SELECT is_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :depth, :description ); SELECT is_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :depth ); SELECT is_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :description ); SELECT is_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table ); SELECT is_descendent_of( :descendent_table, :ancestor_table, :depth, :description ); SELECT is_descendent_of( :descendent_table, :ancestor_table, :depth ); SELECT is_descendent_of( :descendent_table, :ancestor_table, :description ); SELECT is_descendent_of( :descendent_table, :ancestor_table ); **Parameters** `:descendent_schema` : Name of the schema in which the descendent table must be found. `:descendent_table` : Name of the descendent table. `:ancestor_schema` : Name of the schema in which the ancestor table must be found. `:ancestor_table` : Name of the ancestor table. `:depth` : The inheritance distance between the two tables. `:description` : Description of the test. This function provide exactly the same functionality as `is_ancestor_of()`, but with the ancestor and descendent arguments swapped. ### `isnt_descendent_of()` SELECT isnt_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :depth, :description ); SELECT isnt_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :depth ); SELECT isnt_descendent_of( :descendent_schema, :descendent_table, :ancestor_schema, :ancestor_table, :description ); SELECT isnt_descendent_of( :descendent_table, :ancestor_table, :depth, :description ); SELECT isnt_descendent_of( :descendent_table, :ancestor_table, :depth ); SELECT isnt_descendent_of( :descendent_table, :ancestor_table, :description ); SELECT isnt_descendent_of( :descendent_table, :ancestor_table ); **Parameters** `:ancestor_schema` : Name of the schema in which the ancestor table must be found. `:ancestor_table` : Name of the ancestor table. `:descendent_schema` : Name of the schema in which the descendent table must be found. `:descendent_table` : Name of the descendent table. `:depth` : The inheritance distance between the two tables. `:description` : Description of the test. This function provide exactly the same functionality as `isnt_ancestor_of()`, but with the ancestor and descendent arguments swapped. ### `has_sequence()` ### SELECT has_sequence( :schema, :sequence, :description ); SELECT has_sequence( :schema, :sequence ); SELECT has_sequence( :sequence, :description ); SELECT has_sequence( :sequence ); **Parameters** `:schema` : Name of a schema in which to find the sequence. `:sequence` : Name of a sequence. `:description` : A short description of the test. This function tests whether or not a sequence exists in the database. The first argument is a schema name, the second is a sequence name, and the third is the test description. If you omit the schema, the sequence must be visible in the search path. Example: SELECT has_sequence('somesequence'); If you omit the test description, it will be set to "Sequence `:schema`.`:sequence` should exist". If you find that the function call seems to be getting confused, cast the sequence to the `NAME` type: SELECT has_sequence('myschema', 'somesequence'::NAME); ### `hasnt_sequence()` ### SELECT hasnt_sequence( :schema, :sequence, :description ); SELECT hasnt_sequence( :sequence, :description ); SELECT hasnt_sequence( :sequence ); **Parameters** `:schema` : Name of a schema in which to find the sequence. `:sequence` : Name of a sequence. `:description` : A short description of the test. This function is the inverse of `has_sequence()`. The test passes if the specified sequence does *not* exist. ### `has_foreign_table()` ### SELECT has_foreign_table( :schema, :table, :description ); SELECT has_foreign_table( :schema, :table ); SELECT has_foreign_table( :table, :description ); SELECT has_foreign_table( :table ); **Parameters** `:schema` : Name of a schema in which to find the foreign table. `:table` : Name of a foreign table. `:description` : A short description of the test. This function tests whether or not a foreign table exists in the database. The first argument is a schema name, the second is a foreign table name, and the third is the test description. If you omit the schema, the foreign table must be visible in the search path. Example: SELECT has_foreign_table('myschema'::name, 'some_foreign_table'::name); If you omit the test description, it will be set to "Foreign table `:table` should exist". ### `hasnt_foreign_table()` ### SELECT hasnt_foreign_table( :schema, :table, :description ); SELECT hasnt_foreign_table( :schema, :table ); SELECT hasnt_foreign_table( :table, :description ); SELECT hasnt_foreign_table( :table ); **Parameters** `:schema` : Name of a schema in which to find the foreign table. `:table` : Name of a foreign table. `:description` : A short description of the test. This function is the inverse of `has_foreign_table()`. The test passes if the specified foreign table does *not* exist. ### `has_type()` ### SELECT has_type( schema, type, description ); SELECT has_type( schema, type ); SELECT has_type( type, description ); SELECT has_type( type ); **Parameters** `:schema` : Name of a schema in which to find the data type. `:type` : Name of a data type. `:description` : A short description of the test. This function tests whether or not a type exists in the database. Detects all types of types, including base types, composite types, domains, enums, and pseudo-types. The first argument is a schema name, the second is a type name, and the third is the test description. If you omit the schema, the type must be visible in the search path. If you omit the test description, it will be set to "Type `:type` should exist". If you're passing a schema and type rather than type and description, be sure to cast the arguments to `name` values so that your type name doesn't get treated as a description. Example: SELECT has_type( 'myschema', 'sometype' ); If you've created a composite type and want to test that the composed types are a part of it, use the column testing functions to verify them, like so: CREATE TYPE foo AS (id int, name text); SELECT has_type( 'foo' ); SELECT has_column( 'foo', 'id' ); SELECT col_type_is( 'foo', 'id', 'integer' ); ### `hasnt_type()` ### SELECT hasnt_type( schema, type, description ); SELECT hasnt_type( schema, type ); SELECT hasnt_type( type, description ); SELECT hasnt_type( type ); **Parameters** `:schema` : Name of a schema in which to find the data type. `:type` : Name of a data type. `:description` : A short description of the test. This function is the inverse of `has_type()`. The test passes if the specified type does *not* exist. ### `has_composite()` ### SELECT has_composite( schema, type, description ); SELECT has_composite( schema, type ); SELECT has_composite( type, description ); SELECT has_composite( type ); **Parameters** `:schema` : Name of a schema in which to find the composite type. `:composite type` : Name of a composite type. `:description` : A short description of the test. This function tests whether or not a composite type exists in the database. The first argument is a schema name, the second is the name of a composite type, and the third is the test description. If you omit the schema, the composite type must be visible in the search path. If you omit the test description, it will be set to "Composite type `:composite type` should exist". Example: SELECT has_composite( 'myschema', 'somecomposite' ); If you're passing a schema and composite type rather than composite type and description, be sure to cast the arguments to `name` values so that your composite type name doesn't get treated as a description. ### `hasnt_composite()` ### SELECT hasnt_composite( schema, type, description ); SELECT hasnt_composite( schema, type ); SELECT hasnt_composite( type, description ); SELECT hasnt_composite( type ); **Parameters** `:schema` : Name of a schema in which to find the composite type. `:composite type` : Name of a composite type. `:description` : A short description of the test. This function is the inverse of `has_composite()`. The test passes if the specified composite type does *not* exist. ### `has_domain()` ### SELECT has_domain( schema, domain, description ); SELECT has_domain( schema, domain ); SELECT has_domain( domain, description ); SELECT has_domain( domain ); **Parameters** `:schema` : Name of a schema in which to find the domain. `:domain` : Name of a domain. `:description` : A short description of the test. This function tests whether or not a domain exists in the database. The first argument is a schema name, the second is the name of a domain, and the third is the test description. If you omit the schema, the domain must be visible in the search path. If you omit the test description, it will be set to "Domain `:domain` should exist". Example: SELECT has_domain( 'myschema', 'somedomain' ); If you're passing a schema and domain rather than domain and description, be sure to cast the arguments to `name` values so that your domain name doesn't get treated as a description. ### `hasnt_domain()` ### SELECT hasnt_domain( schema, domain, description ); SELECT hasnt_domain( schema, domain ); SELECT hasnt_domain( domain, description ); SELECT hasnt_domain( domain ); **Parameters** `:schema` : Name of a schema in which to find the domain. `:domain` : Name of a domain. `:description` : A short description of the test. This function is the inverse of `has_domain()`. The test passes if the specified domain does *not* exist. ### `has_enum()` ### SELECT has_enum( schema, enum, description ); SELECT has_enum( schema, enum ); SELECT has_enum( enum, description ); SELECT has_enum( enum ); **Parameters** `:schema` : Name of a schema in which to find the enum. `:enum` : Name of a enum. `:description` : A short description of the test. This function tests whether or not a enum exists in the database. The first argument is a schema name, the second is the an enum name, and the third is the test description. If you omit the schema, the enum must be visible in the search path. If you omit the test description, it will be set to "Enum `:enum` should exist". Example: SELECT has_enum( 'myschema', 'someenum' ); If you're passing a schema and enum rather than enum and description, be sure to cast the arguments to `name` values so that your enum name doesn't get treated as a description. ### `hasnt_enum()` ### SELECT hasnt_enum( schema, enum, description ); SELECT hasnt_enum( schema, enum ); SELECT hasnt_enum( enum, description ); SELECT hasnt_enum( enum ); **Parameters** `:schema` : Name of a schema in which to find the enum. `:enum` : Name of a enum. `:description` : A short description of the test. This function is the inverse of `has_enum()`. The test passes if the specified enum does *not* exist. ### `has_index()` ### SELECT has_index( :schema, :table, :index, :columns, :description ); SELECT has_index( :schema, :table, :index, :columns ); SELECT has_index( :schema, :table, :index, :column, :description ); SELECT has_index( :schema, :table, :index, :column ); SELECT has_index( :schema, :table, :index, :description ); SELECT has_index( :schema, :table, :index ); SELECT has_index( :table, :index, :columns, :description ); SELECT has_index( :table, :index, :columns ); SELECT has_index( :table, :index, :column, :description ); SELECT has_index( :table, :index, :column ); SELECT has_index( :table, :index, :description ); SELECT has_index( :table, :index ); **Parameters** `:schema` : Name of a schema in which to find the index. `:table` : Name of a table in which to find index. `:index` : Name of an index. `:columns` : Array of the columns and/or expressions in the index. `:column` : Indexed column name or expression. `:description` : A short description of the test. Checks for the existence of a named index associated with the named table. The `:schema` argument is optional, as is the column name or names or expression, and the description. The columns argument may be a string naming one column or expression, or an array of column names and/or expressions. For expressions, you must use lowercase for all SQL keywords and functions to properly compare to PostgreSQL's internal form of the expression. Non-functional expressions should also be wrapped in parentheses. A few examples: SELECT has_index( 'myschema', 'sometable', 'myindex', ARRAY[ 'somecolumn', 'anothercolumn', 'lower(txtcolumn)' ], 'Index "myindex" should exist' ); SELECT has_index('myschema', 'sometable', 'anidx', 'somecolumn'); SELECT has_index('myschema', 'sometable', 'loweridx', '(somearray[1])'); SELECT has_index('sometable', 'someindex'); If you find that the function call seems to be getting confused, cast the index name to the `NAME` type: SELECT has_index( 'public', 'sometab', 'idx_foo', 'name'::name ); If the index does not exist, `has_index()` will output a diagnostic message such as: # Index "blah" ON public.sometab not found If the index was found but the column specification or expression is incorrect, the diagnostics will look more like this: # have: "idx_baz" ON public.sometab(lower(name)) # want: "idx_baz" ON public.sometab(lower(lname)) Note that unlike most other column parameter arguments in pgTAP, mixed-case column mames crated with double-quotes must be double-quoted when passed to `has_index()`, like so: SELECT has_index( 'myschema', 'sometable', 'myindex', ARRAY[ 'id', '"Name"', 'lower("foo-bar")' ] ); This caveat applies only to column names, not to table and schema names, which should omit double-quoting. ### `hasnt_index()` ### SELECT hasnt_index( schema, table, index, description ); SELECT hasnt_index( schema, table, index ); SELECT hasnt_index( table, index, description ); SELECT hasnt_index( table, index ); **Parameters** `:schema` : Name of a schema in which to not find the index. `:table` : Name of a table in which to not find the index. `:index` : Name of an index. `:description` : A short description of the test. This function is the inverse of `has_index()`. The test passes if the specified index does *not* exist. ### `has_trigger()` ### SELECT has_trigger( :schema, :table, :trigger, :description ); SELECT has_trigger( :schema, :table, :trigger ); SELECT has_trigger( :table, :trigger, :description ); SELECT has_trigger( :table, :trigger )` ### **Parameters** `:schema` : Name of a schema in which to find the trigger. `:table` : Name of a table in which to find the trigger. `:trigger` : Name of an trigger. `:description` : A short description of the test. Tests to see if the specified table has the named trigger. The `:description` is optional, and if the schema is omitted, the table with which the trigger is associated must be visible in the search path. ### `hasnt_trigger()` ### SELECT hasnt_trigger( :schema, :table, :trigger, :description ); SELECT hasnt_trigger( :schema, :table, :trigger ); SELECT hasnt_trigger( :table, :trigger, :description ); SELECT hasnt_trigger( :table, :trigger )` ### **Parameters** `:schema` : Name of a schema in which to not find the trigger. `:table` : Name of a table in which to not find the trigger. `:trigger` : Name of an trigger. `:description` : A short description of the test. This function is the inverse of `has_trigger()`. The test passes if the specified trigger does *not* exist. ### `has_rule()` ### SELECT has_rule( :schema, :table, :rule, :description ); SELECT has_rule( :schema, :table, :rule ); SELECT has_rule( :table, :rule, :description ); SELECT has_rule( :table, :rule )` ### **Parameters** `:schema` : Name of a schema in which to find the rule. `:table` : Name of a table in which to find the rule. `:rule` : Name of an rule. `:description` : A short description of the test. Tests to see if the specified table has the named rule. The `:description` is optional, and if the schema is omitted, the table with which the rule is associated must be visible in the search path. ### `hasnt_rule()` ### SELECT hasnt_rule( :schema, :table, :rule, :description ); SELECT hasnt_rule( :schema, :table, :rule ); SELECT hasnt_rule( :table, :rule, :description ); SELECT hasnt_rule( :table, :rule )` ### **Parameters** `:schema` : Name of a schema in which to not find the rule. `:table` : Name of a table in which to not find the rule. `:rule` : Name of an rule. `:description` : A short description of the test. This function is the inverse of `has_rule()`. The test passes if the specified rule does *not* exist. ### `has_function()` ### SELECT has_function( :schema, :function, :args, :description ); SELECT has_function( :schema, :function, :args ); SELECT has_function( :schema, :function, :description ); SELECT has_function( :schema, :function ); SELECT has_function( :function, :args, :description ); SELECT has_function( :function, :args ); SELECT has_function( :function, :description ); SELECT has_function( :function ); **Parameters** `:schema` : Name of a schema in which to find the function. `:function` : Name of a function or procedure. `:args` : Array of data types of the function arguments. `:description` : A short description of the test. Checks to be sure that the given function or procedure exists in the named schema and with the specified argument data types. If `:schema` is omitted, `has_function()` will search for the function in the schemas defined in the search path. If `:args` is omitted, `has_function()` will see if the function exists without regard to its arguments. Some examples: SELECT has_function( 'pg_catalog', 'decode', ARRAY[ 'text', 'text' ], 'Function decode(text, text) should exist' ); SELECT has_function( 'do_something' ); SELECT has_function( 'do_something', ARRAY['int'] ); SELECT has_function( 'do_something', ARRAY['numeric'] ); If you wish to use the two-argument form of `has_function()`, specifying only the schema and the function name, you must cast the `:function` argument to `:name` in order to disambiguate it from from the `has_function(:function, :description)` form. If you neglect to do so, your results will be unexpected. Also, if you use the string form to specify the `:args` array, be sure to cast it to `name` to disambiguate it from a text string: SELECT has_function( 'lower', '{text}'::name[] ); **Deprecation notice:** The old name for this test function, `can_ok()`, is still available, but emits a warning when called. It will be removed in a future version of pgTAP. ### `hasnt_function()` ### SELECT hasnt_function( :schema, :function, :args, :description ); SELECT hasnt_function( :schema, :function, :args ); SELECT hasnt_function( :schema, :function, :description ); SELECT hasnt_function( :schema, :function ); SELECT hasnt_function( :function, :args, :description ); SELECT hasnt_function( :function, :args ); SELECT hasnt_function( :function, :description ); SELECT hasnt_function( :function ); **Parameters** `:schema` : Name of a schema in which not to find the function. `:function` : Name of a function or procedure. `:args` : Array of data types of the function arguments. `:description` : A short description of the test. This function is the inverse of `has_function()`. The test passes if the specified function or procedure (optionally with the specified signature) does *not* exist. ### `has_cast()` ### SELECT has_cast( :source_type, :target_type, :schema, :function, :description ); SELECT has_cast( :source_type, :target_type, :schema, :function ); SELECT has_cast( :source_type, :target_type, :function, :description ); SELECT has_cast( :source_type, :target_type, :function ); SELECT has_cast( :source_type, :target_type, :description ); SELECT has_cast( :source_type, :target_type ); **Parameters** `:source_type` : Data type of the source value without typemod. `:target_type` : Data type of the target value without typemod. `:schema` : Schema in which to find the operator function. `:function` : Name of the operator function. `:description` : A short description of the test. Tests for the existence of a cast. A cast consists of a source data type, a target data type, and perhaps a (possibly schema-qualified) function. An example: SELECT has_cast( 'integer', 'bigint', 'pg_catalog', 'int8' ); If you omit the description for the 3- or 4-argument version, you'll need to cast the function name to the `NAME` data type so that PostgreSQL doesn't resolve the function name as a description. For example: SELECT has_cast( 'integer', 'bigint', 'int8'::NAME ); pgTAP will generate a useful description if you don't provide one. Types can be defined by their canonical names or their aliases, e.g., `character varying` or `varchar`, so both these tests will pass: SELECT has_cast( 'text', 'character varying' ); SELECT has_cast( 'text', 'varchar' ); Note that pgTAP ignores typemods, so either of these tests will pass: SELECT has_cast( 'integer', 'bit(128)' ); SELECT has_cast( 'integer', 'bit' ); ### `hasnt_cast()` ### SELECT hasnt_cast( :source_type, :target_type, :schema, :function, :description ); SELECT hasnt_cast( :source_type, :target_type, :schema, :function ); SELECT hasnt_cast( :source_type, :target_type, :function, :description ); SELECT hasnt_cast( :source_type, :target_type, :function ); SELECT hasnt_cast( :source_type, :target_type, :description ); SELECT hasnt_cast( :source_type, :target_type ); **Parameters** `:source_type` : Data type of the source value. `:target_type` : Data type of the target value. `:schema` : Schema in which not to find the operator function. `:function` : Name of the operator function. `:description` : A short description of the test. This function is the inverse of `has_cast()`: the test passes if the specified cast does *not* exist. ### `has_operator()` ### SELECT has_operator( :left_type, :schema, :name, :right_type, :return_type, :description ); SELECT has_operator( :left_type, :schema, :name, :right_type, :return_type ); SELECT has_operator( :left_type, :name, :right_type, :return_type, :description ); SELECT has_operator( :left_type, :name, :right_type, :return_type ); SELECT has_operator( :left_type, :name, :right_type, :description ); SELECT has_operator( :left_type, :name, :right_type ); **Parameters** `:left_type` : Data type of the left operand. `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:right_type` : Data type of the right operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. Tests for the presence of a binary operator. If the operator exists with the given schema, name, left and right arguments, and return value, the test will pass. If the operator does not exist, the test will fail. Example: SELECT has_operator( 'integer', 'pg_catalog', '<=', 'integer', 'boolean' ); Types can be defined by their canonical names or their aliases, e.g., `timestamp with time zone` or `timestamptz`, or `character varying` or `varchar`. If you omit the schema name, then the operator must be visible in the search path. If you omit the test description, pgTAP will generate a reasonable one for you. The return value is also optional. If you need to test for a left (prefix) or right (postfix) unary operator, use `has_leftop()` or `has_rightop()` instead. ### `hasnt_operator()` ### SELECT hasnt_operator( :left_type, :schema, :name, :right_type, :return_type, :description ); SELECT hasnt_operator( :left_type, :schema, :name, :right_type, :return_type ); SELECT hasnt_operator( :left_type, :name, :right_type, :return_type, :description ); SELECT hasnt_operator( :left_type, :name, :right_type, :return_type ); SELECT hasnt_operator( :left_type, :name, :right_type, :description ); SELECT hasnt_operator( :left_type, :name, :right_type ); **Parameters** `:left_type` : Data type of the left operand. `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:right_type` : Data type of the right operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. This function is the inverse of `has_operator()`. The test passes if the specified operator does *not* exist. ### `has_leftop()` ### SELECT has_leftop( :schema, :name, :type, :return_type, :description ); SELECT has_leftop( :schema, :name, :type, :return_type ); SELECT has_leftop( :name, :type, :return_type, :description ); SELECT has_leftop( :name, :type, :return_type ); SELECT has_leftop( :name, :type, :description ); SELECT has_leftop( :name, :type ); **Parameters** `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:type` : Data type of the operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. Tests for the presence of a left-unary (prefix) operator. If the operator exists with the given schema, name, right argument, and return value, the test will fail. If the operator does not exist, the test will fail. Example: SELECT has_leftop( 'pg_catalog', '!!', 'bigint', 'numeric' ); If you omit the schema name, then the operator must be visible in the search path. If you omit the test description, pgTAP will generate a reasonable one for you. The return type is also optional. ### `hasnt_leftop()` ### SELECT hasnt_leftop( :schema, :name, :type, :return_type, :description ); SELECT hasnt_leftop( :schema, :name, :type, :return_type ); SELECT hasnt_leftop( :name, :type, :return_type, :description ); SELECT hasnt_leftop( :name, :type, :return_type ); SELECT hasnt_leftop( :name, :type, :description ); SELECT hasnt_leftop( :name, :type ); **Parameters** `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:type` : Data type of the operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. This function is the inverse of `has_leftop()`. The test passes if the specified operator does *not* exist. ### `has_rightop()` ### SELECT has_rightop( :schema, :name, :type, :return_type, :description ); SELECT has_rightop( :schema, :name, :type, :return_type ); SELECT has_rightop( :name, :type, :return_type, :description ); SELECT has_rightop( :name, :type, :return_type ); SELECT has_rightop( :name, :type, :description ); SELECT has_rightop( :name, :type ); **Parameters** `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:type` : Data type of the operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. Tests for the presence of a right-unary (postfix) operator, supported through PostgreSQL 13. If the operator exists with the given left argument, schema, name, and return value, the test will fail. If the operator does not exist, the test will fail. Example: SELECT has_rightop( 'bigint', 'pg_catalog', '!', 'numeric' ); If you omit the schema name, then the operator must be visible in the search path. If you omit the test description, pgTAP will generate a reasonable one for you. The return type is also optional. ### `hasnt_rightop()` ### SELECT hasnt_rightop( :schema, :name, :type, :return_type, :description ); SELECT hasnt_rightop( :schema, :name, :type, :return_type ); SELECT hasnt_rightop( :name, :type, :return_type, :description ); SELECT hasnt_rightop( :name, :type, :return_type ); SELECT hasnt_rightop( :name, :type, :description ); SELECT hasnt_rightop( :name, :type ); **Parameters** `:schema` : Schema in which to find the operator. `:name` : Name of the operator. `:type` : Data type of the operand. `:return_type` : Data type of the return value. `:description` : A short description of the test. This function is the inverse of `hasnt_rightop()`. The test passes if the specified operator does *not* exist. ### `has_opclass()` ### SELECT has_opclass( :schema, :name, :description ); SELECT has_opclass( :schema, :name ); SELECT has_opclass( :name, :description ); SELECT has_opclass( :name ); **Parameters** `:schema` : Schema in which to find the operator class. `:name` : Name of the operator class. `:description` : A short description of the test. Tests for the presence of an operator class. If you omit the schema name, then the operator must be visible in the search path. If you omit the test description, pgTAP will generate a reasonable one for you. The return value is also optional. ### `hasnt_opclass()` ### SELECT hasnt_opclass( :schema, :name, :description ); SELECT hasnt_opclass( :schema, :name ); SELECT hasnt_opclass( :name, :description ); SELECT hasnt_opclass( :name ); **Parameters** `:schema` : Schema in which not to find the operator class. `:name` : Name of the operator class. `:description` : A short description of the test. This function is the inverse of `has_opclass()`. The test passes if the specified operator class does *not* exist. ### `has_role()` ### SELECT has_role( :role, :description ); SELECT has_role( :role ); **Parameters** `:role` : Name of the role. `:description` : A short description of the test. Checks to ensure that a database role exists. If the description is omitted, it will default to "Role `:role` should exist". ### `hasnt_role()` ### SELECT hasnt_role( :role, :description ); SELECT hasnt_role( :role ); **Parameters** `:role` : Name of the role. `:description` : A short description of the test. The inverse of `has_role()`, this function tests for the *absence* of a database role. ### `has_user()` ### SELECT has_user( :user, :description ); SELECT has_user( :user ); **Parameters** `:user` : Name of the user. `:description` : A short description of the test. Checks to ensure that a database user exists. If the description is omitted, it will default to "User `:user` should exist". ### `hasnt_user()` ### SELECT hasnt_user( :user, :description ); SELECT hasnt_user( :user ); **Parameters** `:user` : Name of the user. `:description` : A short description of the test. The inverse of `has_user()`, this function tests for the *absence* of a database user. ### `has_group()` ### SELECT has_group( :group, :description ); SELECT has_group( :group ); **Parameters** `:group` : Name of the group. `:description` : A short description of the test. Checks to ensure that a database group exists. If the description is omitted, it will default to "Group `:group` should exist". ### `hasnt_group()` ### SELECT hasnt_group( :group, :description ); SELECT hasnt_group( :group ); **Parameters** `:group` : Name of the group. `:description` : A short description of the test. The inverse of `has_group()`, this function tests for the *absence* of a database group. ### `has_language()` ### SELECT has_language( :language, :description ); SELECT has_language( :language ); **Parameters** `:language` : Name of the language. `:description` : A short description of the test. Checks to ensure that a procedural language exists. If the description is omitted, it will default to "Procedural language `:language` should exist". ### `hasnt_language()` ### SELECT hasnt_language( :language, :description ); SELECT hasnt_language( :language ); **Parameters** `:language` : Name of the language. `:description` : A short description of the test. The inverse of `has_language()`, this function tests for the *absence* of a procedural language. ### `has_extension()` ### SELECT has_extension( :schema, :extension, :description ); SELECT has_extension( :schema, :extension ); SELECT has_extension( :extension, :description ); SELECT has_extension( :extension ); **Parameters** `:schema` : Schema in which the extension's objects were installed. `:extension` : Name of an extension. `:description` : A short description of the test. This function tests whether or not an extension exists in the database. The first argument is the schema in which the extension objects were installed, the second the extension name, and the third the test description. If the schema is omitted, the may be associated with any schema or no schema. If the test description is omitted, it will be set to "Extension `:extension` should exist". Example: SELECT has_extension('public', 'pgtap'); ### `hasnt_extension()` ### SELECT hasnt_extension( :schema, :extension, :description ); SELECT hasnt_extension( :schema, :extension ); SELECT hasnt_extension( :extension, :description ); SELECT hasnt_extension( :extension ); **Parameters** `:schema` : Schema in which the extension's objects would be installed. `:extension` : Name of an extension. `:description` : A short description of the test. This function is the inverse of `has_extension()`. The test passes if the specified extension does *not* exist. Table For One ------------- Okay, you're sure that your database has exactly the [right schema](#I+Object! "I Object!") and that all of the objects you need [are there](#To+Have+or+Have+Not "To Have or Have Not"). So let's take a closer look at tables. There are a lot of ways to look at tables, to make sure that they have all the columns, indexes, constraints, keys, and indexes they need. So we have the assertions to validate 'em. ### `has_column()` ### SELECT has_column( :schema, :table, :column, :description ); SELECT has_column( :table, :column, :description ); SELECT has_column( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. Tests whether or not a column exists in a given table, view, materialized view or composite type. The first argument is the schema name, the second the table name, the third the column name, and the fourth is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Column `:table.:column` should exist". ### `hasnt_column()` ### SELECT hasnt_column( :schema, :table, :column, :description ); SELECT hasnt_column( :table, :column, :description ); SELECT hasnt_column( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. This function is the inverse of `has_column()`. The test passes if the specified column does *not* exist in the specified table, view, materialized view or composite type. ### `col_not_null()` ### SELECT col_not_null( :schema, :table, :column, :description ); SELECT col_not_null( :schema, :table, :column ); SELECT col_not_null( :table, :column, :description ); SELECT col_not_null( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. Tests whether the specified column has a `NOT NULL` constraint. The first argument is the schema name, the second the table name, the third the column name, and the fourth is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Column `:table.:column` should be NOT NULL". Note that this test will fail with a useful diagnostic message if the table or column in question does not exist. But use `has_column()` to make sure the column exists first, eh? ### `col_is_null()` ### SELECT col_is_null( :schema, :table, :column, :description ); SELECT col_is_null( :schema, :table, :column ); SELECT col_is_null( :table, :column, :description ); SELECT col_is_null( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. This function is the inverse of `col_not_null()`: the test passes if the column does not have a `NOT NULL` constraint. The first argument is the schema name, the second the table name, the third the column name, and the fourth is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Column `:table.:column` should allow NULL". Note that this test will fail with a useful diagnostic message if the table or column in question does not exist. But use `has_column()` to make sure the column exists first, eh? ### `col_has_default()` ### SELECT col_has_default( :schema, :table, :column, :description ); SELECT col_has_default( :table, :column, :description ); SELECT col_has_default( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. Tests whether or not a column has a default value. Fails if the column doesn't have a default value. It will also fail if the column doesn't exist, and emit useful diagnostics to let you know: # Failed test 136: "desc" # Column public.sometab.__asdfasdfs__ does not exist ### `col_hasnt_default()` ### SELECT col_hasnt_default( :schema, :table, :column, :description ); SELECT col_hasnt_default( :table, :column, :description ); SELECT col_hasnt_default( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:description` : A short description of the test. This function is the inverse of `col_has_default()`. The test passes if the specified column does *not* have a default. It will still fail if the column does not exist, and emit useful diagnostics to let you know. ### `col_type_is()` ### SELECT col_type_is( :schema, :table, :column, :type_schema, :type, :description ); SELECT col_type_is( :schema, :table, :column, :type_schema, :type ); SELECT col_type_is( :schema, :table, :column, :type, :description ); SELECT col_type_is( :schema, :table, :column, :type ); SELECT col_type_is( :table, :column, :type, :description ); SELECT col_type_is( :table, :column, :type ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:type_schema` : Schema in which to find the data type. `:type` : Name of a data type. `:description` : A short description of the test. This function tests that the specified column is of a particular type. If it fails, it will emit diagnostics naming the actual type. The first argument is the schema name, the second the table name, the third the column name, the fourth the type's schema, the fifth the type, and the sixth is the test description. If the table schema is omitted, the table must be visible in the search path. If the type schema is omitted, it must be visible in the search path. The schema can optionally be included in the `:type` argument, e.g., "contrib.citext". If the test description is omitted, it will be set to "Column `:schema.:table.:column` should be type `:schema.:type`". Note that this test will fail if the table or column in question does not exist. The type argument may be formatted using the full name of the type or any supported alias. For example, if you created a `varchar(64)` column, you can pass the type as either "varchar(64)" or "character varying(64)". Example: SELECT col_type_is( 'myschema', 'sometable', 'somecolumn', 'timespantz(3)' ); The exception to this rule is interval types, which must be specified as rendered by PostgreSQL itself: SELECT col_type_is( 'myschema', 'sometable', 'somecolumn', 'interval second(3)' ); Types with case-sensitive names or special characters must be double-quoted: SELECT col_type_is( 'myschema', 'sometable', 'somecolumn', '"myType"' ); If the test fails, it will output useful diagnostics. For example this test: SELECT col_type_is( 'pg_catalog', 'pg_type', 'typname', 'text' ); Will produce something like this: # Failed test 138: "Column pg_catalog.pg_type.typname should be type text" # have: name # want: text It will even tell you if the test fails because a column doesn't exist or if the type doesn't exist. But use `has_column()` to make sure the column exists first, eh? ### `col_default_is()` ### SELECT col_default_is( :schema, :table, :column, :default, :description ); SELECT col_default_is( :table, :column, :default, :description ); SELECT col_default_is( :table, :column, :default ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:column` : Name of the column. `:default` : Default value expressed as a string. `:description` : A short description of the test. Tests the default value of a column. If it fails, it will emit diagnostics showing the actual default value. The first argument is the schema name, the second the table name, the third the column name, the fourth the default value, and the fifth is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Column `:table.:column` should default to `:default`". Note that this test will fail if the table or column in question does not exist. The default argument must have an unambiguous type in order for the call to succeed. If you see an error such as 'ERROR: could not determine polymorphic type because input has type "unknown"', it's because you forgot to cast the expected value, probably a `NULL`, to its proper type. IOW, this will fail: SELECT col_default_is( 'tab', age, NULL ); But this will not: SELECT col_default_is( 'tab', age, NULL::integer ); You can also test for functional defaults. Just specify the function call as a string: SELECT col_default_is( 'user', 'created_at', 'now()' ); But beware that the representation of special SQL syntax functions changed in PostgreSQL 10. Where previously a default of `CURRENT_USER` and friends used to be represented as functions: SELECT col_default_is( 'widgets', 'created_by', '"current_user"()' ); As of PostgreSQL 10, they comply with the SQL spec to appear in uppercase and without trailining parentheses: SELECT col_default_is( 'widgets', 'created_by', 'CURRENT_USER' ); If you need to support both variants, use `pg_version_num()` to decide which to use: SELECT col_default_is( 'widgets', 'created_by', CASE WHEN pg_version_num() >= 100000 THEN 'CURRENT_USER' ELSE '"current_user"()' END ); See the note in the [System Information Functions](https://www.postgresql.org/docs/current/functions-info.html) documentation for a complete list. If the test fails, it will output useful diagnostics. For example, this test: SELECT col_default_is( 'pg_catalog', 'pg_type', 'typname', 'foo', 'check typname' ); Will produce something like this: # Failed test 152: "check typname" # have: NULL # want: foo And if the test fails because the table or column in question does not exist, the diagnostics will tell you that, too. But you use `has_column()` and `col_has_default()` to test those conditions before you call `col_default_is()`, right? *Right???* Yeah, good, I thought so. ### `has_pk()` ### SELECT has_pk( :schema, :table, :description ); SELECT has_pk( :schema, :table ); SELECT has_pk( :table, :description ); SELECT has_pk( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. Tests whether or not a table has a primary key. The first argument is the schema name, the second the table name, the the third is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Table `:table` should have a primary key". Note that this test will fail if the table in question does not exist. If you find that the function call confuses the table name for a description, cast the table to the `NAME` type: SELECT has_pk( 'myschema', 'mytable'::name ); ### `hasnt_pk()` ### SELECT hasnt_pk( :schema, :table, :description ); SELECT hasnt_pk( :table, :description ); SELECT hasnt_pk( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. This function is the inverse of `has_pk()`. The test passes if the specified primary key does *not* exist. ### `has_fk()` ### SELECT has_fk( :schema, :table, :description ); SELECT has_fk( :table, :description ); SELECT has_fk( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. Tests whether or not a table has a foreign key constraint. The first argument is the schema name, the second the table name, the the third is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Table `:table` should have a foreign key constraint". Note that this test will fail if the table in question does not exist. ### `hasnt_fk()` ### SELECT hasnt_fk( :schema, :table, :description ); SELECT hasnt_fk( :table, :description ); SELECT hasnt_fk( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. This function is the inverse of `has_fk()`. The test passes if the specified foreign key does *not* exist. ### `col_is_pk()` ### SELECT col_is_pk( :schema, :table, :columns, :description ); SELECT col_is_pk( :schema, :table, :column, :description ); SELECT col_is_pk( :schema, :table, :columns ); SELECT col_is_pk( :schema, :table, :column ); SELECT col_is_pk( :table, :columns, :description ); SELECT col_is_pk( :table, :column, :description ); SELECT col_is_pk( :table, :columns ); SELECT col_is_pk( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the primary key. `:columns` : Array of the names of the primary key columns. `:column` : Name of the primary key column. `:description` : A short description of the test. Tests whether the specified column or columns in a table is/are the primary key for that table. If it fails, it will emit diagnostics showing the actual primary key columns, if any. The first argument is the schema name, the second the table name, the third the column name or an array of column names, and the fourth is the test description. Examples: SELECT col_is_pk( 'myschema', 'sometable', 'id' ); SELECT col_is_pk( 'persons', ARRAY['given_name', 'surname'] ); If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Column `:table(:column)` should be a primary key". Note that this test will fail if the table or column in question does not exist. If the test fails, it will output useful diagnostics. For example this test: SELECT col_is_pk( 'pg_type', 'id' ); Will produce something like this: # Failed test 178: "Column pg_type.id should be a primary key" # have: {} # want: {id} ### `col_isnt_pk()` ### SELECT col_isnt_pk( :schema, :table, :columns, :description ); SELECT col_isnt_pk( :schema, :table, :column, :description ); SELECT col_isnt_pk( :table, :columns, :description ); SELECT col_isnt_pk( :table, :column, :description ); SELECT col_isnt_pk( :table, :columns ); SELECT col_isnt_pk( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table not containing the primary key. `:columns` : Array of the names of the primary key columns. `:column` : Name of the primary key column. `:description` : A short description of the test. This function is the inverse of `col_is_pk()`. The test passes if the specified column or columns are not a primary key. ### `col_is_fk()` ### SELECT col_is_fk( :schema, :table, :columns, :description ); SELECT col_is_fk( :schema, :table, :column, :description ); SELECT col_is_fk( :table, :columns, :description ); SELECT col_is_fk( :table, :column, :description ); SELECT col_is_fk( :table, :columns ); SELECT col_is_fk( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the foreign key constraint. `:columns` : Array of the names of the foreign key columns. `:column` : Name of the foreign key column. `:description` : A short description of the test. Just like `col_is_fk()`, except that it test that the column or array of columns are a primary key. The diagnostics on failure are a bit different, too. Since the table might have more than one foreign key, the diagnostics simply list all of the foreign key constraint columns, like so: # Table widget has foreign key constraints on these columns: # {thingy_id} # {surname,given_name} ### `col_isnt_fk()` ### SELECT col_isnt_fk( :schema, :table, :columns, :description ); SELECT col_isnt_fk( :schema, :table, :column, :description ); SELECT col_isnt_fk( :table, :columns, :description ); SELECT col_isnt_fk( :table, :column, :description ); SELECT col_isnt_fk( :table, :columns ); SELECT col_isnt_fk( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table not containing the foreign key constraint. `:columns` : Array of the names of the foreign key columns. `:column` : Name of the foreign key column. `:description` : A short description of the test. This function is the inverse of `col_is_fk()`. The test passes if the specified column or columns are not a foreign key. ### `fk_ok()` ### SELECT fk_ok( :fk_schema, :fk_table, :fk_columns, :pk_schema, :pk_table, :pk_columns, :description ); SELECT fk_ok( :fk_schema, :fk_table, :fk_columns, :pk_schema, :pk_table, :pk_columns ); SELECT fk_ok( :fk_table, :fk_columns, :pk_table, :pk_columns, :description ); SELECT fk_ok( :fk_table, :fk_columns, :pk_table, :pk_columns ); SELECT fk_ok( :fk_schema, :fk_table, :fk_column, :pk_schema, :pk_table, :pk_column, :description ); SELECT fk_ok( :fk_schema, :fk_table, :fk_column, :pk_schema, :pk_table, :pk_column ); SELECT fk_ok( :fk_table, :fk_column, :pk_table, :pk_column, :description ); SELECT fk_ok( :fk_table, :fk_column, :pk_table, :pk_column ); **Parameters** `:fk_schema` : Schema in which to find the table with the foreign key `:fk_table` : Name of a table containing the foreign key. `:fk_columns` : Array of the names of the foreign key columns. `:fk_column` : Name of the foreign key column. `:pk_schema` : Schema in which to find the table with the primary key `:pk_table` : Name of a table containing the primary key. `:pk_columns` : Array of the names of the primary key columns. `:pk_column` : Name of the primary key column. `:description` : A short description of the test. This function combines `col_is_fk()` and `col_is_pk()` into a single test that also happens to determine that there is in fact a foreign key relationship between the foreign and primary key tables. To properly test your relationships, this should be your main test function of choice. The first three arguments are the schema, table, and column or array of columns that constitute the foreign key constraint. The schema name is optional, and the columns can be specified as a string for a single column or an array of strings for multiple columns. The next three arguments are the schema, table, and column or columns that constitute the corresponding primary key. Again, the schema is optional and the columns may be a string or array of strings (though of course it should have the same number of elements as the foreign key column argument). The seventh argument is an optional description If it's not included, it will be set to `:fk_schema.:fk_table(:fk_column)` should reference `:pk_column.pk_table(:pk_column)`. Some examples: SELECT fk_ok( 'myschema', 'sometable', 'big_id', 'myschema', 'bigtable', 'id' ); SELECT fk_ok( 'contacts', ARRAY['person_given_name', 'person_surname'], 'persons', ARRAY['given_name', 'surname'], ); To test constraints in a temporary table (for example, after running a function that's expected to create one), either omit the schema names or use `pg_my_temp_schema()::regnamespace::name` (on PostgreSQL 9.5 and higher) or `(SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())` (on PostgreSQL 9.4 and lower) to specify the temporary schema name. For example: SELECT fk_ok( pg_my_temp_schema()::regnamespace::name, 'tmpa', 'id', pg_my_temp_schema()::regnamespace::name, 'tmpb', 'id' ); If the test fails, it will output useful diagnostics. For example this test: SELECT fk_ok( 'contacts', 'person_id', 'persons', 'id' ); Will produce something like this: # Failed test 178: "Column contacts(person_id) should reference persons(id)" # have: contacts(person_id) REFERENCES persons(id)" # want: contacts(person_nick) REFERENCES persons(nick)" ### `has_unique()` ### SELECT has_unique( :schema, :table, :description ); SELECT has_unique( :table, :description ); SELECT has_unique( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the unique constraint. `:description` : A short description of the test. Tests whether or not a table has a unique constraint. The first argument is the schema name, the second the table name, the the third is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Table `:table` should have a unique constraint". Note that this test will fail if the table in question does not exist. ### `col_is_unique()` ### SELECT col_is_unique( schema, table, columns, description ); SELECT col_is_unique( schema, table, column, description ); SELECT col_is_unique( schema, table, columns ); SELECT col_is_unique( schema, table, column ); SELECT col_is_unique( table, columns, description ); SELECT col_is_unique( table, column, description ); SELECT col_is_unique( table, columns ); SELECT col_is_unique( table, column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the unique constraint. `:columns` : Array of the names of the unique columns. `:column` : Name of the unique column. `:description` : A short description of the test. Just like `col_is_pk()`, except that it test that the column or array of columns have a unique constraint on them. Examples: SELECT col_is_unique( 'contacts', ARRAY['given_name', 'surname'] ); SELECT col_is_unique( 'myschema', 'sometable', 'other_id', 'myschema.sometable.other_id should be unique' ); If you omit the description for the 3-argument version, you'll need to cast the table and column parameters to the `NAME` data type so that PostgreSQL doesn't resolve the function name as a description. For example: SELECT col_is_unique( 'myschema', 'sometable'::name, 'other_id'::name ); In the event of failure, the diagnostics will list the unique constraints that were actually found, if any: Failed test 40: "users.email should be unique" have: {username} {first_name,last_name} want: {email} ### `has_check()` ### SELECT has_check( :schema, :table, :description ); SELECT has_check( :table, :description ); SELECT has_check( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the check constraint. `:description` : A short description of the test. Tests whether or not a table has a check constraint. The first argument is the schema name, the second the table name, the the third is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Table `:table` should have a check constraint". Note that this test will fail if the table in question does not exist. In the event of failure, the diagnostics will list the columns on the table that do have check constraints, if any: Failed test 41: "users.email should have a check constraint" have: {username} want: {email} ### `col_has_check()` ### SELECT col_has_check( :schema, :table, :columns, :description ); SELECT col_has_check( :schema, :table, :column, :description ); SELECT col_has_check( :table, :columns, :description ); SELECT col_has_check( :table, :column, :description ); SELECT col_has_check( :table, :columns ); SELECT col_has_check( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the check constraint. `:columns` : Array of the names of the check constraint columns. `:column` : Name of the check constraint column. `:description` : A short description of the test. Just like `col_is_pk()`, except that it test that the column or array of columns have a check constraint on them. ### `index_is_unique()` ### SELECT index_is_unique( :schema, :table, :index, :description ); SELECT index_is_unique( :schema, :table, :index ); SELECT index_is_unique( :table, :index ); SELECT index_is_unique( :index ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the index. `:index` : Name of the index. `:description` : A short description of the test. Tests whether an index is unique. ### `index_is_primary()` ### SELECT index_is_primary( :schema, :table, :index, :description ); SELECT index_is_primary( :schema, :table, :index ); SELECT index_is_primary( :table, :index ); SELECT index_is_primary( :index ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the index. `:index` : Name of the index. `:description` : A short description of the test. Tests whether an index is on a primary key. ### `is_partitioned()` ### SELECT is_partitioned( :schema, :table, :description ); SELECT is_partitioned( :schema, :table ); SELECT is_partitioned( :table, :description); SELECT is_partitioned( :table ); **Parameters** `:schema` : Schema in which to find the partitioned table. `:table` : Name of a partitioned table. `:description` : A short description of the test. Tests whether a table is partitioned. The first argument is the schema name, the second the table name, the the third is the test description. If the schema is omitted, the table must be visible in the search path. If the test description is omitted, it will be set to "Table `:table` should be partitioned". Note that this test will fail if the table in question does not exist. ### `isnt_partitioned()` ### SELECT isnt_partitioned( :schema, :table, :description ); SELECT isnt_partitioned( :schema, :table ); SELECT isnt_partitioned( :table, :description); SELECT isnt_partitioned( :table ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table. `:description` : A short description of the test. This function is the inverse of `is_partitioned()`. The test passes if the specified table is *not* partitioned, or if it does not exist. ### `is_partition_of()` ### SELECT is_parent( :child_schema, :child, :parent_schema, :parent_table, :description ); SELECT is_parent( :child_schema, :child, :parent_schema, :parent_table ); SELECT is_parent( :child, :parent_table, :description ); SELECT is_parent( :child, :parent_table ); **Parameters** `:child_schema` : Schema in which to find the partition table. `:child` : Name of a partition table. `:parent_schema` : Schema in which to find the partitioned table. `:parent_table` : Name of a partitioned table. `:description` : A short description of the test. Tests that one table is a partition of another table. The partition (or child) table is specified first, the partitioned (or parent) table second. Without the schema parameters, both tables must be visible in the search path. If the test description is omitted, it will be set to "Table `:child_table` should be a partition of `:parent_table`". Note that this test will fail if either table does not exist. ### `is_clustered()` ### SELECT is_clustered( :schema, :table, :index, :description ); SELECT is_clustered( :schema, :table, :index ); SELECT is_clustered( :table, :index ); SELECT is_clustered( :index ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the index. `:index` : Name of the index. `:description` : A short description of the test. Tests whether a table is clustered on the given index. A table is clustered on an index when the SQL command `CLUSTER TABLE INDEXNAME` has been executed. Clustering reorganizes the table tuples so that they are stored on disk in the order defined by the index. ### `is_indexed()` ### SELECT is_indexed( :schema, :table, :columns, :description ); SELECT is_indexed( :schema, :table, :columns ); SELECT is_indexed( :table, :columns, :description ); SELECT is_indexed( :table, :columns ); SELECT is_indexed( :schema, :table, :column, :description ); SELECT is_indexed( :schema, :table, :column ); SELECT is_indexed( :table, :column, :description ); SELECT is_indexed( :table, :column ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the index. `:columns` : Array of the columns and/or expressions in the index. `:column` : Indexed column name or expression. `:description` : A short description of the test. Checks that the specified columns or expressions are contained in a single index on the named table. Effectively like `has_index()` except that it doesn't require an index name and does require one or more column names or expressions in the defined for the index. Note that unlike most other column parameter arguments in pgTAP, mixed-case column mames crated with double-quotes must be double-quoted when passed to `is_indexed()`, like so: SELECT is_indexed( 'widgets', '"Name"' ); This caveat applies only to column names, not to table and schema names, which should omit double-quoting. ### `index_is_type()` ### SELECT index_is_type( :schema, :table, :index, :type, :description ); SELECT index_is_type( :schema, :table, :index, :type ); SELECT index_is_type( :table, :index, :type ); SELECT index_is_type( :index, :type ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Name of a table containing the index. `:index` : Name of the index. `:type` : The index Type. `:description` : A short description of the test. Tests to ensure that an index is of a particular type. At the time of this writing, the supported types are: * btree * hash * gist * gin If the test fails, it will emit a diagnostic message with the actual index type, like so: # Failed test 175: "Index idx_bar should be a hash index" # have: btree # want: hash Feeling Funky ------------- Perhaps more important than testing the database schema is testing your custom functions. Especially if you write functions that provide the interface for clients to interact with the database, making sure that they work will save you time in the long run. So use these assertions to save yourself heartache in the future. ### `can()` ### SELECT can( :schema, :functions, :description ); SELECT can( :schema, :functions ); SELECT can( :functions, :description ); SELECT can( :functions ); **Parameters** `:schema` : Schema in which to find the functions. `:functions` : Array of function and/or procedure names. `:description` : A short description of the test. Checks to be sure that `:schema` has `:functions` defined. This is subtly different from `functions_are()`. `functions_are()` fails if the functions defined in `:schema` are not exactly the functions defined in `:functions`. `can()`, on the other hand, just makes sure that `:functions` exist. If `:schema` is omitted, then `can()` will look for functions defined in schemas defined in the search path. No matter how many functions are listed in `:functions`, a single call to `can()` counts as one test. If you want otherwise, call `can()` once for each function --- or better yet, use `has_function()`. Example: SELECT can( 'pg_catalog', ARRAY['upper', 'lower'] ); If any of the functions are not defined, the test will fail and the diagnostics will output a list of the functions that are missing, like so: # Failed test 52: "Schema pg_catalog can" # pg_catalog.foo() missing # pg_catalog.bar() missing ### `function_lang_is()` ### SELECT function_lang_is( :schema, :function, :args, :language, :description ); SELECT function_lang_is( :schema, :function, :args, :language ); SELECT function_lang_is( :schema, :function, :language, :description ); SELECT function_lang_is( :schema, :function, :language ); SELECT function_lang_is( :function, :args, :language, :description ); SELECT function_lang_is( :function, :args, :language ); SELECT function_lang_is( :function, :language, :description ); SELECT function_lang_is( :function, :language ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:language` : Name of the procedural language. `:description` : A short description of the test. Tests that a particular function is implemented in a particular procedural language. The function name is required. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Examples: SELECT function_lang_is( 'myschema', 'foo', ARRAY['integer', 'text'], 'plperl' ); SELECT function_lang_is( 'do_something', 'sql' ); SELECT function_lang_is( 'do_something', ARRAY['integer'], 'plpgsql' ); SELECT function_lang_is( 'do_something', ARRAY['numeric'], 'plpgsql' ); In the event of a failure, you'll useful diagnostics will tell you what went wrong, for example: # Failed test 211: "Function mychema.eat(integer, text) should be written in perl" # have: plpgsql # want: perl If the function does not exist, you'll be told that, too. # Failed test 212: "Function myschema.grab() should be written in sql" # Function myschema.grab() does not exist But then you check with `has_function()` first, right? ### `function_returns()` ### SELECT function_returns( :schema, :function, :args, :type, :description ); SELECT function_returns( :schema, :function, :args, :type ); SELECT function_returns( :schema, :function, :type, :description ); SELECT function_returns( :schema, :function, :type ); SELECT function_returns( :function, :args, :type, :description ); SELECT function_returns( :function, :args, :type ); SELECT function_returns( :function, :type, :description ); SELECT function_returns( :function, :type ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:type` : Return value data type. `:description` : A short description of the test. Tests that a particular function returns a particular data type. The `:type` argument may be formatted with full or aliased type names, e.g., `integer`, `int4`, or `int`. For set returning functions, the `:type` argument should start with "setof " (yes, lowercase). Examples: SELECT function_returns( 'myschema', 'foo', ARRAY['int', 'text'], 'integer' ); SELECT function_returns( 'do_something', 'setof boolean' ); SELECT function_returns( 'do_something', ARRAY['integer'], 'boolean' ); SELECT function_returns( 'do_something', ARRAY['numeric'], 'numeric' ); If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Procedures can also be tested; they always return `void`: SELECT function_returns( 'my_proc', 'void' ); In the event of a failure, you'll useful diagnostics will tell you what went wrong, for example: # Failed test 283: "Function oww(integer, text) should return integer" # have: bool # want: integer If the function does not exist, you'll be told that, too. # Failed test 284: "Function oui(integer, text) should return integer" # Function oui(integer, text) does not exist But then you check with `has_function()` first, right? ### `is_definer()` ### SELECT is_definer( :schema, :function, :args, :description ); SELECT is_definer( :schema, :function, :args ); SELECT is_definer( :schema, :function, :description ); SELECT is_definer( :schema, :function ); SELECT is_definer( :function, :args, :description ); SELECT is_definer( :function, :args ); SELECT is_definer( :function, :description ); SELECT is_definer( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function or proceudure name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function or procedure is a security definer (i.e., a "setuid" function). If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Examples: SELECT is_definer( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_definer( 'do_something' ); SELECT is_definer( 'do_something', ARRAY['integer'] ); SELECT is_definer( 'do_something', ARRAY['numeric'] ); If the function does not exist, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be security definer" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_definer()` ### SELECT isnt_definer( :schema, :function, :args, :description ); SELECT isnt_definer( :schema, :function, :args ); SELECT isnt_definer( :schema, :function, :description ); SELECT isnt_definer( :schema, :function ); SELECT isnt_definer( :function, :args, :description ); SELECT isnt_definer( :function, :args ); SELECT isnt_definer( :function, :description ); SELECT isnt_definer( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function or proceure name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_definer()`. The test passes if the specified function or procedure is not a security definer. If the function does not exist, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should not be security definer" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `is_strict()` ### SELECT is_strict( :schema, :function, :args, :description ); SELECT is_strict( :schema, :function, :args ); SELECT is_strict( :schema, :function, :description ); SELECT is_strict( :schema, :function ); SELECT is_strict( :function, :args, :description ); SELECT is_strict( :function, :args ); SELECT is_strict( :function, :description ); SELECT is_strict( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function is a strict, meaning that the function returns null if any argument is null. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Examples: SELECT is_strict( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_strict( 'do_something' ); SELECT is_strict( 'do_something', ARRAY['integer'] ); SELECT is_strict( 'do_something', ARRAY['numeric'] ); If the function does not exist, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be strict" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_strict()` ### SELECT isnt_strict( :schema, :function, :args, :description ); SELECT isnt_strict( :schema, :function, :args ); SELECT isnt_strict( :schema, :function, :description ); SELECT isnt_strict( :schema, :function ); SELECT isnt_strict( :function, :args, :description ); SELECT isnt_strict( :function, :args ); SELECT isnt_strict( :function, :description ); SELECT isnt_strict( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_strict()`. The test passes if the specified function is not strict. If the function does not exist, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be an aggregate function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `is_normal_function()` ### SELECT is_normal_function( :schema, :function, :args, :description ); SELECT is_normal_function( :schema, :function, :args ); SELECT is_normal_function( :schema, :function, :description ); SELECT is_normal_function( :schema, :function ); SELECT is_normal_function( :function, :args, :description ); SELECT is_normal_function( :function, :args ); SELECT is_normal_function( :function, :description ); SELECT is_normal_function( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function is a normal function --- that is, not an aggregate, window, or procedural function. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Fails if the function is not a normal function or if the function does not exist. Examples: SELECT is_normal_function( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_normal_function( 'do_something' ); SELECT is_normal_function( 'do_something', ARRAY['integer'] ); SELECT is_normal_function( 'do_something', ARRAY['numeric'] ); If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be a normal function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_normal_function()` ### SELECT isnt_normal_function( :schema, :function, :args, :description ); SELECT isnt_normal_function( :schema, :function, :args ); SELECT isnt_normal_function( :schema, :function, :description ); SELECT isnt_normal_function( :schema, :function ); SELECT isnt_normal_function( :function, :args, :description ); SELECT isnt_normal_function( :function, :args ); SELECT isnt_normal_function( :function, :description ); SELECT isnt_normal_function( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_normal_function()`. The test passes if the specified function exists and is not a normal function. If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should not be a normal function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `is_aggregate()` ### SELECT is_aggregate( :schema, :function, :args, :description ); SELECT is_aggregate( :schema, :function, :args ); SELECT is_aggregate( :schema, :function, :description ); SELECT is_aggregate( :schema, :function ); SELECT is_aggregate( :function, :args, :description ); SELECT is_aggregate( :function, :args ); SELECT is_aggregate( :function, :description ); SELECT is_aggregate( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function is an aggregate function. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Fails if the function is not an aggregate function, or if the function does not exist. Examples: SELECT is_aggregate( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_aggregate( 'do_something' ); SELECT is_aggregate( 'do_something', ARRAY['integer'] ); SELECT is_aggregate( 'do_something', ARRAY['numeric'] ); If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be an aggregate function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_aggregate()` ### SELECT isnt_aggregate( :schema, :function, :args, :description ); SELECT isnt_aggregate( :schema, :function, :args ); SELECT isnt_aggregate( :schema, :function, :description ); SELECT isnt_aggregate( :schema, :function ); SELECT isnt_aggregate( :function, :args, :description ); SELECT isnt_aggregate( :function, :args ); SELECT isnt_aggregate( :function, :description ); SELECT isnt_aggregate( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_aggregate()`. The test passes if the specified function exists and is not an aggregate function. If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should not be an aggregate function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `is_window()` ### SELECT is_window( :schema, :function, :args, :description ); SELECT is_window( :schema, :function, :args ); SELECT is_window( :schema, :function, :description ); SELECT is_window( :schema, :function ); SELECT is_window( :function, :args, :description ); SELECT is_window( :function, :args ); SELECT is_window( :function, :description ); SELECT is_window( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function is a window function. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Fails if the function is not a window function or if the function does not exist. Examples: SELECT is_window( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_window( 'do_something' ); SELECT is_window( 'do_something', ARRAY['integer'] ); SELECT is_window( 'do_something', ARRAY['numeric'] ); If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be a window function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_window()` ### SELECT isnt_window( :schema, :function, :args, :description ); SELECT isnt_window( :schema, :function, :args ); SELECT isnt_window( :schema, :function, :description ); SELECT isnt_window( :schema, :function ); SELECT isnt_window( :function, :args, :description ); SELECT isnt_window( :function, :args ); SELECT isnt_window( :function, :description ); SELECT isnt_window( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_window()`. The test passes if the specified function exists and is not a window function. If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should not be a window function" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `is_procedure()` ### SELECT is_procedure( :schema, :function, :args, :description ); SELECT is_procedure( :schema, :function, :args ); SELECT is_procedure( :schema, :function, :description ); SELECT is_procedure( :schema, :function ); SELECT is_procedure( :function, :args, :description ); SELECT is_procedure( :function, :args ); SELECT is_procedure( :function, :description ); SELECT is_procedure( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. Tests that a function is a procedural function. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Fails if the function is not a procedure or if the function does not exist. Examples: SELECT is_procedure( 'myschema', 'foo', ARRAY['integer', 'text'] ); SELECT is_procedure( 'do_something' ); SELECT is_procedure( 'do_something', ARRAY['integer'] ); SELECT is_procedure( 'do_something', ARRAY['numeric'] ); If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should be a procedure" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `isnt_procedure()` ### SELECT isnt_procedure( :schema, :function, :args, :description ); SELECT isnt_procedure( :schema, :function, :args ); SELECT isnt_procedure( :schema, :function, :description ); SELECT isnt_procedure( :schema, :function ); SELECT isnt_procedure( :function, :args, :description ); SELECT isnt_procedure( :function, :args ); SELECT isnt_procedure( :function, :description ); SELECT isnt_procedure( :function ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:description` : A short description of the test. This function is the inverse of `is_procedure()`. The test passes if the specified function exists and is not a procedure. If no such function exists, a handy diagnostic message will let you know: # Failed test 290: "Function nasty() should not be a procedure" # Function nasty() does not exist But then you check with `has_function()` first, right? ### `volatility_is()` ### SELECT volatility_is( :schema, :function, :args, :volatility, :description ); SELECT volatility_is( :schema, :function, :args, :volatility ); SELECT volatility_is( :schema, :function, :volatility, :description ); SELECT volatility_is( :schema, :function, :volatility ); SELECT volatility_is( :function, :args, :volatility, :description ); SELECT volatility_is( :function, :args, :volatility ); SELECT volatility_is( :function, :volatility, :description ); SELECT volatility_is( :function, :volatility ); **Parameters** `:schema` : Schema in which to find the function. `:function` : Function name. `:args` : Array of data types for the function arguments. `:volatility` : Volatility level. `:description` : A short description of the test. Tests the volatility of a function. Supported volatilities are "volatile", "stable", and "immutable". Consult the [`CREATE FUNCTION` documentation](https://www.postgresql.org/docs/current/static/sql-createfunction.html) for details. The function name is required. If the `:schema` argument is omitted, then the function must be visible in the search path. If the `:args[]` argument is passed, then the function with that argument signature will be the one tested; otherwise, a function with any signature will be checked (pass an empty array to specify a function with an empty signature). If the `:description` is omitted, a reasonable substitute will be created. Examples: SELECT volatility_is( 'myschema', 'foo', ARRAY['integer', 'text'], 'stable' ); SELECT volatility_is( 'do_something', 'immutable' ); SELECT volatility_is( 'do_something', ARRAY['integer'], 'stable' ); SELECT volatility_is( 'do_something', ARRAY['numeric'], 'volatile' ); In the event of a failure, you'll useful diagnostics will tell you what went wrong, for example: # Failed test 211: "Function mychema.eat(integer, text) should be IMMUTABLE" # have: VOLATILE # want: IMMUTABLE If the function does not exist, you'll be told that, too. # Failed test 212: "Function myschema.grab() should be IMMUTABLE" # Function myschema.grab() does not exist But then you check with `has_function()` first, right? ### `trigger_is()` ### SELECT trigger_is( :schema, :table, :trigger, :func_schema, :function, :description ); SELECT trigger_is( :schema, :table, :trigger, :func_schema, :function ); SELECT trigger_is( :table, :trigger, :function, :description ); SELECT trigger_is( :table, :trigger, :function ); **Parameters** `:schema` : Schema in which to find the table. `:table` : Table in which to find the trigger. `:trigger` : Trigger name. `:func_schema` : Schema in which to find the trigger function. `:function` : Function name. `:description` : A short description of the test. Tests that the specified trigger calls the named function. If not, it outputs a useful diagnostic: # Failed test 31: "Trigger set_users_pass should call hash_password()" # have: hash_pass # want: hash_password Database Deets -------------- Tables and functions aren't the only objects in the database, as you well know. These assertions close the gap by letting you test the attributes of other database objects. ### `language_is_trusted()` ### SELECT language_is_trusted( language, description ); SELECT language_is_trusted( language ); **Parameters** `:language` : Name of a procedural language. `:description` : A short description of the test. Tests that the specified procedural language is trusted. See the [CREATE LANGUAGE](https://www.postgresql.org/docs/current/static/sql-createlanguage.html "CREATE LANGUAGE") documentation for details on trusted and untrusted procedural languages. If the `:description` argument is not passed, a suitably useful default will be created. In the event that the language in question does not exist in the database, `language_is_trusted()` will emit a diagnostic message to alert you to this fact, like so: # Failed test 523: "Procedural language plomgwtf should be trusted" # Procedural language plomgwtf does not exist But you really ought to call `has_language()` first so that you never get that far. ### `enum_has_labels()` ### SELECT enum_has_labels( :schema, :enum, :labels, :description ); SELECT enum_has_labels( :schema, :enum, :labels ); SELECT enum_has_labels( :enum, :labels, :description ); SELECT enum_has_labels( :enum, :labels ); **Parameters** `:schema` : Schema in which to find the enum. `:enum` : Enum name. `:labels` : An array of the enum labels. `:description` : A short description of the test. This function tests that an enum consists of an expected list of labels.The first argument is a schema name, the second an enum name, the third an array of enum labels, and the fourth a description. Example: SELECT enum_has_labels( 'myschema', 'someenum', ARRAY['foo', 'bar'] ); If you omit the schema, the enum must be visible in the search path. If you omit the test description, it will be set to "Enum `:enum` should have labels (`:labels`)". ### `domain_type_is()` ### SELECT domain_type_is( :schema, :domain, :type_schema, :type, :description ); SELECT domain_type_is( :schema, :domain, :type_schema, :type ); SELECT domain_type_is( :schema, :domain, :type, :description ); SELECT domain_type_is( :schema, :domain, :type ); SELECT domain_type_is( :domain, :type, :description ); SELECT domain_type_is( :domain, :type ); **Parameters** `:schema` : Schema in which to find the domain. `:domain` : Domain name. `:type_schema` : Schema in which to find the data type. `:type` : Domain data type. `:description` : A short description of the test. Tests the data type underlying a domain. The first two arguments are the schema and name of the domain. The second two are the schema and name of the type that the domain should extend. The fifth argument is a description. If there is no description, a reasonable default description will be created. The schema arguments are also optional. However, if there is no `:schema` argument, there cannot be a `:type_schema` argument, either, though the schema can be included in the `type` argument, e.g., `contrib.citext`. Types can be defined by their canonical names or their aliases, e.g., `timestamp with time zone` or `timestamptz`, or `character varying` or `varchar`. For the 3- and 4-argument forms with schemas, cast the schemas to `NAME` to avoid ambiguities. Example: SELECT domain_type_is( 'public'::name, 'us_postal_code', 'public'::name, 'text' ); If the data type does not match the type that the domain extends, the test will fail and output diagnostics like so: # Failed test 631: "Domain public.us_postal_code should extend type public.integer" # have: public.text # want: public.integer If the domain in question does not actually exist, the test will fail with diagnostics that tell you so: # Failed test 632: "Domain public.zip_code should extend type public.text" # Domain public.zip_code does not exist ### `domain_type_isnt()` ### SELECT domain_type_isnt( :schema, :domain, :type_schema, :type, :description ); SELECT domain_type_isnt( :schema, :domain, :type_schema, :type ); SELECT domain_type_isnt( :schema, :domain, :type, :description ); SELECT domain_type_isnt( :schema, :domain, :type ); SELECT domain_type_isnt( :domain, :type, :description ); SELECT domain_type_isnt( :domain, :type ); **Parameters** `:schema` : Schema in which to find the domain. `:domain` : Domain name. `:type_schema` : Schema in which to find the data type. `:type` : Domain data type. `:description` : A short description of the test. The inverse of `domain_type_is()`, this function tests that a domain does *not* extend a particular data type. For example, a US postal code domain should probably extend the `text` type, not `integer`, since leading 0s are valid and required. Example: SELECT domain_type_isnt( 'public', 'us_postal_code', 'public', 'integer', 'The us_postal_code domain should not extend the integer type' ); The arguments are the same as for `domain_type_is()`. ### `cast_context_is()` ### SELECT cast_context_is( :source_type, :target_type, :context, :description ); SELECT cast_context_is( :source_type, :target_type, :context ); **Parameters** `:source_type` : The type cast from. `:target_type` : The type cast to. `:context` : The context for the cast, one of "implicit", "assignment", or "explicit". Test that a cast from a source to a target data type has a particular context. Example: SELECT cast_context_is( 'integer', 'bigint', 'implicit' ); The data types may be defined by their canonical names or their aliases, e.g., `character varying` or `varchar`, so both these tests will pass: SELECT cast_context_is( 'text', 'character varying', 'implicit' ); SELECT cast_context_is( 'text', 'varchar', 'implicit' ); The supported contexts are "implicit", "assignment", and "explicit". You can also just pass in "i", "a", or "e". Consult the PostgreSQL [`CREATE CAST`](https://www.postgresql.org/docs/current/static/sql-createcast.html) documentation for the differences between these contexts (hint: they correspond to the default context, `AS IMPLICIT`, and `AS ASSIGNMENT`). If you don't supply a test description, pgTAP will create a reasonable one for you. Test failure will result in useful diagnostics, such as: # Failed test 124: "Cast ("integer" AS "bigint") context should be explicit" # have: implicit # want: explicit If the cast doesn't exist, you'll be told that, too: # Failed test 199: "Cast ("integer" AS foo) context should be explicit" # Cast ("integer" AS foo) does not exist But you've already used `has_cast()` to make sure of that, right? ### `is_superuser()` ### SELECT is_superuser( :user, :description ); SELECT is_superuser( :user ); **Parameters** `:user` : Name of a PostgreSQL user. `:description` : A short description of the test. Tests that a database user is a super user. If the description is omitted, it will default to "User `:user` should be a super user". Example: SELECT is_superuser('theory' ; If the user does not exist in the database, the diagnostics will say so. ### `isnt_superuser()` ### SELECT is_superuser( 'dr_evil', 'User "dr_evil" should not be a super user' ); **Parameters** `:user` : Name of a PostgreSQL user. `:description` : A short description of the test. The inverse of `is_superuser()`, this function tests that a database user is *not* a super user. Note that if the named user does not exist in the database, the test is still considered a failure, and the diagnostics will say so. ### `is_member_of()` ### SELECT is_member_of( :role, :members, :description ); SELECT is_member_of( :role, :members ); SELECT is_member_of( :role, :member, :description ); SELECT is_member_of( :role, :member ); **Parameters** `:role` : Name of a PostgreSQL group role. `:members` : Array of names of roles that should be members of the group role. `:member` : Name of a role that should be a member of the group role. `:description` : A short description of the test. SELECT is_member_of( 'sweeties', 'anna' 'Anna should be a sweetie' ); SELECT is_member_of( 'meanies', ARRAY['dr_evil', 'dr_no' ] ); Checks whether a group role contains a member role or all of an array of member roles. If the description is omitted, it will default to "Should have members of role `:role`." On failure, `is_member_of()` will output diagnostics listing the missing member roles, like so: # Failed test 370: "Should have members of role meanies" # Members missing from the meanies role: # theory # agliodbs If the group role does not exist, the diagnostics will tell you that, instead. But you use `has_role()` to make sure the role exists before you check its members, don't you? Of course you do. ### `isnt_member_of()` ### SELECT isnt_member_of( :role, :members, :description ); SELECT isnt_member_of( :role, :members ); SELECT isnt_member_of( :role, :member, :description ); SELECT isnt_member_of( :role, :member ); **Parameters** `:role` : Name of a PostgreSQL group role. `:members` : Array of names of roles that should *not* be members of the group role. `:member` : Name of a role that should *not* be a member of the group role. `:description` : A short description of the test. SELECT isnt_member_of( 'meanies', 'anna' 'Anna should not be a meanie' ); SELECT isnt_member_of( 'sweeties', ARRAY['dr_evil', 'dr_no' ] ); The inverse of `is_member_of()`, checks whether a group role does not contain a member role or none of an array of member roles. If the description is omitted, it will default to "Should not have members of role `:role`." On failure, `isnt_member_of()` will output diagnostics listing the missing member roles, like so: # Failed test 371: "Should not have members of role sweeties" # Members, who should not be in sweeties role: # dr_evil # dr_no If the group role does not exist, the diagnostics will tell you that, instead. But you use `has_role()` to make sure the role exists before you check its members, don't you? Of course you do. ### `rule_is_instead()` ### SELECT rule_is_instead( :schema, :table, :rule, :description ); SELECT rule_is_instead( :schema, :table, :rule ); SELECT rule_is_instead( :table, :rule, :description ); SELECT rule_is_instead( :table, :rule ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of the table to which the rule is applied. `:rule` : A rule name. `:description` : A short description of the test. Checks whether a rule on the specified relation is an `INSTEAD` rule. See the [`CREATE RULE` Documentation](https://www.postgresql.org/docs/current/static/sql-createrule.html) for details. If the `:schema` argument is omitted, the relation must be visible in the search path. If the `:description` argument is omitted, an appropriate description will be created. An example: SELECT rule_is_instead('public', 'users', 'on_insert'); In the event that the test fails because the rule in question does not actually exist, you will see an appropriate diagnostic such as: # Failed test 625: "Rule on_insert on relation public.users should be an INSTEAD rule" # Rule on_insert does not exist ### `rule_is_on()` ### SELECT rule_is_on( :schema, :table, :rule, :event, :description ); SELECT rule_is_on( :schema, :table, :rule, :event ); SELECT rule_is_on( :table, :rule, :event, :description ); SELECT rule_is_on( :table, :rule, :event ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of the table to which the rule is applied. `:rule` : A rule name. `:event` : Name of a rule event, one of "SELECT", "INSERT", "UPDATE", or "DELETE". `:description` : A short description of the test. Tests the event for a rule, which may be one of "SELECT", "INSERT", "UPDATE", or "DELETE". For the `:event` argument, you can specify the name of the event in any case, or even with a single letter ("s", "i", "u", or "d"). If the `:schema` argument is omitted, then the table must be visible in the search path. If the `:description` is omitted, a reasonable default will be created. Example: SELECT rule_is_on('public', 'users', 'on_insert', 'INSERT'); If the test fails, you'll see useful diagnostics, such as: # Failed test 133: "Rule ins_me should be on INSERT to public.widgets" # have: UPDATE # want: INSERT If the rule in question does not exist, you'll be told that, too: # Failed test 134: "Rule upd_me should be on UPDATE to public.widgets" # Rule upd_me does not exist on public.widgets But then you run `has_rule()` first, don't you? Who owns me? ------------ After testing the availability of several objects, we often need to know who owns an object. ### `db_owner_is ()` ### SELECT db_owner_is ( :dbname, :user, :description ); SELECT db_owner_is ( :dbname, :user ); **Parameters** `:dbname` : Name of a database. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of the database. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT db_owner_is( 'mydb', 'someuser', 'mydb should be owned by someuser' ); SELECT db_owner_is( current_database(), current_user ); In the event that the test fails because the database in question does not actually exist, you will see an appropriate diagnostic such as: # Failed test 16: "Database foo should be owned by www" # Database foo does not exist If the test fails because the database is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Database bar should be owned by root" # have: postgres # want: root ### `schema_owner_is ()` ### SELECT schema_owner_is ( :schemaname, :user, :description ); SELECT schema_owner_is ( :schemaname, :user ); **Parameters** `:schemaname` : Name of a schema. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of the schema. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT schema_owner_is( 'myschema', 'someuser', 'myschema should be owned by someuser' ); SELECT schema_owner_is( current_schema(), current_user ); In the event that the test fails because the schema in question does not actually exist, you will see an appropriate diagnostic such as: # Failed test 16: "Schema foo should be owned by www" # Schema foo does not exist If the test fails because the schema is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Schema bar should be owned by root" # have: postgres # want: root ### `tablespace_owner_is ()` ### SELECT tablespace_owner_is ( :tablespacename, :user, :description ); SELECT tablespace_owner_is ( :tablespacename, :user ); **Parameters** `:tablespacename` : Name of a tablespace. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of the tablespace. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT tablespace_owner_is( 'myts', 'joe', 'Joe has mytablespace' ); SELECT tablespace_owner_is( 'pg_default', current_user ); In the event that the test fails because the tablespace in question does not actually exist, you will see an appropriate diagnostic such as: # Failed test 16: "Tablespace ssd should be owned by www" # Tablespace ssd does not exist If the test fails because the tablespace is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Tablespace raid_hds should be owned by root" # have: postgres # want: root ### `relation_owner_is ()` ### SELECT relation_owner_is ( :schema, :relation, :user, :description ); SELECT relation_owner_is ( :relation, :user, :description ); SELECT relation_owner_is ( :schema, :relation, :user ); SELECT relation_owner_is ( :relation, :user ); **Parameters** `:schema` : Name of a schema in which find to the `:relation`. `:relation` : Name of a relation. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a relation. Relations are tables, views, materialized views, sequences, composite types, foreign tables, and toast tables. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT relation_owner_is( 'public', 'mytable', 'someuser', 'mytable should be owned by someuser' ); SELECT relation_owner_is( current_schema(), 'mysequence', current_user ); In the event that the test fails because the relation in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Relation foo should be owned by www" # Relation foo does not exist If the test fails because the relation is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Relation bar should be owned by root" # have: postgres # want: root ### `table_owner_is ()` ### SELECT table_owner_is ( :schema, :table, :user, :description ); SELECT table_owner_is ( :table, :user, :description ); SELECT table_owner_is ( :schema, :table, :user ); SELECT table_owner_is ( :table, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a table. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT table_owner_is( 'public', 'mytable', 'someuser', 'mytable should be owned by someuser' ); SELECT table_owner_is( 'widgets', current_user ); Note that this function will not recognize foreign tables; use `foreign_table_owner_is()` to test for the presence of foreign tables. In the event that the test fails because the table in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Table foo should be owned by www" # Table foo does not exist If the test fails because the table is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Table bar should be owned by root" # have: postgres # want: root ### `view_owner_is ()` ### SELECT view_owner_is ( :schema, :view, :user, :description ); SELECT view_owner_is ( :view, :user, :description ); SELECT view_owner_is ( :schema, :view, :user ); SELECT view_owner_is ( :view, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:view`. `:view` : Name of a view. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a view. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT view_owner_is( 'public', 'myview', 'someuser', 'myview should be owned by someuser' ); SELECT view_owner_is( 'widgets', current_user ); In the event that the test fails because the view in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "View foo should be owned by www" # View foo does not exist If the test fails because the view is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "View bar should be owned by root" # have: postgres # want: root ### `materialized_view_owner_is ()` ### SELECT materialized_view_owner_is ( :schema, :materialized_view, :user, :description ); SELECT materialized_view_owner_is ( :materialized_view, :user, :description ); SELECT materialized_view_owner_is ( :schema, :materialized_view, :user ); SELECT materialized_view_owner_is ( :materialized_view, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:materialized_view`. `:materialized_view` : Name of a materialized view. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a materialized view. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT view_owner_is( 'public', 'my_matview', 'someuser', 'my_matview should be owned by someuser' ); SELECT materialized_view_owner_is( 'widgets', current_user ); In the event that the test fails because the materialized view in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Materialized view foo should be owned by www" # Materialized view foo does not exist If the test fails because the materialized view is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Materialized view bar should be owned by root" # have: postgres # want: root ### `sequence_owner_is ()` ### SELECT sequence_owner_is ( :schema, :sequence, :user, :description ); SELECT sequence_owner_is ( :sequence, :user, :description ); SELECT sequence_owner_is ( :schema, :sequence, :user ); SELECT sequence_owner_is ( :sequence, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:sequence`. `:sequence` : Name of a sequence. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a sequence. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT sequence_owner_is( 'public', 'mysequence', 'someuser', 'mysequence should be owned by someuser' ); SELECT sequence_owner_is( 'widgets', current_user ); In the event that the test fails because the sequence in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Sequence foo should be owned by www" # Sequence foo does not exist If the test fails because the sequence is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Sequence bar should be owned by root" # have: postgres # want: root ### `composite_owner_is ()` ### SELECT composite_owner_is ( :schema, :composite, :user, :description ); SELECT composite_owner_is ( :composite, :user, :description ); SELECT composite_owner_is ( :schema, :composite, :user ); SELECT composite_owner_is ( :composite, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:composite` type. `:composite` : Name of a composite type. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a composite. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT composite_owner_is( 'public', 'mycomposite', 'someuser', 'mycomposite should be owned by someuser' ); SELECT composite_owner_is( 'widgets', current_user ); In the event that the test fails because the composite in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Composite type foo should be owned by www" # Composite type foo does not exist If the test fails because the composite is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Composite type bar should be owned by root" # have: postgres # want: root ### `foreign_table_owner_is ()` ### SELECT foreign_table_owner_is ( :schema, :foreign_table, :user, :description ); SELECT foreign_table_owner_is ( :foreign_table, :user, :description ); SELECT foreign_table_owner_is ( :schema, :foreign_table, :user ); SELECT foreign_table_owner_is ( :foreign_table, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:foreign_table`. `:foreign_table` : Name of a foreign table. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a foreign table. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT foreign_table_owner_is( 'public', 'mytable', 'someuser', 'mytable should be owned by someuser' ); SELECT foreign_table_owner_is( 'widgets', current_user ); In the event that the test fails because the foreign table in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Foreign table foo should be owned by www" # Foreign table foo does not exist If the test fails because the foreign table is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Foreign table bar should be owned by root" # have: postgres # want: root ### `index_owner_is ()` ### SELECT index_owner_is ( :schema, :table, :index, :user, :description ); SELECT index_owner_is ( :table, :index, :user, :description ); SELECT index_owner_is ( :schema, :table, :index, :user ); SELECT index_owner_is ( :table, :index, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:table, :index`. `:table` : Name of a table. `:table` : Name of an index on the table. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of an index. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT index_owner_is( 'public', 'mytable', 'idx_name', 'someuser', 'Index "idx_name" on mytable should be owned by someuser' ); SELECT index_owner_is( 'widgets', 'widgets_pkey', current_user ); In the event that the test fails because the index in question does not actually exist, or the table or schema it's on does not exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Index idx_foo should be owned by root" # Index idx_foo on table darfoo not found If the test fails because the table is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Index idx_foo on table bar should be owned by bob" # have: postgres # want: bob ### `function_owner_is ()` ### SELECT function_owner_is ( :schema, :function, :args, :user, :description ); SELECT function_owner_is ( :function, :args, :user, :description ); SELECT function_owner_is ( :schema, :function, :args, :user ); SELECT function_owner_is ( :function, :args, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:function`. `:function` : Name of a function. `:args` : Array of data types of the function arguments. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a function. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT function_owner_is( 'public', 'frobulate', ARRAY['integer', 'text'], 'someuser', 'public.frobulate(integer, text) should be owned by someuser' ); SELECT function_owner_is( 'masticate', ARRAY['text'], current_user ); In the event that the test fails because the function in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Function foo() should be owned by www" # Function foo() does not exist If the test fails because the function is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Function bar() should be owned by root" # have: postgres # want: root ### `language_owner_is ()` ### SELECT language_owner_is ( :languagename, :user, :description ); SELECT language_owner_is ( :languagename, :user ); **Parameters** `:languagename` : Name of a language. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a procedural language. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT language_owner_is( 'plpgsql', 'larry', 'Larry should own plpgsql' ); SELECT language_owner_is( 'plperl', current_user ); In the event that the test fails because the language in question does not actually exist, you will see an appropriate diagnostic such as: # Failed test 16: "Language pllolcode should be owned by meow" # Language pllolcode does not exist If the test fails because the language is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "Language plruby should be owned by mats" # have: postgres # want: mats ### `opclass_owner_is ()` ### SELECT opclass_owner_is ( :schema, :opclass, :user, :description ); SELECT opclass_owner_is ( :opclass, :user, :description ); SELECT opclass_owner_is ( :schema, :opclass, :user ); SELECT opclass_owner_is ( :opclass, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:opclass`. `:opclass` : Name of an operator class. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of an operator class. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT opclass_owner_is( 'pg_catalog', 'int4_ops', 'postgres', 'Operator class int4_ops should be owned by postgres' ); SELECT opclass_owner_is( 'my_ops', current_user ); In the event that the test fails because the operator class in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "operator class foo should be owned by www" # operator class foo does not exist If the test fails because the operator class is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "operator class bar should be owned by root" # have: postgres # want: root ### `type_owner_is ()` ### SELECT type_owner_is ( :schema, :type, :user, :description ); SELECT type_owner_is ( :type, :user, :description ); SELECT type_owner_is ( :schema, :type, :user ); SELECT type_owner_is ( :type, :user ); **Parameters** `:schema` : Name of a schema in which to find the `:type`. `:type` : Name of a type. `:user` : Name of a user. `:description` : A short description of the test. Tests the ownership of a data type. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT type_owner_is( 'pg_catalog', 'int4', 'postgres', 'type int4 should be owned by postgres' ); SELECT type_owner_is( 'us_postal_code', current_user ); In the event that the test fails because the type in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "type uk_postal_code should be owned by www" # type uk_postal_code does not exist If the test fails because the type is not owned by the specified user, the diagnostics will look something like: # Failed test 17: "type us_postal_code should be owned by root" # have: postgres # want: root Privileged Access ----------------- So we know who owns the objects. But what about other roles? Can they access database objects? Let's find out! ### `database_privs_are()` SELECT database_privs_are ( :db, :role, :privileges, :description ); SELECT database_privs_are ( :db, :role, :privileges ); **Parameters** `:db` : Name of a database. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the database. `:description` : A short description of the test. Tests the privileges granted to a role to access a database. The available database privileges are: * CREATE * CONNECT * TEMPORARY If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT database_privs_are( 'flipr', 'fred', ARRAY['CONNECT', 'TEMPORARY'], 'Fred should be granted CONNECT and TERMPORARY on db "flipr"' ); SELECT database_privs_are( 'dept_corrections', ARRAY['CREATE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted CREATE on database banks" # Extra privileges: # CONNECT # TEMPORARY Likewise if the role is not granted some of the specified permissions on the database: # Failed test 15: "Role kurk should be granted CONNECT, TEMPORARY on database banks" # Missing privileges: # CREATE In the event that the test fails because the database in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted CONNECT on database maindb" # Database maindb does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted CONNECT, CREATE on database widgets" # Role slim does not exist ### `tablespace_privs_are()` SELECT tablespace_privs_are ( :tablespace, :role, :privileges, :description ); SELECT tablespace_privs_are ( :tablespace, :role, :privileges ); **Parameters** `:tablespace` : Name of a tablespace. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the tablespace. `:description` : A short description of the test. Tests the privileges granted to a role to access a tablespace. The available function privileges are: * CREATE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT tablespace_privs_are( 'ssd', 'fred', ARRAY['CREATE'], 'Fred should be granted CREATE on tablespace "ssd"' ); SELECT tablespace_privs_are( 'san', ARRAY['CREATE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on tablespace hdd" # Extra privileges: # CREATE Likewise if the role is not granted some of the specified permissions on the tablespace: # Failed test 15: "Role kurk should be granted USAGE on ssd" # Missing privileges: # CREATE In the event that the test fails because the tablespace in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted CREATE on tablespace tape" # Tablespace tape does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted CREATE on san" # Role slim does not exist ### `schema_privs_are()` SELECT schema_privs_are ( :schema, :role, :privileges, :description ); SELECT schema_privs_are ( :schema, :role, :privileges ); **Parameters** `:schema` : Name of a schema. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the schema. `:description` : A short description of the test. Tests the privileges granted to a role to access a schema. The available schema privileges are: * CREATE * USAGE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT schema_privs_are( 'flipr', 'fred', ARRAY['CREATE', 'USAGE'], 'Fred should be granted CREATE and USAGE on schema "flipr"' ); SELECT schema_privs_are( 'hr', ARRAY['USAGE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on schema pinata" # Extra privileges: # CREATE # USAGE Likewise if the role is not granted some of the specified permissions on the schema: # Failed test 15: "Role kurk should be granted CREATE, USAGE on schema stuff" # Missing privileges: # CREATE In the event that the test fails because the schema in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted USAGE on schema main" # Schema main does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted CREATE, USAGE on schema admin" # Role slim does not exist ### `table_privs_are()` SELECT table_privs_are ( :schema, :table, :role, :privileges, :description ); SELECT table_privs_are ( :schema, :table, :role, :privileges ); SELECT table_privs_are ( :table, :role, :privileges, :description ); SELECT table_privs_are ( :table, :role, :privileges ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of a table. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the table. `:description` : A short description of the test. Tests the privileges granted to a role to access a table. The available table privileges are: * DELETE * INSERT * REFERENCES * RULE * SELECT * TRIGGER * TRUNCATE * UPDATE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT table_privs_are( 'public', 'frobulate', 'fred', ARRAY['SELECT', 'DELETE'], 'Fred should be able to select and delete on frobulate' ); SELECT table_privs_are( 'widgets', 'slim', ARRAY['INSERT', 'UPDATE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted SELECT on widgets" # Extra privileges: # DELETE # INSERT # UPDATE Likewise if the role is not granted some of the specified permissions on the table: # Failed test 15: "Role kurk should be granted SELECT, INSERT, UPDATE on widgets" # Missing privileges: # INSERT # UPDATE In the event that the test fails because the table in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted SELECT on widgets" # Table widgets does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted SELECT on widgets" # Role slim does not exist ### `sequence_privs_are()` SELECT sequence_privs_are ( :schema, :sequence, :role, :privileges, :description ); SELECT sequence_privs_are ( :schema, :sequence, :role, :privileges ); SELECT sequence_privs_are ( :sequence, :role, :privileges, :description ); SELECT sequence_privs_are ( :sequence, :role, :privileges ); **Parameters** `:schema` : Name of a schema in which to find the sequence. `:sequence` : Name of a sequence. `:role` : Name of a user or group role. `:privileges` : An array of sequence privileges the role should be granted to the sequence. `:description` : A short description of the test. Tests the privileges granted to a role to access a sequence. The available sequence privileges are: * SELECT * UPDATE * USAGE Note that sequence privileges were added in PostgreSQL 9.0, so this function will likely throw an exception on earlier versions. If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT sequence_privs_are( 'public', 'seq_ids', 'fred', ARRAY['SELECT', 'UPDATE'], 'Fred should be able to select and update seq_ids' ); SELECT sequence_privs_are( 'seq_u', 'slim', ARRAY['USAGE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted SELECT on seq_foo_id" # Extra privileges: # UPDATE # USAGE Likewise if the role is not granted some of the specified permissions on the sequence: # Failed test 15: "Role kurk should be granted USAGE on seq_widgets" # Missing privileges: # SELECT # UPDATE In the event that the test fails because the sequence in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted SELECT on seq_widgets" # Sequence widgets does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted SELECT on seq_widgets" # Role slim does not exist ### `any_column_privs_are()` SELECT any_column_privs_are ( :schema, :table, :role, :privileges, :description ); SELECT any_column_privs_are ( :schema, :table, :role, :privileges ); SELECT any_column_privs_are ( :table, :role, :privileges, :description ); SELECT any_column_privs_are ( :table, :role, :privileges ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of a table. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the table. `:description` : A short description of the test. Tests the privileges granted to access one or more of the columns in a table. The available column privileges are: * INSERT * REFERENCES * SELECT * UPDATE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT any_column_privs_are( 'public', 'frobulate', 'fred', ARRAY['SELECT', 'UPDATE'], 'Fred should be able to select and update columns in frobulate' ); SELECT any_column_privs_are( 'widgets', 'slim', ARRAY['INSERT', 'UPDATE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted SELECT on columns in widgets" # Extra privileges: # INSERT # UPDATE Likewise if the role is not granted some of the specified permissions on the table: # Failed test 15: "Role kurk should be granted SELECT, INSERT, UPDATE on columns in widgets" # Missing privileges: # INSERT # UPDATE In the event that the test fails because the table in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted SELECT on columns in widgets" # Table widgets does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted SELECT on columns in widgets" # Role slim does not exist ### `column_privs_are()` SELECT column_privs_are ( :schema, :table, :column, :role, :privileges, :description ); SELECT column_privs_are ( :schema, :table, :column, :role, :privileges ); SELECT column_privs_are ( :table, :column, :role, :privileges, :description ); SELECT column_privs_are ( :table, :column, :role, :privileges ); **Parameters** `:schema` : Name of a schema in which to find the table. `:table` : Name of a table. `:column` : Name of a column. `:role` : Name of a user or group role. `:privileges` : An array of column privileges the role should be granted to the column. `:description` : A short description of the test. Tests the privileges granted to a role to access a single column. The available column privileges are: * INSERT * REFERENCES * SELECT * UPDATE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT column_privs_are( 'public', 'frobulate', 'id', 'fred', ARRAY['SELECT', 'UPDATE'], 'Fred should be able to select and update frobulate.id' ); SELECT column_privs_are( 'widgets', 'name', 'slim', ARRAY['INSERT', 'UPDATE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted SELECT on widgets.foo" # Extra privileges: # INSERT # UPDATE Likewise if the role is not granted some of the specified permissions on the table: # Failed test 15: "Role kurk should be granted SELECT, INSERT, UPDATE on widgets.foo" # Missing privileges: # INSERT # UPDATE In the event that the test fails because the table in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted SELECT on widgets.foo" # Table widgets does not exist If the test fails because the column does not actually exist or is not visible, the diagnostics will tell you: # Failed test 17: "Role slim should be granted SELECT on gadgets.foo" # Column gadgets.foo does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 18: "Role slim should be granted SELECT on gadgets.foo" # Role slim does not exist ### `function_privs_are()` SELECT function_privs_are ( :schema, :function, :args, :role, :privileges, :description ); SELECT function_privs_are ( :schema, :function, :args, :role, :privileges ); SELECT function_privs_are ( :function, :args, :role, :privileges, :description ); SELECT function_privs_are ( :function, :args, :role, :privileges ); **Parameters** `:schema` : Name of a schema in which to find the function. `:function` : Name of a function. `:args` : Array of function arguments. `:role` : Name of a user or group role. `:privileges` : An array of function privileges the role should be granted to the function. `:description` : A short description of the test. Tests the privileges granted to a role to access a function. The available function privileges are: * EXECUTE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT function_privs_are( 'public', 'frobulate', ARRAY['integer'], 'fred', ARRAY['EXECUTE'], 'Fred should be able to execute frobulate(int)' ); SELECT function_privs_are( 'bake', '{}', 'slim', '{}'); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on foo()" # Extra privileges: # EXECUTE Likewise if the role is not granted some of the specified permissions on the function: # Failed test 15: "Role kurk should be granted EXECUTE foo()" # Missing privileges: # EXECUTE In the event that the test fails because the function in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted EXECUTE on foo(int)" # Function foo(int) does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted EXECUTE on foo()" # Role slim does not exist ### `language_privs_are()` SELECT language_privs_are ( :lang, :role, :privileges, :description ); SELECT language_privs_are ( :lang, :role, :privileges ); **Parameters** `:lang` : Name of a language. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the language. `:description` : A short description of the test. Tests the privileges granted to a role to access a language. The available function privileges are: * USAGE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT language_privs_are( 'plpgsql', 'fred', ARRAY['USAGE'], 'Fred should be granted USAGE on language "flipr"' ); SELECT language_privs_are( 'plperl', ARRAY['USAGE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on banks" # Extra privileges: # USAGE Likewise if the role is not granted some of the specified permissions on the language: # Failed test 15: "Role kurk should be granted USAGE on banks" # Missing privileges: # USAGE In the event that the test fails because the language in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted USAGE on plr" # Language plr does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted USAGE on pllolcode" # Role slim does not exist ### `fdw_privs_are()` SELECT fdw_privs_are ( :fdw, :role, :privileges, :description ); SELECT fdw_privs_are ( :fdw, :role, :privileges ); **Parameters** `:fdw` : Name of a foreign data wrapper. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the foreign data wrapper. `:description` : A short description of the test. Tests the privileges granted to a role to access a foreign data wrapper. The available function privileges are: * USAGE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT fdw_privs_are( 'oracle', 'fred', ARRAY['USAGE'], 'Fred should be granted USAGE on fdw "oracle"' ); SELECT fdw_privs_are( 'log_csv', ARRAY['USAGE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on odbc" # Extra privileges: # USAGE Likewise if the role is not granted some of the specified permissions on the FDW: # Failed test 15: "Role kurk should be granted USAGE on odbc" # Missing privileges: # USAGE In the event that the test fails because the FDW in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted USAGE on FDW sqlite" # FDW sqlite does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted USAGE on sqlite" # Role slim does not exist ### `server_privs_are()` SELECT server_privs_are ( :server, :role, :privileges, :description ); SELECT server_privs_are ( :server, :role, :privileges ); **Parameters** `:server` : Name of a server. `:role` : Name of a user or group role. `:privileges` : An array of table privileges the role should be granted to the server. `:description` : A short description of the test. Tests the privileges granted to a role to access a server. The available function privileges are: * USAGE If the `:description` argument is omitted, an appropriate description will be created. Examples: SELECT server_privs_are( 'otherdb', 'fred', ARRAY['USAGE'], 'Fred should be granted USAGE on server "otherdb"' ); SELECT server_privs_are( 'myserv', ARRAY['USAGE'] ); If the role is granted permissions other than those specified, the diagnostics will list the extra permissions, like so: # Failed test 14: "Role bob should be granted no privileges on myserv" # Extra privileges: # USAGE Likewise if the role is not granted some of the specified permissions on the server: # Failed test 15: "Role kurk should be granted USAGE on oltp" # Missing privileges: # USAGE In the event that the test fails because the server in question does not actually exist or is not visible, you will see an appropriate diagnostic such as: # Failed test 16: "Role slim should be granted USAGE on server oltp" # server oltp does not exist If the test fails because the role does not exist, the diagnostics will look something like: # Failed test 17: "Role slim should be granted USAGE on oltp" # Role slim does not exist ### `policies_are()` ### SELECT policies_are( :schema, :table, :policies, :description ); SELECT policies_are( :schema, :table, :policies ); SELECT policies_are( :table, :policies, :description ); SELECT policies_are( :table, :policies ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table in which to find policies. `:policies` : An array of policy names. `:description` : A short description of the test. This function tests that all of the policies on the named table are only the policies that *should* be on that table. If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT policies_are( 'myschema', 'atable', ARRAY[ 'atable_policy_one', 'atable_policy_two' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing policies, like so: # Failed test 13: "Table myschema.atable should have the correct policies" # Extra policies: # policy_for_atable # Missing policies: # atable_policy_two ### `policy_roles_are()` ### SELECT policy_roles_are( :schema, :table, :policy, :roles, :description ); SELECT policy_roles_are( :schema, :table, :policy, :roles ); SELECT policy_roles_are( :table, :policy, :roles, :description ); SELECT policy_roles_are( :table, :policy, :roles ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table to which `:policy` applies. `:policy` : Name of a policy. `:roles` : An array of role names to which `:policy` is applied. `:description` : A short description of the test. This function tests whether the roles to which policy applies are only the roles that *should* be on that policy. If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the description is omitted, a generally useful default description will be generated. Example: SELECT policy_roles_are( 'myschema', 'atable', 'apolicy' ARRAY[ 'atable_apolicy_role_one', 'atable_apolicy_role_two' ] ); In the event of a failure, you'll see diagnostics listing the extra and/or missing policy roles, like so: # Failed test 13: "Policy apolicy for table myschema.atable should have the correct roles" # Extra policy roles: # arole_one # Missing policy roles: # atable_apolicy_role_one ### `policy_cmd_is()` ### SELECT policy_cmd_is( :schema, :table, :policy, :command, :description ); SELECT policy_cmd_is( :schema, :table, :policy, :command ); SELECT policy_cmd_is( :table, :policy, :command, :description ); SELECT policy_cmd_is( :table, :policy, :command ); **Parameters** `:schema` : Name of a schema in which to find the `:table`. `:table` : Name of a table to which `:policy` applies. `:policy` : Name of a policy. `:command` : The command type to which the `:policy` is applied. `:description` : A short description of the test. This function tests whether the command to which policy applies is same as command that is given in function arguments. The available policy `:command` types are: * SELECT * INSERT * UPDATE * DELETE * ALL If the `:schema` argument is omitted, the table must be visible in the search path, excluding `pg_catalog` and `information_schema`. If the `:description` is omitted (but `:schema` is present, be sure to cast `:policy` to name), a generally useful default description will be generated. Example: SELECT policy_cmd_is( 'myschema', 'atable', 'apolicy'::NAME 'all' ); In the event of a failure, you'll see diagnostics listing the extra and/or missing policy command, like so: # Failed test 13: "Policy apolicy for table myschema.atable should apply to ALL command" # have: INSERT # want: ALL No Test for the Wicked ====================== There is more to pgTAP. Oh *so* much more! You can output your own [diagnostics](#Diagnostics). You can write [conditional tests](#Conditional+Tests) based on the output of [utility functions](#Utility+Functions). You can [batch up tests in functions](#Tap+That+Batch). Read on to learn all about it. Diagnostics ----------- If you pick the right test function, you'll usually get a good idea of what went wrong when it failed. But sometimes it doesn't work out that way. So here we have ways for you to write your own diagnostic messages which are safer than just `\echo` or `SELECT foo`. ### `diag()` ### SELECT diag( :lines ); **Parameters** `:lines` : A list of one or more SQL values of the same type. Returns a diagnostic message which is guaranteed not to interfere with test output. Handy for this sort of thing: -- Output a diagnostic message if the collation is not en_US.UTF-8. SELECT diag( E'These tests expect LC_COLLATE to be en_US.UTF-8,\n', 'but yours is set to ', setting, E'.\n', 'As a result, some tests may fail. YMMV.' ) FROM pg_settings WHERE name = 'lc_collate' AND setting <> 'en_US.UTF-8'; Which would produce: # These tests expect LC_COLLATE to be en_US.UTF-8, # but yours is set to en_US.ISO8859-1. # As a result, some tests may fail. YMMV. You can pass data of any type to `diag()` and it will all be converted to text for the diagnostics. You can also pass any number of arguments (as long as they are all the same data type) and they will be concatenated together. Conditional Tests ----------------- Sometimes running a test under certain conditions will cause the test script or function to die. A certain function or feature isn't implemented (such as `sha256()` prior to PostgreSQL 11), some resource isn't available (like a procedural language), or a contrib module isn't available. In these cases it's necessary to skip tests, or declare that they are supposed to fail but will work in the future (a todo test). ### `skip()` ### SELECT skip( :why, :how_many ); SELECT skip( :how_many, :why ); SELECT skip( :why ); SELECT skip( :how_many ); **Parameters** `:why` : Reason for skipping the tests. `:how_many` : Number of tests to skip Outputs SKIP test results. Use it in a conditional expression within a `SELECT` statement to replace the output of a test that you otherwise would have run. SELECT CASE WHEN pg_version_num() < 80300 THEN skip('has_enum() not supported before 8.3', 2 ) ELSE collect_tap( has_enum( 'bug_status' ), has_enum( 'bug_status', 'mydesc' ) ) END; Note how use of the conditional `CASE` statement has been used to determine whether or not to run a couple of tests. If they are to be run, they are run through `collect_tap()`, so that we can run a few tests in the same query. If we don't want to run them, we call `skip()` and tell it how many tests we're skipping. If you don't specify how many tests to skip, `skip()` will assume that you're skipping only one. This is useful for the simple case, of course: SELECT CASE current_schema() WHEN 'public' THEN is( :this, :that ) ELSE skip( 'Tests not running in the "public" schema' ) END; But you can also use it in a `SELECT` statement that would otherwise return multiple rows: SELECT CASE current_schema() WHEN 'public' THEN is( nspname, 'public' ) ELSE skip( 'Cannot see the public schema' ) END FROM pg_namespace; This will cause it to skip the same number of rows as would have been tested had the `WHEN` condition been true. ### `todo()` ### SELECT todo( :why, :how_many ); SELECT todo( :how_many, :why ); SELECT todo( :why ); SELECT todo( :how_many ); **Parameters** `:why` : Reason for marking tests as to dos. `:how_many` : Number of tests to mark as to dos. Declares a series of tests that you expect to fail and why. Perhaps it's because you haven't fixed a bug or haven't finished a new feature: SELECT todo('URIGeller not finished', 2); \set card '\'Eight of clubs\'' SELECT is( URIGeller.yourCard(), :card, 'Is THIS your card?' ); SELECT is( URIGeller.bendSpoon(), 'bent', 'Spoon bending, how original' ); With `todo()`, `:how_many` specifies how many tests are expected to fail. If `:how_many` is omitted, it defaults to 1. pgTAP will run the tests normally, but print out special flags indicating they are "todo" tests. The test harness will interpret these failures as ok. Should any todo test pass, the harness will report it as an unexpected success. You then know that the thing you had todo is done and can remove the call to `todo()`. The nice part about todo tests, as opposed to simply commenting out a block of tests, is that they're like a programmatic todo list. You know how much work is left to be done, you're aware of what bugs there are, and you'll know immediately when they're fixed. ### `todo_start( why )` ### ### `todo_start( )` ### This function allows you declare all subsequent tests as TODO tests, up until the `todo_end()` function is called. The `todo()` syntax is generally pretty good about figuring out whether or not we're in a TODO test. However, often we find it difficult to specify the *number* of tests that are TODO tests. Thus, you can instead use `todo_start()` and `todo_end()` to more easily define the scope of your TODO tests. Note that you can nest TODO tests, too: SELECT todo_start('working on this'); -- lots of code SELECT todo_start('working on that'); -- more code SELECT todo_end(); SELECT todo_end(); This is generally not recommended, but large testing systems often have weird internal needs. The `todo_start()` and `todo_end()` function should also work with the `todo()` function, although it's not guaranteed and its use is also discouraged: SELECT todo_start('working on this'); -- lots of code SELECT todo('working on that', 2); -- Two tests for which the above line applies -- Followed by more tests scoped till the following line. SELECT todo_end(); We recommend that you pick one style or another of TODO to be on the safe side. ### `todo_end()` ### Stops running tests as TODO tests. This function is fatal if called without a preceding `todo_start()` method call. ### `in_todo()` ### Returns true if the test is currently inside a TODO block. Utility Functions ----------------- Along with the usual array of testing, planning, and diagnostic functions, pTAP provides a few extra functions to make the work of testing more pleasant. ### `pgtap_version()` ### SELECT pgtap_version(); Returns the version of pgTAP installed in the server. The value is `NUMERIC`, and thus suitable for comparing to a decimal value: SELECT CASE WHEN pgtap_version() < 0.17 THEN skip('No sequence assertions before pgTAP 0.17') ELSE has_sequence('my_big_seq') END; ### `pg_version()` ### SELECT pg_version(); Returns the server version number against which pgTAP was compiled. This is the stringified version number displayed in the first part of the core `version()` function and stored in the "server_version" setting: try=% select current_setting( 'server_version'), pg_version(); current_setting | pg_version -----------------+------------ 12.2 | 12.2 (1 row) ### `pg_version_num()` ### SELECT pg_version_num(); Returns an integer representation of the server version number against which pgTAP was compiled. This function is useful for determining whether or not certain tests should be run or skipped (using `skip()`) depending on the version of PostgreSQL. For example: SELECT CASE WHEN pg_version_num() < 80300 THEN skip('has_enum() not supported before 8.3' ) ELSE has_enum( 'bug_status', 'mydesc' ) END; The revision level is in the tens position, the minor version in the thousands position, and the major version in the ten thousands position and above (assuming PostgreSQL 10 is ever released, it will be in the hundred thousands position). This value is the same as the `server_version_num` setting. ### `os_name()` ### SELECT os_name(); Returns a string representing the name of the operating system on which pgTAP was compiled. This can be useful for determining whether or not to skip tests on certain operating systems. This is usually the same a the output of `uname`, but converted to lower case. There are some semantics in the pgTAP build process to detect other operating systems, though assistance in improving such detection would be greatly appreciated. **NOTE:** The values returned by this function may change in the future, depending on how good the pgTAP build process gets at detecting a OS. ### `collect_tap()` ### SELECT collect_tap(:lines); **Parameters** `:lines` : A list of one or more lines of TAP. Collects the results of one or more pgTAP tests and returns them all. Useful when used in combination with `skip()`: SELECT CASE os_name() WHEN 'darwin' THEN collect_tap( cmp_ok( 'Bjørn'::text, '>', 'Bjorn', 'ø > o' ), cmp_ok( 'Pınar'::text, '>', 'Pinar', 'ı > i' ), cmp_ok( 'José'::text, '>', 'Jose', 'é > e' ), cmp_ok( 'Täp'::text, '>', 'Tap', 'ä > a' ) ) ELSE skip('Collation-specific test', 4) END; ### `display_oper()` ### SELECT display_oper( :opername, :operoid ); **Parameters** `:opername` : Operator name. `:operoid` : Operator OID. Similar to casting an operator OID to `regoperator`, only the schema is not included in the display. For example: SELECT display_oper(oprname, oid ) FROM pg_operator; Used internally by pgTAP to compare operators, but may be more generally useful. ### `format_type_string()` ### SELECT format_type_string( :text ); **Parameters** `:text` : An SQL type declaration, optionally schema-qualified. This function normalizes data type declarations for accurate comparison to table columns by `col_type_is()`. It's effectively the identical to the calling `format_type()` with the type OID and type modifier that define the column, but returns a `NULL` on an invalid or missing type, rather than raising an error. Types can be defined by their canonical names or their aliases, e.g., `character varying` or `varchar`. The exception is `interval` types, which must be specified exactly as Postgres renders them internally, e.g., `'interval(0)`, `interval second(0)`, or `interval day to second(4)`. try=# SELECT format_type_string('timestamp(3)'); format_type_string -------------------------------- timestamp(3) without time zone ### `findfuncs()` ### SELECT findfuncs( :schema, :pattern, :exclude_pattern ); SELECT findfuncs( :schema, :pattern ); SELECT findfuncs( :pattern, :exclude_pattern ); SELECT findfuncs( :pattern ); **Parameters** `:schema` : Schema to search for functions. `:pattern` : Regular expression pattern against which to match function names. `:pattern` : Regular expression pattern to exclude functions with matching names. This function searches the named schema or, if no schema is passed, the search patch, for all functions that match the regular expression pattern. The optional exclude regular expression pattern can be used to prevent matchin startup/setup/teardown/shutdown functions. The functions it finds are returned as an array of text values, with each value consisting of the schema name, a dot, and the function name. For example: SELECT findfuncs('tests', '^test); findfuncs ----------------------------------- {tests.test_foo,tests."test bar"} (1 row) Tap that Batch -------------- Sometimes it can be useful to batch a lot of TAP tests into a function. The simplest way to do so is to define a function that `RETURNS SETOF TEXT` and then simply call `RETURN NEXT` for each TAP test. Here's a simple example: CREATE OR REPLACE FUNCTION my_tests( ) RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); RETURN NEXT pass( 'plpgsql simple 2' ); END; $$ LANGUAGE plpgsql; Then you can just call the function to run all of your TAP tests at once: SELECT plan(2); SELECT * FROM my_tests(); SELECT * FROM finish(); ### `do_tap()` ### SELECT do_tap( :schema, :pattern ); SELECT do_tap( :schema ); SELECT do_tap( :pattern ); SELECT do_tap(); **Parameters** `:schema` : Name of a schema containing pgTAP test functions. `:pattern` : Regular expression pattern against which to match function names. If you like you can create a whole slew of these batched tap functions, and then use the `do_tap()` function to run them all at once. If passed no arguments, it will attempt to find all visible functions that start with "test". If passed a schema name, it will look for and run test functions only in that schema (be sure to cast the schema to `name` if it is the only argument). If passed a regular expression pattern, it will look for function names that match that pattern in the search path. If passed both, it will of course only search for test functions that match the function in the named schema. This can be very useful if you prefer to keep all of your TAP tests in functions defined in the database. Simply call `plan()`, use `do_tap()` to execute all of your tests, and then call `finish()`. A dead simple example: SELECT plan(32); SELECT * FROM do_tap('testschema'::name); SELECT * FROM finish(); As a bonus, if `client_min_messages` is set to "warning", "error", "fatal", or "panic", the name of each function will be emitted as a diagnostic message before it is called. For example, if `do_tap()` found and executed two TAP testing functions an `client_min_messages` is set to "warning", output will look something like this: # public.test_this() ok 1 - simple pass ok 2 - another simple pass # public.test_that() ok 3 - that simple ok 4 - that simple 2 Which will make it much easier to tell what functions need to be examined for failing tests. ### `runtests()` ### SELECT runtests( :schema, :pattern ); SELECT runtests( :schema ); SELECT runtests( :pattern ); SELECT runtests( ); **Parameters** `:schema` : Name of a schema containing pgTAP test functions. `:pattern` : Regular expression pattern against which to match function names. If you'd like pgTAP to plan, run all of your test functions, and finish, all in one fell swoop, use `runtests()`. This most closely emulates the xUnit testing environment, similar to the functionality of [PGUnit](http://en.dklab.ru/lib/dklab_pgunit/). Example: SELECT * FROM runtests( 'testschema', '^test' ); As with `do_tap()`, you can pass in a schema argument and/or a pattern that the names of the tests functions can match. If you pass in only the schema argument, be sure to cast it to `name` to identify it as a schema name rather than a pattern: SELECT * FROM runtests('testschema'::name); Unlike `do_tap()`, `runtests()` fully supports startup, shutdown, setup, and teardown functions, as well as transactional rollbacks between tests. It also outputs the test plan, executes each test function as a TAP subtest, and finishes the tests, so you don't have to call `plan()` or `finish()` yourself. The output, assuming a single startup test, two subtests, and a single shutdown test, will look something like this: ok 1 - Startup test # Subtest: public.test_this() ok 1 - simple pass ok 2 - another simple pass ok 2 - public.test_this() # Subtest: public.test_that() ok 1 - that simple ok 2 - that simple 2 ok 3 - public.test_that() ok 4 - Shutdown test 1..4 The fixture functions run by `runtests()` are as follows: * `^startup` - Functions whose names start with "startup" are run in alphabetical order before any test functions are run. * `^setup` - Functions whose names start with "setup" are run in alphabetical order before each test function is run. * `^teardown` - Functions whose names start with "teardown" are run in alphabetical order after each test function is run. They will not be run, however, after a test that has died. * `^shutdown` - Functions whose names start with "shutdown" are run in alphabetical order after all test functions have been run. Note that all tests executed by `runtests()` are run within a single transaction, and each test is run in a subtransaction that also includes execution all the setup and teardown functions. All transactions are rolled back after each test function, and at the end of testing, leaving your database in largely the same condition as it was in when you started it (the one exception I'm aware of being sequences, which are not rolled back to the value used at the beginning of a rolled-back transaction). Secrets of the pgTAP Mavens =========================== Over the years, a number of techniques have evolved to make all of our pgTAP testing lives easier. Here are some of them. Relational-style Loops ---------------------- Need to test a bunch of objects and find yourself looking for some kind of `for` loop to [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) off with? SQL doesn't have one, of course, but that's because it doesn't need one: the whole language is built around doing things to a bunch of rows. So take advantage of it: build relations with the [`VALUES`](https://www.postgresql.org/docs/current/static/sql-values.html) command! For example, to make sure you have a table in a defined list of schemas, try something like this: SELECT has_table(sch, 'widgets', format('Has %I.widgets', sch)) FROM (VALUES('amazon'), ('starbucks'), ('boeing')) F(sch); Note the use of the [`format` function](https://www.postgresql.org/docs/current/static/functions-string.html#functions-string-format) to make a nice test description, too. Here's a more complicated example that uses a cross join to test that various columns are `NOT NULL` in a specific table in a bunch of schemas: SELECT col_not_null(sch, 'table1', col) FROM (VALUES('schema1'), ('schema1')) AS stmp (sch) CROSS JOIN (VALUES('col_pk'), ('col2'), ('col3')) AS ctmp (col); Compose Yourself ================ So, you've been using pgTAP for a while, and now you want to write your own test functions. Go ahead; I don't mind. In fact, I encourage it. How? Why, by providing a function you can use to test your tests, of course! But first, a brief primer on writing your own test functions. There isn't much to it, really. Just write your function to do whatever comparison you want. As long as you have a boolean value indicating whether or not the test passed, you're golden. Just then use `ok()` to ensure that everything is tracked appropriately by a test script. For example, say that you wanted to create a function to ensure that two text values always compare case-insensitively. Sure you could do this with `is()` and the `LOWER()` function, but if you're doing this all the time, you might want to simplify things. Here's how to go about it: CREATE OR REPLACE FUNCTION lc_is (text, text, text) RETURNS TEXT AS $$ DECLARE result BOOLEAN; BEGIN result := LOWER($1) = LOWER($2); RETURN ok( result, $3 ) || CASE WHEN result THEN '' ELSE E'\n' || diag( ' Have: ' || $1 || E'\n Want: ' || $2; ) END; END; $$ LANGUAGE plpgsql; Yep, that's it. The key is to always use pgTAP's `ok()` function to guarantee that the output is properly formatted, uses the next number in the sequence, and the results are properly recorded in the database for summarization at the end of the test script. You can also provide diagnostics as appropriate; just append them to the output of `ok()` as we've done here. Of course, you don't have to directly use `ok()`; you can also use another pgTAP function that ultimately calls `ok()`. IOW, while the above example is instructive, this version is easier on the eyes: CREATE OR REPLACE FUNCTION lc_is ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT is( LOWER($1), LOWER($2), $3); $$ LANGUAGE sql; But either way, let pgTAP handle recording the test results and formatting the output. Testing Test Functions ---------------------- Now you've written your test function. So how do you test it? Why, with this handy-dandy test function! ### `check_test()` ### SELECT check_test( :test_output, :is_ok, :name, :want_description, :want_diag, :match_diag ); SELECT check_test( :test_output, :is_ok, :name, :want_description, :want_diag ); SELECT check_test( :test_output, :is_ok, :name, :want_description ); SELECT check_test( :test_output, :is_ok, :name ); SELECT check_test( :test_output, :is_ok ); **Parameters** `:test_output` : The output from your test. Usually it's just returned by a call to the test function itself. Required. `:is_ok` : Boolean indicating whether or not the test is expected to pass. Required. `:name` : A brief name for your test, to make it easier to find failures in your test script. Optional. `:want_description` : Expected test description to be output by the test. Optional. Use an empty string to test that no description is output. `:want_diag` : Expected diagnostic message output during the execution of a test. Must always follow whatever is output by the call to `ok()`. Optional. Use an empty string to test that no description is output. `:match_diag` : Use `matches()` to compare the diagnostics rather than `:is()`. Useful for those situations where you're not sure what will be in the output, but you can match it with a regular expression. This function runs anywhere between one and three tests against a test function. At its simplest, you just pass in the output of your test function (and it must be one and **only one** test function's output, or you'll screw up the count, so don't do that!) and a boolean value indicating whether or not you expect the test to have passed. That looks something like this: SELECT * FROM check_test( lc_eq('This', 'THIS', 'eq'), true ); All other arguments are optional, but I recommend that you *always* include a short test name to make it easier to track down failures in your test script. `check_test()` uses this name to construct descriptions of all of the tests it runs. For example, without a short name, the above example will yield output like so: not ok 14 - Test should pass Yeah, but which test? So give it a very succinct name and you'll know what test. If you have a lot of these, it won't be much help. So give each call to `check_test()` a name: SELECT * FROM check_test( lc_eq('This', 'THIS', 'eq'), true, 'Simple lc_eq test', ); Then you'll get output more like this: not ok 14 - Simple lc_test should pass Which will make it much easier to find the failing test in your test script. The optional fourth argument is the description you expect to be output. This is especially important if your test function generates a description when none is passed to it. You want to make sure that your function generates the test description you think it should! This will cause a second test to be run on your test function. So for something like this: SELECT * FROM check_test( lc_eq( ''this'', ''THIS'' ), true, 'lc_eq() test', 'this is THIS' ); The output then would look something like this, assuming that the `lc_eq()` function generated the proper description (the above example does not): ok 42 - lc_eq() test should pass ok 43 - lc_eq() test should have the proper description See how there are two tests run for a single call to `check_test()`? Be sure to adjust your plan accordingly. Also note how the test name was used in the descriptions for both tests. If the test had failed, it would output a nice diagnostics. Internally it just uses `is()` to compare the strings: # Failed test 43: "lc_eq() test should have the proper description" # have: 'this is this' # want: 'this is THIS' The fifth argument, `:want_diag`, which is also optional, compares the diagnostics generated during the test to an expected string. Such diagnostics **must** follow whatever is output by the call to `ok()` in your test. Your test function should not call `diag()` until after it calls `ok()` or things will get truly funky. Assuming you've followed that rule in your `lc_eq()` test function, see what happens when a `lc_eq()` fails. Write your test to test the diagnostics like so: SELECT * FROM check_test( lc_eq( ''this'', ''THat'' ), false, 'lc_eq() failing test', 'this is THat', E' Want: this\n Have: THat ); This of course triggers a third test to run. The output will look like so: ok 44 - lc_eq() failing test should fail ok 45 - lc_eq() failing test should have the proper description ok 46 - lc_eq() failing test should have the proper diagnostics And of course, it the diagnostic test fails, it will output diagnostics just like a description failure would, something like this: # Failed test 46: "lc_eq() failing test should have the proper diagnostics" # have: Have: this # Want: that # want: Have: this # Want: THat If you pass in the optional sixth argument, `:match_diag`, the `:want_diag` argument will be compared to the actual diagnostic output using `matches()` instead of `is()`. This allows you to use a regular expression in the `:want_diag` argument to match the output, for those situations where some part of the output might vary, such as time-based diagnostics. I realize that all of this can be a bit confusing, given the various haves and wants, but it gets the job done. Of course, if your diagnostics use something other than indented "have" and "want", such failures will be easier to read. But either way, *do* test your diagnostics! Compatibility ============= Here are some notes on how pgTAP is built for particular versions of PostgreSQL. This helps you to understand any side-effects. To see the specifics for each version of PostgreSQL, consult the files in the `compat/` directory in the pgTAP distribution. 11 and Up --------- No changes. Everything should just work. 10 and Down ----------- * The stored procedure-testing funtions are not available, because stored procedures were not introduced until 11. 9.6 and Down ------------ * The partition-testing functions are not available, because partitions were not introduced until 10. 9.4 and Down ------------ * lives_ok() and throws_ok() will not trap ASSERT_FAILURE, since asserts do not exist prior to 9.5. 9.2 and Down ------------ * Lacks full automated testing. Recommend using 9.4 or higher. * Diagnostic output from `lives_ok()` and xUnit function exceptions will not include schema, table, column, data type, or constraint information, since such diagnostics were not introduced until 9.3. 9.1 and Down ------------ * Lacks full automated testing. Recommend using 9.4 or higher. * Diagnostic output from `lives_ok()` and xUnit function exceptions will not error context or details, since such diagnostics were not introduced until 9.2. 9.0 and Down ------------ No longer supported. Metadata ======== Public Repository ----------------- The source code for pgTAP is available on [GitHub](https://github.com/theory/pgtap/tree/). Please feel free to fork and contribute! Mail List --------- Join the pgTAP community by subscribing to the [pgtap-users mail list](https://groups.google.com/forum/#!forum/pgtap-users). All questions, comments, suggestions, and bug reports are welcomed there. Author ------ [David E. Wheeler](https://justatheory.com/) Credits ------- * Michael Schwern and chromatic for Test::More. * Adrian Howard for Test::Exception. Copyright and License --------------------- Copyright (c) 2008-2023 David E. Wheeler. Some rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL DAVID E. WHEELER BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DAVID E. WHEELER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. DAVID E. WHEELER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND DAVID E. WHEELER HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. pgtap-1.3.2/pgtap.control000066400000000000000000000002601455775703000153600ustar00rootroot00000000000000# pgTAP extension comment = 'Unit testing for PostgreSQL' default_version = '1.3.2' module_pathname = '$libdir/pgtap' requires = 'plpgsql' relocatable = true superuser = false pgtap-1.3.2/release.md000066400000000000000000000111441455775703000146100ustar00rootroot00000000000000pgTAP Release Management ======================== Here are the steps to take to make a release of pgTAP: * Review and fix any open bugs in the [issue tracker](https://github.com/theory/pgtap/issues). * Review and merge any appropriate [pull requests](https://github.com/theory/pgtap/pulls). * Make sure that [all tests](https://github.com/theory/pgtap/actions) pass on all supported versions of Postgres. If you want to run the tests manually, you can use the [pgxn-utils Docker image](https://github.com/pgxn/docker-pgxn-tools) or [pgenv](https://github.com/theory/pgenv/) to install and switch between versions. For each version, ensure that: + Patches apply cleanly (try to eliminate Hunk warnings for patches to `pgtap.sql` itself, usually by fixing line numbers) + All files are installed. + `ALTER EXTENSION pgtap UPDATE;` works. + `CREATE EXTENSION pgtap;` works. + All tests pass in `make installcheck`. * If you've made any significant changes while testing versions backward, test them again in forward order (9.1, 9.2, 9.3, etc.) to make sure the changes didn't break any later versions. * Review the documentation in `doc/pgtap.mmd`, and make any necessary changes, including to the list of PostgreSQL version-compatibility notes at the end of the document. * Add an item to the top of the `%changelog` section of `contrib/pgtap.spec`. It should use the version you're about to release, as well as the date (use `date +'%a %b %d %Y'`) and your name and email address. Add at least one bullet mentioning the upgrade. * Run `make html` (you'll need [MultiMarkdown](https://fletcherpenney.net/multimarkdown/) (Homebrew: `brew install multimarkdown`) in your path and the [Pod::Simple::XHTML](https://metacpan.org/module/Pod::Simple::XHTML) (Homebrew: `brew install cpanm && cpanm Pod::Simple::XHTML`) Perl module installed), then checkout the `gh-pages` branch and make these changes: + `cp .documentation.html.template documentation.html`. Edit documentation.html, the main div should look like this:
+ Copy the first `

` and `

` from `doc/pgtap.html` into the `DOCS INTRO HERE` section. + Copy the rest of `doc/pgtap.html` into the `DOCS HERE, WITH INTRO MOVED ABOVE` section. + Copy the entire contents of `doc/toc.html` into the `DOC SANS pgTAP x.xx` section, and then remove the first `

  • ` element that says "pgTAP x.xx". + Review to ensure that everything looks right; use `git diff` to make sure nothing important was lost. It should mainly be additions. + Commit the changes, but don't push them yet. * Go back to the `main` branch and proofread the additions to the `Changes` file since the last release. Make sure all relevant changes are recorded there, and that any typos or formatting errors are corrected. * Timestamp the `Changes` file. I generate the timestamp like so: perl -MDateTime -e 'print DateTime->now->datetime . "Z\n"' Paste that into the line with the new version, maybe increment by a minute to account for the time you'll need to actually do the release. * Commit the timestamp and push it: git ci -m 'Timestamp v0.98.0.' git push * Once again make sure [all tests](https://github.com/theory/pgtap/actions) pass. Fix any that fail. * Once all tests pass, tag the release with its semantic version (including the leading `v`) and push the tag. git tag -sm 'Tag v0.98.0.' v0.98.0 git push --tags * Monitor the [release workflow](https://github.com/theory/pgtap/actions/workflows/release.yml) to make sure the new version is released on both PGXN and GitHub. * Push the `gh-pages` branch: git push * Increment the minor version to kick off development for the next release. The version should be added to the `Changes` file, and incremented in the following files: + `META.json` (including for the three parts of the `provides` section) + `README.md` + `contrib/pgtap.spec` + `doc/pgtap.mmd` + `pgtap.control` * Commit that change and push it. git ci -m 'Increment to v1.0.1.' git push * Start hacking on the next version! pgtap-1.3.2/sql/000077500000000000000000000000001455775703000134445ustar00rootroot00000000000000pgtap-1.3.2/sql/pgtap--0.90.0--0.91.0.sql000066400000000000000000000013331455775703000166770ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.91;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION has_tablespace( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN IF pg_version_num() >= 90200 THEN RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 AND pg_tablespace_location(oid) = $2 ), $3 ); ELSE RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 AND spclocation = $2 ), $3 ); END IF; END; $$ LANGUAGE plpgsql; pgtap-1.3.2/sql/pgtap--0.91.0--0.92.0.sql000066400000000000000000001521461455775703000167120ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.92;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _cexists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE c.relname = $1 AND pg_catalog.pg_table_is_visible(c.oid) AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2 ); $$ LANGUAGE SQL; -- has_foreign_table( schema, table, description ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_foreign_table( table, description ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1 ), $2 ); $$ LANGUAGE SQL; -- has_foreign_table( table ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME ) RETURNS TEXT AS $$ SELECT has_foreign_table( $1, 'Foreign table ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_foreign_table( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_foreign_table( table, description ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_foreign_table( table ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_foreign_table( $1, 'Foreign table ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- has_composite( schema, type, description ) CREATE OR REPLACE FUNCTION has_composite ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'c', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_composite( type, description ) CREATE OR REPLACE FUNCTION has_composite ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'c', $1 ), $2 ); $$ LANGUAGE SQL; -- has_composite( type ) CREATE OR REPLACE FUNCTION has_composite ( NAME ) RETURNS TEXT AS $$ SELECT has_composite( $1, 'Composite type ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_composite( schema, type, description ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'c', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_composite( type, description ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'c', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_composite( type ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_composite( $1, 'Composite type ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c WHERE c.relname = $1 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- relation_owner_is ( schema, relation, user, description ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner($1, $2); BEGIN -- Make sure the relation exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- relation_owner_is ( schema, relation, user ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT relation_owner_is( $1, $2, $3, 'Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- relation_owner_is ( relation, user, description ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner($1); BEGIN -- Make sure the relation exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Relation ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- relation_owner_is ( relation, user ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT relation_owner_is( $1, $2, 'Relation ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = $1 AND n.nspname = $2 AND c.relname = $3 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c WHERE c.relkind = $1 AND c.relname = $2 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- table_owner_is ( schema, table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('r'::char, $1, $2); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- table_owner_is ( schema, table, user ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT table_owner_is( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- table_owner_is ( table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('r'::char, $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- table_owner_is ( table, user ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT table_owner_is( $1, $2, 'Table ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- view_owner_is ( schema, view, user, description ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('v'::char, $1, $2); BEGIN -- Make sure the view exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' View ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- view_owner_is ( schema, view, user ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT view_owner_is( $1, $2, $3, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- view_owner_is ( view, user, description ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('v'::char, $1); BEGIN -- Make sure the view exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' View ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- view_owner_is ( view, user ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT view_owner_is( $1, $2, 'View ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- sequence_owner_is ( schema, sequence, user, description ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('S'::char, $1, $2); BEGIN -- Make sure the sequence exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- sequence_owner_is ( schema, sequence, user ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT sequence_owner_is( $1, $2, $3, 'Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- sequence_owner_is ( sequence, user, description ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('S'::char, $1); BEGIN -- Make sure the sequence exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Sequence ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- sequence_owner_is ( sequence, user ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT sequence_owner_is( $1, $2, 'Sequence ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- composite_owner_is ( schema, composite, user, description ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('c'::char, $1, $2); BEGIN -- Make sure the composite exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Composite type ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- composite_owner_is ( schema, composite, user ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT composite_owner_is( $1, $2, $3, 'Composite type ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- composite_owner_is ( composite, user, description ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('c'::char, $1); BEGIN -- Make sure the composite exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Composite type ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- composite_owner_is ( composite, user ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT composite_owner_is( $1, $2, 'Composite type ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- foreign_table_owner_is ( schema, table, user, description ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('f'::char, $1, $2); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- foreign_table_owner_is ( schema, table, user ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT foreign_table_owner_is( $1, $2, $3, 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- foreign_table_owner_is ( table, user, description ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('f'::char, $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Foreign table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- foreign_table_owner_is ( table, user ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT foreign_table_owner_is( $1, $2, 'Foreign table ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _relexists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _relexists ( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 ); $$ LANGUAGE SQL; -- has_relation( schema, relation, description ) CREATE OR REPLACE FUNCTION has_relation ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _relexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_relation( relation, description ) CREATE OR REPLACE FUNCTION has_relation ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _relexists( $1 ), $2 ); $$ LANGUAGE SQL; -- has_relation( relation ) CREATE OR REPLACE FUNCTION has_relation ( NAME ) RETURNS TEXT AS $$ SELECT has_relation( $1, 'Relation ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_relation( schema, relation, description ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _relexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_relation( relation, description ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _relexists( $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_relation( relation ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_relation( $1, 'Relation ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; DROP VIEW tap_funky; CREATE VIEW tap_funky AS SELECT p.oid AS oid, n.nspname AS schema, p.proname AS name, pg_catalog.pg_get_userbyid(p.proowner) AS owner, array_to_string(p.proargtypes::regtype[], ',') AS args, CASE p.proretset WHEN TRUE THEN 'setof ' ELSE '' END || p.prorettype::regtype AS returns, p.prolang AS langoid, p.proisstrict AS is_strict, p.proisagg AS is_agg, p.prosecdef AS is_definer, p.proretset AS returns_set, p.provolatile::char AS volatility, pg_catalog.pg_function_is_visible(p.oid) AS is_visible FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid ; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE schema = $1 AND name = $2 AND args = array_to_string($3, ',') $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE name = $1 AND args = array_to_string($2, ',') AND is_visible $$ LANGUAGE SQL; -- function_owner_is( schema, function, args[], user, description ) CREATE OR REPLACE FUNCTION function_owner_is ( NAME, NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_func_owner($1, $2, $3); BEGIN -- Make sure the function exists. IF owner IS NULL THEN RETURN ok(FALSE, $5) || E'\n' || diag( E' Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') does not exist' ); END IF; RETURN is(owner, $4, $5); END; $$ LANGUAGE plpgsql; -- function_owner_is( schema, function, args[], user ) CREATE OR REPLACE FUNCTION function_owner_is( NAME, NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_owner_is( $1, $2, $3, $4, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be owned by ' || quote_ident($4) ); $$ LANGUAGE sql; -- function_owner_is( function, args[], user, description ) CREATE OR REPLACE FUNCTION function_owner_is ( NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_func_owner($1, $2); BEGIN -- Make sure the function exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- function_owner_is( function, args[], user ) CREATE OR REPLACE FUNCTION function_owner_is( NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_owner_is( $1, $2, $3, 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_latest ( text ) RETURNS integer[] AS $$ DECLARE ret integer[]; BEGIN EXECUTE 'SELECT ARRAY[ id, value] FROM __tcache__ WHERE label = ' || quote_literal($1) || ' AND id = (SELECT MAX(id) FROM __tcache__ WHERE label = ' || quote_literal($1) || ') LIMIT 1' INTO ret; RETURN ret; EXCEPTION WHEN undefined_table THEN RAISE EXCEPTION 'You tried to run a test without a plan! Gotta have a plan'; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _trig ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND t.tgname = $3 AND NOT t.tgisinternal ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _trig ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid WHERE c.relname = $1 AND t.tgname = $2 AND NOT t.tgisinternal ); $$ LANGUAGE SQL; -- triggers_are( schema, table, triggers[], description ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'triggers', ARRAY( SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND NOT t.tgisinternal EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND NOT t.tgisinternal ), $4 ); $$ LANGUAGE SQL; -- triggers_are( table, triggers[], description ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'triggers', ARRAY( SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND NOT t.tgisinternal EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND NOT t.tgisinternal ), $3 ); $$ LANGUAGE SQL; -- results_eq( cursor, cursor, description ) CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor, text ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; have_rec RECORD; want_rec RECORD; have_found BOOLEAN; want_found BOOLEAN; rownum INTEGER := 1; BEGIN FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN RETURN ok( false, $3 ) || E'\n' || diag( ' Results differ beginning at row ' || rownum || E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END ); END IF; rownum = rownum + 1; FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; END LOOP; RETURN ok( true, $3 ); EXCEPTION WHEN datatype_mismatch THEN RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END END ); END; $$ LANGUAGE plpgsql; -- isnt_empty( sql, description ) CREATE OR REPLACE FUNCTION isnt_empty( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE res BOOLEAN := FALSE; rec RECORD; BEGIN -- Find extra records. FOR rec in EXECUTE _query($1) LOOP res := TRUE; EXIT; END LOOP; RETURN ok(res, $2); END; $$ LANGUAGE plpgsql; -- isnt_empty( sql ) CREATE OR REPLACE FUNCTION isnt_empty( TEXT ) RETURNS TEXT AS $$ SELECT isnt_empty( $1, NULL ); $$ LANGUAGE sql; DROP FUNCTION _ikeys( NAME, NAME, NAME ); DROP FUNCTION _ikeys( NAME, NAME ); DROP FUNCTION _iexpr( NAME, NAME, NAME ); DROP FUNCTION _iexpr( NAME, NAME ); CREATE OR REPLACE FUNCTION _ikeys( NAME, NAME, NAME) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT pg_catalog.pg_get_indexdef( ci.oid, s.i + 1, false) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace JOIN generate_series(0, current_setting('max_index_keys')::int - 1) s(i) ON x.indkey[s.i] IS NOT NULL WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 ORDER BY s.i ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _ikeys( NAME, NAME) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT pg_catalog.pg_get_indexdef( ci.oid, s.i + 1, false) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN generate_series(0, current_setting('max_index_keys')::int - 1) s(i) ON x.indkey[s.i] IS NOT NULL WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) ORDER BY s.i ); $$ LANGUAGE sql; -- has_index( schema, table, index, columns[], description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME[], text ) RETURNS TEXT AS $$ DECLARE index_cols name[]; BEGIN index_cols := _ikeys($1, $2, $3 ); IF index_cols IS NULL OR index_cols = '{}'::name[] THEN RETURN ok( false, $5 ) || E'\n' || diag( 'Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' not found'); END IF; RETURN is( quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( index_cols, ', ' ) || ')', quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( $4, ', ' ) || ')', $5 ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT has_index( $1, $2, $3, ARRAY[$4], $5 ); $$ LANGUAGE sql; -- has_index( table, index, columns[], description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME[], text ) RETURNS TEXT AS $$ DECLARE index_cols name[]; BEGIN index_cols := _ikeys($1, $2 ); IF index_cols IS NULL OR index_cols = '{}'::name[] THEN RETURN ok( false, $4 ) || E'\n' || diag( 'Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' not found'); END IF; RETURN is( quote_ident($2) || ' ON ' || quote_ident($1) || '(' || array_to_string( index_cols, ', ' ) || ')', quote_ident($2) || ' ON ' || quote_ident($1) || '(' || array_to_string( $3, ', ' ) || ')', $4 ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT CASE WHEN _is_schema( $1 ) THEN -- Looking for schema.table index. ok ( _have_index( $1, $2, $3 ), $4) ELSE -- Looking for particular columns. has_index( $1, $2, ARRAY[$3], $4 ) END; $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _assets_are ( text, text[], text[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( $1, ARRAY( SELECT UPPER($2[i]) AS thing FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ORDER BY thing ), ARRAY( SELECT $3[i] AS thing FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT UPPER($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) ORDER BY thing ), $4 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_table_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := _table_privs(); grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_table_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid table name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _table_privs() RETURNS NAME[] AS $$ DECLARE pgversion INTEGER := pg_version_num(); BEGIN IF pgversion < 80200 THEN RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'RULE', 'SELECT', 'TRIGGER', 'UPDATE' ]; ELSIF pgversion < 80400 THEN RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'SELECT', 'TRIGGER', 'UPDATE' ]; ELSE RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'SELECT', 'TRIGGER', 'TRUNCATE', 'UPDATE' ]; END IF; END; $$ language plpgsql; -- table_privs_are ( schema, table, user, privileges[], description ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_table_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- table_privs_are ( schema, table, user, privileges[] ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT table_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on table ' || quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- table_privs_are ( table, user, privileges[], description ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_table_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- table_privs_are ( table, user, privileges[] ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT table_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on table ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _db_privs() RETURNS NAME[] AS $$ DECLARE pgversion INTEGER := pg_version_num(); BEGIN IF pgversion < 80200 THEN RETURN ARRAY['CREATE', 'TEMPORARY']; ELSE RETURN ARRAY['CREATE', 'CONNECT', 'TEMPORARY']; END IF; END; $$ language plpgsql; CREATE OR REPLACE FUNCTION _get_db_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := _db_privs(); grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_database_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN invalid_catalog_name THEN -- Not a valid db name. RETURN '{invalid_catalog_name}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- database_privs_are ( db, user, privileges[], description ) CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_db_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'invalid_catalog_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Database ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- database_privs_are ( db, user, privileges[] ) CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT database_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on database ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_privs(NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_function_privilege($1, $2, 'EXECUTE') THEN RETURN '{EXECUTE}'; ELSE RETURN '{}'; END IF; EXCEPTION -- Not a valid func name. WHEN undefined_function THEN RETURN '{undefined_function}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _fprivs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_func_privs($2, $1); BEGIN IF grants[1] = 'undefined_function' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Function ' || $1 || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- function_privs_are ( schema, function, args[], user, privileges[], description ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _fprivs_are( quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ')', $4, $5, $6 ); $$ LANGUAGE SQL; -- function_privs_are ( schema, function, args[], user, privileges[] ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME, NAME[], NAME, NAME[] ) RETURNS TEXT AS $$ SELECT function_privs_are( $1, $2, $3, $4, $5, 'Role ' || quote_ident($4) || ' should be granted ' || CASE WHEN $5[1] IS NULL THEN 'no privileges' ELSE array_to_string($5, ', ') END || ' on function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ')' ); $$ LANGUAGE SQL; -- function_privs_are ( function, args[], user, privileges[], description ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _fprivs_are( quote_ident($1) || '(' || array_to_string($2, ', ') || ')', $3, $4, $5 ); $$ LANGUAGE SQL; -- function_privs_are ( function, args[], user, privileges[] ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME[], NAME, NAME[] ) RETURNS TEXT AS $$ SELECT function_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ')' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_lang_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_language_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or language. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_language}' END; END; $$ LANGUAGE plpgsql; -- language_privs_are ( lang, user, privileges[], description ) CREATE OR REPLACE FUNCTION language_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_lang_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_language' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Language ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- language_privs_are ( lang, user, privileges[] ) CREATE OR REPLACE FUNCTION language_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT language_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on language ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_schema_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['CREATE', 'USAGE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP IF pg_catalog.has_schema_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; END LOOP; RETURN grants; EXCEPTION -- Not a valid schema name. WHEN invalid_schema_name THEN RETURN '{invalid_schema_name}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; -- schema_privs_are ( schema, user, privileges[], description ) CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_schema_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'invalid_schema_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Schema ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- schema_privs_are ( schema, user, privileges[] ) CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT schema_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on schema ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_tablespaceprivs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_tablespace_privilege($1, $2, 'CREATE') THEN RETURN '{CREATE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or tablespace. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_tablespace}' END; END; $$ LANGUAGE plpgsql; -- tablespace_privs_are ( tablespace, user, privileges[], description ) CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_tablespaceprivs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_tablespace' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Tablespace ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- tablespace_privs_are ( tablespace, user, privileges[] ) CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT tablespace_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on tablespace ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_sequence_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['SELECT', 'UPDATE', 'USAGE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_sequence_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid sequence name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( schema, sequence, user, privileges[], description ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_sequence_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( schema, sequence, user, privileges[] ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT sequence_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on sequence '|| quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- sequence_privs_are ( sequence, user, privileges[], description ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_sequence_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( sequence, user, privileges[] ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT sequence_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on sequence ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_ac_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_any_column_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid table name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( schema, table, user, privileges[], description ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_ac_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( schema, table, user, privileges[] ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT any_column_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on any column in '|| quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- any_column_privs_are ( table, user, privileges[], description ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_ac_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( table, user, privileges[] ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT any_column_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on any column in ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_privs(NAME, TEXT, NAME) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP IF pg_catalog.has_column_privilege($1, $2, $3, privs[i]) THEN grants := grants || privs[i]; END IF; END LOOP; RETURN grants; EXCEPTION -- Not a valid column name. WHEN undefined_column THEN RETURN '{undefined_column}'; -- Not a valid table name. WHEN undefined_table THEN RETURN '{undefined_table}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; -- column_privs_are ( schema, table, column, user, privileges[], description ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_col_privs( $4, quote_ident($1) || '.' || quote_ident($2), $3 ); BEGIN IF grants[1] = 'undefined_column' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); ELSIF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Role ' || quote_ident($4) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $5, $6); END; $$ LANGUAGE plpgsql; -- column_privs_are ( schema, table, column, user, privileges[] ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT column_privs_are( $1, $2, $3, $4, $5, 'Role ' || quote_ident($4) || ' should be granted ' || CASE WHEN $5[1] IS NULL THEN 'no privileges' ELSE array_to_string($5, ', ') END || ' on column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) ); $$ LANGUAGE SQL; -- column_privs_are ( table, column, user, privileges[], description ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_col_privs( $3, quote_ident($1), $2 ); BEGIN IF grants[1] = 'undefined_column' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- column_privs_are ( table, column, user, privileges[] ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT column_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on column ' || quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_fdw_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_foreign_data_wrapper_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or fdw. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_fdw}' END; END; $$ LANGUAGE plpgsql; -- fdw_privs_are ( fdw, user, privileges[], description ) CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_fdw_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_fdw' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' FDW ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- fdw_privs_are ( fdw, user, privileges[] ) CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT fdw_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on FDW ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_schema_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['CREATE', 'USAGE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP IF pg_catalog.has_schema_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; END LOOP; RETURN grants; EXCEPTION -- Not a valid schema name. WHEN invalid_schema_name THEN RETURN '{invalid_schema_name}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _get_server_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_server_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or server. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_server}' END; END; $$ LANGUAGE plpgsql; -- server_privs_are ( server, user, privileges[], description ) CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_server_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_server' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Server ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- server_privs_are ( server, user, privileges[] ) CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT server_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on server ' || quote_ident($1) ); $$ LANGUAGE SQL; pgtap-1.3.2/sql/pgtap--0.92.0--0.93.0.sql000066400000000000000000000506711455775703000167140ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.93;' LANGUAGE SQL IMMUTABLE; -- _get_schema_owner( schema ) CREATE OR REPLACE FUNCTION _get_schema_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(nspowner) FROM pg_catalog.pg_namespace WHERE nspname = $1; $$ LANGUAGE SQL; -- schema_owner_is ( schema, user, description ) CREATE OR REPLACE FUNCTION schema_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_schema_owner($1); BEGIN -- Make sure the schema exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Schema ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- schema_owner_is ( schema, user ) CREATE OR REPLACE FUNCTION schema_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT schema_owner_is( $1, $2, 'Schema ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _constraint ( NAME, NAME, CHAR, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE akey NAME[]; keys TEXT[] := '{}'; have TEXT; BEGIN FOR akey IN SELECT * FROM _keys($1, $2, $3) LOOP IF akey = $4 THEN RETURN pass($5); END IF; keys = keys || akey::text; END LOOP; IF array_upper(keys, 0) = 1 THEN have := 'No ' || $6 || ' constraints'; ELSE have := array_to_string(keys, E'\n '); END IF; RETURN fail($5) || E'\n' || diag( ' have: ' || have || E'\n want: ' || CASE WHEN $4 IS NULL THEN 'NULL' ELSE $4::text END ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _constraint ( NAME, CHAR, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE akey NAME[]; keys TEXT[] := '{}'; have TEXT; BEGIN FOR akey IN SELECT * FROM _keys($1, $2) LOOP IF akey = $3 THEN RETURN pass($4); END IF; keys = keys || akey::text; END LOOP; IF array_upper(keys, 0) = 1 THEN have := 'No ' || $5 || ' constraints'; ELSE have := array_to_string(keys, E'\n '); END IF; RETURN fail($4) || E'\n' || diag( ' have: ' || have || E'\n want: ' || CASE WHEN $3 IS NULL THEN 'NULL' ELSE $3::text END ); END; $$ LANGUAGE plpgsql; -- fk_ok( fk_table, fk_column[], pk_table, pk_column[], description ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE tab name; cols name[]; BEGIN SELECT pk_table_name, pk_columns FROM pg_all_foreign_keys WHERE fk_table_name = $1 AND fk_columns = $2 AND pg_catalog.pg_table_is_visible(fk_table_oid) INTO tab, cols; RETURN is( -- have $1 || '(' || _ident_array_to_string( $2, ', ' ) || ') REFERENCES ' || COALESCE( tab || '(' || _ident_array_to_string( cols, ', ' ) || ')', 'NOTHING'), -- want $1 || '(' || _ident_array_to_string( $2, ', ' ) || ') REFERENCES ' || $3 || '(' || _ident_array_to_string( $4, ', ' ) || ')', $5 ); END; $$ LANGUAGE plpgsql; -- _keys( table, constraint_type ) CREATE OR REPLACE FUNCTION _keys ( NAME, CHAR ) RETURNS SETOF NAME[] AS $$ SELECT _pg_sv_column_array(x.conrelid,x.conkey) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid AND c.relname = $1 AND x.contype = $2 WHERE pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _trig ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid WHERE c.relname = $1 AND t.tgname = $2 AND pg_catalog.pg_table_is_visible(c.oid) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _fkexists ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM pg_all_foreign_keys WHERE quote_ident(fk_table_name) = quote_ident($1) AND pg_catalog.pg_table_is_visible(fk_table_oid) AND fk_columns = $2 ); $$ LANGUAGE SQL; DROP FUNCTION display_type ( OID, INTEGER ); DROP FUNCTION display_type ( NAME, OID, INTEGER ); CREATE OR REPLACE FUNCTION _get_col_type ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attname = $3 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_type ( NAME, NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON a.attrelid = c.oid WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attname = $2 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_ns_type ( NAME, NAME, NAME ) RETURNS TEXT AS $$ -- Always include the namespace. SELECT CASE WHEN pg_catalog.pg_type_is_visible(t.oid) THEN quote_ident(tn.nspname) || '.' ELSE '' END || pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid JOIN pg_catalog.pg_type t ON a.atttypid = t.oid JOIN pg_catalog.pg_namespace tn ON t.typnamespace = tn.oid WHERE n.nspname = $1 AND c.relname = $2 AND a.attname = $3 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; -- _cdi( schema, table, column, default, description ) CREATE OR REPLACE FUNCTION _cdi ( NAME, NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( $5 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; IF NOT _has_def( $1, $2, $3 ) THEN RETURN fail( $5 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' has no default' ); END IF; RETURN _def_is( pg_catalog.pg_get_expr(d.adbin, d.adrelid), pg_catalog.format_type(a.atttypid, a.atttypmod), $4, $5 ) FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c, pg_catalog.pg_attribute a, pg_catalog.pg_attrdef d WHERE n.oid = c.relnamespace AND c.oid = a.attrelid AND a.atthasdef AND a.attrelid = d.adrelid AND a.attnum = d.adnum AND n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3; END; $$ LANGUAGE plpgsql; -- _cdi( table, column, default, description ) CREATE OR REPLACE FUNCTION _cdi ( NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; IF NOT _has_def( $1, $2 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' has no default' ); END IF; RETURN _def_is( pg_catalog.pg_get_expr(d.adbin, d.adrelid), pg_catalog.format_type(a.atttypid, a.atttypmod), $3, $4 ) FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a, pg_catalog.pg_attrdef d WHERE c.oid = a.attrelid AND pg_table_is_visible(c.oid) AND a.atthasdef AND a.attrelid = d.adrelid AND a.attnum = d.adnum AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _cmp_types(oid, name) RETURNS BOOLEAN AS $$ DECLARE dtype TEXT := pg_catalog.format_type($1, NULL); BEGIN RETURN dtype = _quote_ident_like($2, dtype); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _get_dtype( NAME, TEXT, BOOLEAN ) RETURNS TEXT AS $$ SELECT CASE WHEN $3 AND pg_catalog.pg_type_is_visible(t.oid) THEN quote_ident(tn.nspname) || '.' ELSE '' END || pg_catalog.format_type(t.oid, t.typtypmod) FROM pg_catalog.pg_type d JOIN pg_catalog.pg_namespace dn ON d.typnamespace = dn.oid JOIN pg_catalog.pg_type t ON d.typbasetype = t.oid JOIN pg_catalog.pg_namespace tn ON t.typnamespace = tn.oid WHERE d.typisdefined AND dn.nspname = $1 AND d.typname = LOWER($2) AND d.typtype = 'd' $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_dtype( NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(t.oid, t.typtypmod) FROM pg_catalog.pg_type d JOIN pg_catalog.pg_type t ON d.typbasetype = t.oid WHERE d.typisdefined AND pg_catalog.pg_type_is_visible(d.oid) AND d.typname = LOWER($1) AND d.typtype = 'd' $$ LANGUAGE sql; -- casts_are( casts[], description ) CREATE OR REPLACE FUNCTION casts_are ( TEXT[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( 'casts', ARRAY( SELECT pg_catalog.format_type(castsource, NULL) || ' AS ' || pg_catalog.format_type(casttarget, NULL) FROM pg_catalog.pg_cast c EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT pg_catalog.format_type(castsource, NULL) || ' AS ' || pg_catalog.format_type(casttarget, NULL) FROM pg_catalog.pg_cast c ), $2 ); $$ LANGUAGE sql; -- _get_tablespace_owner( tablespace ) CREATE OR REPLACE FUNCTION _get_tablespace_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(spcowner) FROM pg_catalog.pg_tablespace WHERE spcname = $1; $$ LANGUAGE SQL; -- tablespace_owner_is ( tablespace, user, description ) CREATE OR REPLACE FUNCTION tablespace_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_tablespace_owner($1); BEGIN -- Make sure the tablespace exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Tablespace ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- tablespace_owner_is ( tablespace, user ) CREATE OR REPLACE FUNCTION tablespace_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT tablespace_owner_is( $1, $2, 'Tablespace ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _have_index( NAME, NAME, NAME) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE n.nspname = $1 AND ct.relname = $2 AND ci.relname = $3 ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _have_index( NAME, NAME) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_index_owner( NAME, NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(ci.relowner) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE n.nspname = $1 AND ct.relname = $2 AND ci.relname = $3; $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_index_owner( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(ci.relowner) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid); $$ LANGUAGE sql; -- index_owner_is ( schema, table, index, user, description ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_index_owner($1, $2, $3); BEGIN -- Make sure the index exists. IF owner IS NULL THEN RETURN ok(FALSE, $5) || E'\n' || diag( E' Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $4, $5); END; $$ LANGUAGE plpgsql; -- index_owner_is ( schema, table, index, user ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_owner_is( $1, $2, $3, $4, 'Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($4) ); $$ LANGUAGE sql; -- index_owner_is ( table, index, user, description ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_index_owner($1, $2); BEGIN -- Make sure the index exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- index_owner_is ( table, index, user ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_owner_is( $1, $2, $3, 'Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- _get_language_owner( language ) CREATE OR REPLACE FUNCTION _get_language_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(lanowner) FROM pg_catalog.pg_language WHERE lanname = $1; $$ LANGUAGE SQL; -- language_owner_is ( language, user, description ) CREATE OR REPLACE FUNCTION language_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_language_owner($1); BEGIN -- Make sure the language exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Language ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- language_owner_is ( language, user ) CREATE OR REPLACE FUNCTION language_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT language_owner_is( $1, $2, 'Language ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_opclass_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(opcowner) FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 AND opcname = $2; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_opclass_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(opcowner) FROM pg_catalog.pg_opclass WHERE opcname = $1 AND pg_catalog.pg_opclass_is_visible(oid); $$ LANGUAGE SQL; -- opclass_owner_is( schema, opclass, user, description ) CREATE OR REPLACE FUNCTION opclass_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_opclass_owner($1, $2); BEGIN -- Make sure the opclass exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- opclass_owner_is( schema, opclass, user ) CREATE OR REPLACE FUNCTION opclass_owner_is( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT opclass_owner_is( $1, $2, $3, 'Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- opclass_owner_is( opclass, user, description ) CREATE OR REPLACE FUNCTION opclass_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_opclass_owner($1); BEGIN -- Make sure the opclass exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Operator class ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- opclass_owner_is( opclass, user ) CREATE OR REPLACE FUNCTION opclass_owner_is( NAME, NAME ) RETURNS TEXT AS $$ SELECT opclass_owner_is( $1, $2, 'Operator class ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _opc_exists( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 AND oc.opcname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _opc_exists( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_opclass oc WHERE oc.opcname = $1 AND pg_opclass_is_visible(oid) ); $$ LANGUAGE SQL; -- has_opclass( name, description ) CREATE OR REPLACE FUNCTION has_opclass( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1 ), $2) $$ LANGUAGE SQL; -- has_opclass( name ) CREATE OR REPLACE FUNCTION has_opclass( NAME ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1 ), 'Operator class ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_opclass( name, description ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1 ), $2) $$ LANGUAGE SQL; -- hasnt_opclass( name ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1 ), 'Operator class ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_type_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(t.typowner) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = $1 AND t.typname = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_type_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(typowner) FROM pg_catalog.pg_type WHERE typname = $1 AND pg_catalog.pg_type_is_visible(oid) $$ LANGUAGE SQL; -- type_owner_is ( schema, type, user, description ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_type_owner($1, $2); BEGIN -- Make sure the type exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Type ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- type_owner_is ( schema, type, user ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT type_owner_is( $1, $2, $3, 'Type ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- type_owner_is ( type, user, description ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_type_owner($1); BEGIN -- Make sure the type exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Type ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- type_owner_is ( type, user ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT type_owner_is( $1, $2, 'Type ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; pgtap-1.3.2/sql/pgtap--0.93.0--0.94.0.sql000066400000000000000000000126001455775703000167040ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.94;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _get_func_privs(TEXT, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_function_privilege($1, $2, 'EXECUTE') THEN RETURN '{EXECUTE}'; ELSE RETURN '{}'; END IF; EXCEPTION -- Not a valid func name. WHEN undefined_function THEN RETURN '{undefined_function}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _fprivs_are ( TEXT, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_func_privs($2, $1); BEGIN IF grants[1] = 'undefined_function' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Function ' || $1 || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- has_table( schema, table ) CREATE OR REPLACE FUNCTION has_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'r', $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_table( schema, table ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'r', $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- has_foreign_table( schema, table ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1, $2 ), 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_foreign_table( schema, table ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1, $2 ), 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' not should exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION skip ( why text, how_many int ) RETURNS TEXT AS $$ DECLARE output TEXT[]; BEGIN output := '{}'; FOR i IN 1..how_many LOOP output = array_append( output, ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE( ' ' || why, '') ) ); END LOOP; RETURN array_to_string(output, E'\n'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION skip ( text ) RETURNS TEXT AS $$ SELECT ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE(' ' || $1, '') ); $$ LANGUAGE sql; -- check_test( test_output, pass, name, description, diag, match_diag ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN ) RETURNS SETOF TEXT AS $$ DECLARE tnumb INTEGER; aok BOOLEAN; adescr TEXT; res BOOLEAN; descr TEXT; adiag TEXT; have ALIAS FOR $1; eok ALIAS FOR $2; name ALIAS FOR $3; edescr ALIAS FOR $4; ediag ALIAS FOR $5; matchit ALIAS FOR $6; BEGIN -- What test was it that just ran? tnumb := currval('__tresults___numb_seq'); -- Fetch the results. EXECUTE 'SELECT aok, descr FROM __tresults__ WHERE numb = ' || tnumb INTO aok, adescr; -- Now delete those results. EXECUTE 'DELETE FROM __tresults__ WHERE numb = ' || tnumb; EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb; -- Set up the description. descr := coalesce( name || ' ', 'Test ' ) || 'should '; -- So, did the test pass? RETURN NEXT is( aok, eok, descr || CASE eok WHEN true then 'pass' ELSE 'fail' END ); -- Was the description as expected? IF edescr IS NOT NULL THEN RETURN NEXT is( adescr, edescr, descr || 'have the proper description' ); END IF; -- Were the diagnostics as expected? IF ediag IS NOT NULL THEN -- Remove ok and the test number. adiag := substring( have FROM CASE WHEN aok THEN 4 ELSE 9 END + char_length(tnumb::text) ); -- Remove the description, if there is one. IF adescr <> '' THEN adiag := substring( adiag FROM 1 + char_length( ' - ' || substr(diag( adescr ), 3) ) ); END IF; IF NOT aok THEN -- Remove failure message from ok(). adiag := substring(adiag FROM 1 + char_length(diag( 'Failed test ' || tnumb || CASE adescr WHEN '' THEN '' ELSE COALESCE(': "' || adescr || '"', '') END ))); END IF; IF ediag <> '' THEN -- Remove the space before the diagnostics. adiag := substring(adiag FROM 2); END IF; -- Remove the #s. adiag := replace( substring(adiag from 3), E'\n# ', E'\n' ); -- Now compare the diagnostics. IF matchit THEN RETURN NEXT matches( adiag, ediag, descr || 'have the proper diagnostics' ); ELSE RETURN NEXT is( adiag, ediag, descr || 'have the proper diagnostics' ); END IF; END IF; -- And we're done RETURN; END; $$ LANGUAGE plpgsql; pgtap-1.3.2/sql/pgtap--0.94.0--0.95.0.sql000066400000000000000000000507421455775703000167170ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.95;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION plan( integer ) RETURNS TEXT AS $$ DECLARE rcount INTEGER; BEGIN BEGIN EXECUTE ' CREATE TEMP SEQUENCE __tcache___id_seq; CREATE TEMP TABLE __tcache__ ( id INTEGER NOT NULL DEFAULT nextval(''__tcache___id_seq''), label TEXT NOT NULL, value INTEGER NOT NULL, note TEXT NOT NULL DEFAULT '''' ); CREATE UNIQUE INDEX __tcache___key ON __tcache__(id); GRANT ALL ON TABLE __tcache__ TO PUBLIC; GRANT ALL ON TABLE __tcache___id_seq TO PUBLIC; CREATE TEMP SEQUENCE __tresults___numb_seq; GRANT ALL ON TABLE __tresults___numb_seq TO PUBLIC; '; EXCEPTION WHEN duplicate_table THEN -- Raise an exception if there's already a plan. EXECUTE 'SELECT TRUE FROM __tcache__ WHERE label = ''plan'''; GET DIAGNOSTICS rcount = ROW_COUNT; IF rcount > 0 THEN RAISE EXCEPTION 'You tried to plan twice!'; END IF; END; -- Save the plan and return. PERFORM _set('plan', $1 ); PERFORM _set('failed', 0 ); RETURN '1..' || $1; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION add_result ( bool, bool, text, text, text ) RETURNS integer AS $$ BEGIN IF NOT $1 THEN PERFORM _set('failed', _get('failed') + 1); END IF; RETURN nextval('__tresults___numb_seq'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION num_failed () RETURNS INTEGER AS $$ SELECT _get('failed'); $$ LANGUAGE SQL strict; CREATE OR REPLACE FUNCTION _finish (INTEGER, INTEGER, INTEGER) RETURNS SETOF TEXT AS $$ DECLARE curr_test ALIAS FOR $1; exp_tests INTEGER := $2; num_faild ALIAS FOR $3; plural CHAR; BEGIN plural := CASE exp_tests WHEN 1 THEN '' ELSE 's' END; IF curr_test IS NULL THEN RAISE EXCEPTION '# No tests run!'; END IF; IF exp_tests = 0 OR exp_tests IS NULL THEN -- No plan. Output one now. exp_tests = curr_test; RETURN NEXT '1..' || exp_tests; END IF; IF curr_test <> exp_tests THEN RETURN NEXT diag( 'Looks like you planned ' || exp_tests || ' test' || plural || ' but ran ' || curr_test ); ELSIF num_faild > 0 THEN RETURN NEXT diag( 'Looks like you failed ' || num_faild || ' test' || CASE num_faild WHEN 1 THEN '' ELSE 's' END || ' of ' || exp_tests ); ELSE END IF; RETURN; END; $$ LANGUAGE plpgsql; -- is_member_of( role, members[], description ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE missing text[]; BEGIN IF NOT _has_role($1) THEN RETURN fail( $3 ) || E'\n' || diag ( ' Role ' || quote_ident($1) || ' does not exist' ); END IF; SELECT ARRAY( SELECT quote_ident($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) LEFT JOIN pg_catalog.pg_roles r ON rolname = $2[i] WHERE r.oid IS NULL OR NOT r.oid = ANY ( _grolist($1) ) ORDER BY s.i ) INTO missing; IF missing[1] IS NULL THEN RETURN ok( true, $3 ); END IF; RETURN ok( false, $3 ) || E'\n' || diag( ' Members missing from the ' || quote_ident($1) || E' role:\n ' || array_to_string( missing, E'\n ') ); END; $$ LANGUAGE plpgsql; -- is_member_of( role, members[] ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT is_member_of( $1, $2, 'Should have members of role ' || quote_ident($1) ); $$ LANGUAGE SQL; -- foreign_tables_are( schema, tables, description ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2), $3); $$ LANGUAGE SQL; -- materialized_views_are( schema, materialized_views, description ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2), $3); $$ LANGUAGE SQL; -- materialized_views_are( materialized_views, description ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1), _missing('m', $1), $2); $$ LANGUAGE SQL; -- materialized_views_are( schema, materialized_views ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct materialized views' ); $$ LANGUAGE SQL; -- materialized_views_are( materialized_views ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1), _missing('m', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views' ); $$ LANGUAGE SQL; -- materialized_view_owner_is ( schema, materialized_view, user, description ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('m'::char, $1, $2); BEGIN -- Make sure the materialized view exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- materialized_view_owner_is ( schema, materialized_view, user ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT materialized_view_owner_is( $1, $2, $3, 'Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- materialized_view_owner_is ( materialized_view, user, description ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('m'::char, $1); BEGIN -- Make sure the materialized view exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Materialized view ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- materialized_view_owner_is ( materialized_view, user ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT materialized_view_owner_is( $1, $2, 'Materialized view ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- has_materialized_view( schema, materialized_view, description ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'm', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_materialized_view( materialized_view, description ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'm', $1 ), $2 ); $$ LANGUAGE SQL; -- has_materialized_view( materialized_view ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME ) RETURNS TEXT AS $$ SELECT has_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_materialized_view( schema, materialized_view, description ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'm', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_materialized_view( materialized_view, description ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'm', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_materialized_view( materialized_view ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- foreign_tables_are( tables, description ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1), _missing('f', $1), $2); $$ LANGUAGE SQL; -- foreign_tables_are( schema, tables ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct foreign tables' ); $$ LANGUAGE SQL; -- foreign_tables_are( tables ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1), _missing('f', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _fix_enum_has_labels( ) RETURNS VOID LANGUAGE PLPGSQL AS $FIX$ BEGIN IF pg_version_num() < 90100 THEN RETURN; END IF; EXECUTE $RUN$ -- enum_has_labels( schema, enum, labels, description ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( ARRAY( SELECT e.enumlabel FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.typisdefined AND n.nspname = $1 AND t.typname = $2 AND t.typtype = 'e' ORDER BY e.enumsortorder ), $3, $4 ); $$ LANGUAGE sql; -- enum_has_labels( enum, labels, description ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( ARRAY( SELECT e.enumlabel FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid WHERE t.typisdefined AND pg_catalog.pg_type_is_visible(t.oid) AND t.typname = $1 AND t.typtype = 'e' ORDER BY e.enumsortorder ), $2, $3 ); $$ LANGUAGE sql; $RUN$; END; $FIX$; SELECT _fix_enum_has_labels(); DROP FUNCTION _fix_enum_has_labels(); -- isnt_strict( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _strict($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_strict( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_strict( schema, function ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_strict( function, args[] ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( function, description ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _strict($1), $2 ); $$ LANGUAGE sql; -- isnt_strict( function ) CREATE OR REPLACE FUNCTION isnt_strict( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1), 'Function ' || quote_ident($1) || '() should not be strict' ); $$ LANGUAGE sql; -- col_is_unique( schema, table, column[] ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, $3, 'Columns ' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should have a unique constraint' ); $$ LANGUAGE sql; -- col_is_unique( scheam, table, column ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, ARRAY[$3], 'Column ' || quote_ident($2) || '(' || quote_ident($3) || ') should have a unique constraint' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) RETURNS SETOF TEXT AS $$ DECLARE startup ALIAS FOR $1; shutdown ALIAS FOR $2; setup ALIAS FOR $3; teardown ALIAS FOR $4; tests ALIAS FOR $5; tap TEXT; tfaild INTEGER := 0; ffaild INTEGER := 0; tnumb INTEGER := 0; fnumb INTEGER := 0; tok BOOLEAN := TRUE; errmsg TEXT; BEGIN BEGIN -- No plan support. PERFORM * FROM no_plan(); FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; EXCEPTION -- Catch all exceptions and simply rethrow custom exceptions. This -- will roll back everything in the above block. WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; END; -- Record how startup tests have failed. tfaild := num_failed(); FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP -- What subtest are we running? RETURN NEXT ' ' || diag_test_name('Subtest: ' || tests[i]); -- Reset the results. tok := TRUE; tnumb := COALESCE(_get('curr_test'), 0); IF tnumb > 0 THEN EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; PERFORM _set('curr_test', 0); PERFORM _set('failed', 0); END IF; BEGIN BEGIN -- Run the setup functions. FOR tap IN SELECT * FROM _runem(setup, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the actual test function. FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the teardown functions. FOR tap IN SELECT * FROM _runem(teardown, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Emit the plan. fnumb := COALESCE(_get('curr_test'), 0); RETURN NEXT ' 1..' || fnumb; -- Emit any error messages. IF fnumb = 0 THEN RETURN NEXT ' # No tests run!'; tok = false; ELSE -- Report failures. ffaild := num_failed(); IF ffaild > 0 THEN tok := FALSE; RETURN NEXT ' ' || diag( 'Looks like you failed ' || ffaild || ' test' || CASE tfaild WHEN 1 THEN '' ELSE 's' END || ' of ' || fnumb ); END IF; END IF; EXCEPTION WHEN raise_exception THEN -- Something went wrong. Record that fact. errmsg := SQLERRM; END; -- Always raise an exception to rollback any changes. RAISE EXCEPTION '__TAP_ROLLBACK__'; EXCEPTION WHEN raise_exception THEN IF errmsg IS NOT NULL THEN -- Something went wrong. Emit the error message. tok := FALSE; RETURN NEXT ' ' || diag('Test died: ' || errmsg); errmsg := NULL; END IF; END; -- Restore the sequence. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; PERFORM _set('curr_test', tnumb); PERFORM _set('failed', tfaild); -- Record this test. RETURN NEXT ok(tok, tests[i]); IF NOT tok THEN tfaild := tfaild + 1; END IF; END LOOP; -- Run the shutdown functions. FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; -- Finish up. FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP RETURN NEXT tap; END LOOP; -- Clean up and return. PERFORM _cleanup(); RETURN; END; $$ LANGUAGE plpgsql; -- check_test( test_output, pass, name, description, diag, match_diag ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN ) RETURNS SETOF TEXT AS $$ DECLARE tnumb INTEGER; aok BOOLEAN; adescr TEXT; res BOOLEAN; descr TEXT; adiag TEXT; have ALIAS FOR $1; eok ALIAS FOR $2; name ALIAS FOR $3; edescr ALIAS FOR $4; ediag ALIAS FOR $5; matchit ALIAS FOR $6; BEGIN -- What test was it that just ran? tnumb := currval('__tresults___numb_seq'); -- Fetch the results. aok := substring(have, 1, 2) = 'ok'; adescr := COALESCE(substring(have FROM E'(?:not )?ok [[:digit:]]+ - ([^\n]+)'), ''); -- Now delete those results. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb; IF NOT aok THEN PERFORM _set('failed', _get('failed') - 1); END IF; -- Set up the description. descr := coalesce( name || ' ', 'Test ' ) || 'should '; -- So, did the test pass? RETURN NEXT is( aok, eok, descr || CASE eok WHEN true then 'pass' ELSE 'fail' END ); -- Was the description as expected? IF edescr IS NOT NULL THEN RETURN NEXT is( adescr, edescr, descr || 'have the proper description' ); END IF; -- Were the diagnostics as expected? IF ediag IS NOT NULL THEN -- Remove ok and the test number. adiag := substring( have FROM CASE WHEN aok THEN 4 ELSE 9 END + char_length(tnumb::text) ); -- Remove the description, if there is one. IF adescr <> '' THEN adiag := substring( adiag FROM 1 + char_length( ' - ' || substr(diag( adescr ), 3) ) ); END IF; IF NOT aok THEN -- Remove failure message from ok(). adiag := substring(adiag FROM 1 + char_length(diag( 'Failed test ' || tnumb || CASE adescr WHEN '' THEN '' ELSE COALESCE(': "' || adescr || '"', '') END ))); END IF; IF ediag <> '' THEN -- Remove the space before the diagnostics. adiag := substring(adiag FROM 2); END IF; -- Remove the #s. adiag := replace( substring(adiag from 3), E'\n# ', E'\n' ); -- Now compare the diagnostics. IF matchit THEN RETURN NEXT matches( adiag, ediag, descr || 'have the proper diagnostics' ); ELSE RETURN NEXT is( adiag, ediag, descr || 'have the proper diagnostics' ); END IF; END IF; -- And we're done RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _cleanup() RETURNS boolean AS $$ DROP SEQUENCE __tresults___numb_seq; DROP TABLE __tcache__; DROP SEQUENCE __tcache___id_seq; SELECT TRUE; $$ LANGUAGE sql; -- has_sequence( schema, sequence ) CREATE OR REPLACE FUNCTION has_sequence ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'S', $1, $2 ), 'Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; GRANT SELECT ON tap_funky TO PUBLIC; GRANT SELECT ON pg_all_foreign_keys TO PUBLIC; pgtap-1.3.2/sql/pgtap--0.95.0--0.96.0.sql.in000066400000000000000000000331151455775703000173210ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.96;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT, TEXT ) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT DISTINCT quote_ident(n.nspname) || '.' || quote_ident(p.proname) AS pname FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid WHERE n.nspname = $1 AND p.proname ~ $2 AND ($3 IS NULL OR p.proname !~ $3) ORDER BY pname ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT ) RETURNS TEXT[] AS $$ SELECT findfuncs( $1, $2, NULL ) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( TEXT, TEXT ) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT DISTINCT quote_ident(n.nspname) || '.' || quote_ident(p.proname) AS pname FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid WHERE pg_catalog.pg_function_is_visible(p.oid) AND p.proname ~ $1 AND ($2 IS NULL OR p.proname !~ $2) ORDER BY pname ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( TEXT ) RETURNS TEXT[] AS $$ SELECT findfuncs( $1, NULL ) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION runtests( NAME, TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runner( findfuncs( $1, '^startup' ), findfuncs( $1, '^shutdown' ), findfuncs( $1, '^setup' ), findfuncs( $1, '^teardown' ), findfuncs( $1, $2, '^(startup|shutdown|setup|teardown)' ) ); $$ LANGUAGE sql; -- runtests( match ) CREATE OR REPLACE FUNCTION runtests( TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runner( findfuncs( '^startup' ), findfuncs( '^shutdown' ), findfuncs( '^setup' ), findfuncs( '^teardown' ), findfuncs( $1, '^(startup|shutdown|setup|teardown)' ) ); $$ LANGUAGE sql; -- database_privs_are ( db, user, privileges[], description ) CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_db_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'invalid_catalog_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Database ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- schema_privs_are ( schema, user, privileges[], description ) CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_schema_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'invalid_schema_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Schema ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- tablespace_privs_are ( tablespace, user, privileges[], description ) CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_tablespaceprivs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_tablespace' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Tablespace ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_fdw_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_fdw' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' FDW ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- server_privs_are ( server, user, privileges[], description ) CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_server_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_server' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Server ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- Get extensions in a given schema CREATE OR REPLACE FUNCTION _extensions( NAME ) RETURNS SETOF NAME AS $$ SELECT e.extname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_extension e ON n.oid = e.extnamespace WHERE n.nspname = $1 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extensions() RETURNS SETOF NAME AS $$ SELECT extname FROM pg_catalog.pg_extension $$ LANGUAGE SQL; -- extensions_are( schema, extensions, description ) CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'extensions', ARRAY(SELECT _extensions($1) EXCEPT SELECT unnest($2)), ARRAY(SELECT unnest($2) EXCEPT SELECT _extensions($1)), $3 ); $$ LANGUAGE SQL; -- extensions_are( schema, extensions) CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT extensions_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct extensions' ); $$ LANGUAGE SQL; -- extensions_are( extensions, description ) CREATE OR REPLACE FUNCTION extensions_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'extensions', ARRAY(SELECT _extensions() EXCEPT SELECT unnest($1)), ARRAY(SELECT unnest($1) EXCEPT SELECT _extensions()), $2 ); $$ LANGUAGE SQL; -- extensions_are( schema, extensions) CREATE OR REPLACE FUNCTION extensions_are( NAME[] ) RETURNS TEXT AS $$ SELECT extensions_are($1, 'Should have the correct extensions'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _error_diag( sqlstate TEXT DEFAULT NULL, errmsg TEXT DEFAULT NULL, detail TEXT DEFAULT NULL, hint TEXT DEFAULT NULL, context TEXT DEFAULT NULL, schname TEXT DEFAULT NULL, tabname TEXT DEFAULT NULL, colname TEXT DEFAULT NULL, chkname TEXT DEFAULT NULL, typname TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT COALESCE( COALESCE( NULLIF(sqlstate, '') || ': ', '' ) || COALESCE( NULLIF(errmsg, ''), '' ), 'NO ERROR FOUND' ) || COALESCE(E'\n DETAIL: ' || nullif(detail, ''), '') || COALESCE(E'\n HINT: ' || nullif(hint, ''), '') || COALESCE(E'\n SCHEMA: ' || nullif(schname, ''), '') || COALESCE(E'\n TABLE: ' || nullif(tabname, ''), '') || COALESCE(E'\n COLUMN: ' || nullif(colname, ''), '') || COALESCE(E'\n CONSTRAINT: ' || nullif(chkname, ''), '') || COALESCE(E'\n TYPE: ' || nullif(typname, ''), '') -- We need to manually indent all the context lines || COALESCE(E'\n CONTEXT:\n' || regexp_replace(NULLIF( context, ''), '^', ' ', 'gn' ), ''); $$ LANGUAGE sql IMMUTABLE; -- lives_ok( sql, description ) CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE code TEXT := _query($1); descr ALIAS FOR $2; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN EXECUTE code; RETURN ok( TRUE, descr ); EXCEPTION WHEN OTHERS THEN -- There should have been no exception. GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; RETURN ok( FALSE, descr ) || E'\n' || diag( ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) RETURNS SETOF TEXT AS $$ DECLARE startup ALIAS FOR $1; shutdown ALIAS FOR $2; setup ALIAS FOR $3; teardown ALIAS FOR $4; tests ALIAS FOR $5; tap TEXT; tfaild INTEGER := 0; ffaild INTEGER := 0; tnumb INTEGER := 0; fnumb INTEGER := 0; tok BOOLEAN := TRUE; BEGIN BEGIN -- No plan support. PERFORM * FROM no_plan(); FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; EXCEPTION -- Catch all exceptions and simply rethrow custom exceptions. This -- will roll back everything in the above block. WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; END; -- Record how startup tests have failed. tfaild := num_failed(); FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP -- What subtest are we running? RETURN NEXT ' ' || diag_test_name('Subtest: ' || tests[i]); -- Reset the results. tok := TRUE; tnumb := COALESCE(_get('curr_test'), 0); IF tnumb > 0 THEN EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; PERFORM _set('curr_test', 0); PERFORM _set('failed', 0); END IF; DECLARE errstate text; errmsg text; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN BEGIN -- Run the setup functions. FOR tap IN SELECT * FROM _runem(setup, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the actual test function. FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the teardown functions. FOR tap IN SELECT * FROM _runem(teardown, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Emit the plan. fnumb := COALESCE(_get('curr_test'), 0); RETURN NEXT ' 1..' || fnumb; -- Emit any error messages. IF fnumb = 0 THEN RETURN NEXT ' # No tests run!'; tok = false; ELSE -- Report failures. ffaild := num_failed(); IF ffaild > 0 THEN tok := FALSE; RETURN NEXT ' ' || diag( 'Looks like you failed ' || ffaild || ' test' || CASE tfaild WHEN 1 THEN '' ELSE 's' END || ' of ' || fnumb ); END IF; END IF; EXCEPTION WHEN raise_exception THEN -- Something went wrong. Record that fact. errstate := SQLSTATE; errmsg := SQLERRM; GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; END; -- Always raise an exception to rollback any changes. RAISE EXCEPTION '__TAP_ROLLBACK__'; EXCEPTION WHEN raise_exception THEN IF errmsg IS NOT NULL THEN -- Something went wrong. Emit the error message. tok := FALSE; RETURN NEXT regexp_replace( diag('Test died: ' || _error_diag( errstate, errmsg, detail, hint, context, schname, tabname, colname, chkname, typname )), '^', ' ', 'gn'); errmsg := NULL; END IF; END; -- Restore the sequence. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; PERFORM _set('curr_test', tnumb); PERFORM _set('failed', tfaild); -- Record this test. RETURN NEXT ok(tok, tests[i]); IF NOT tok THEN tfaild := tfaild + 1; END IF; END LOOP; -- Run the shutdown functions. FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; -- Finish up. FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP RETURN NEXT tap; END LOOP; -- Clean up and return. PERFORM _cleanup(); RETURN; END; $$ LANGUAGE plpgsql; pgtap-1.3.2/sql/pgtap--0.96.0--0.97.0.sql.in000066400000000000000000000275411455775703000173310ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.97;' LANGUAGE SQL IMMUTABLE; -- pg_version_num() CREATE OR REPLACE FUNCTION pg_version_num() RETURNS integer AS $$ SELECT substring(s.a[1] FROM '[[:digit:]]+')::int * 10000 + COALESCE(substring(s.a[2] FROM '[[:digit:]]+')::int, 0) * 100 + COALESCE(substring(s.a[3] FROM '[[:digit:]]+')::int, 0) FROM ( SELECT string_to_array(current_setting('server_version'), '.') AS a ) AS s; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _is_indexed( NAME, NAME, TEXT[] ) RETURNS BOOL AS $$ SELECT EXISTS( SELECT TRUE FROM ( SELECT _ikeys(coalesce($1, n.nspname), $2, ci.relname) AS cols FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ($1 IS NULL OR n.nspname = $1) AND ct.relname = $2 ) icols WHERE cols = $3 ) $$ LANGUAGE sql; -- is_indexed( schema, table, columns[], description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_indexed($1, $2, $3), $4 ); $$ LANGUAGE sql; -- is_indexed( schema, table, columns[] ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _is_indexed($1, $2, $3), 'Should have an index on ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( $3, ', ' ) || ')' ); $$ LANGUAGE sql; -- is_indexed( table, columns[], description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_indexed(NULL, $1, $2), $3 ); $$ LANGUAGE sql; -- is_indexed( table, columns[] ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _is_indexed(NULL, $1, $2), 'Should have an index on ' || quote_ident($1) || '(' || array_to_string( $2, ', ' ) || ')' ); $$ LANGUAGE sql; -- is_indexed( schema, table, column, description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok ( _is_indexed( $1, $2, ARRAY[$3]::NAME[]), $4); $$ LANGUAGE sql; -- is_indexed( schema, table, column ) -- is_indexed( table, column, description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT CASE WHEN _is_schema( $1 ) THEN -- Looking for schema.table index. is_indexed( $1, $2, ARRAY[$3]::NAME[] ) ELSE -- Looking for particular columns. is_indexed( $1, ARRAY[$2]::NAME[], $3 ) END; $$ LANGUAGE sql; -- is_indexed( table, column ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok ( _is_indexed( NULL, $1, ARRAY[$2]::NAME[]) ); $$ LANGUAGE sql; -- isnt_definer( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _definer($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_definer( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_definer( schema, function ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_definer( function, args[] ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( function, description ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _definer($1), $2 ); $$ LANGUAGE sql; -- isnt_definer( function ) CREATE OR REPLACE FUNCTION isnt_definer( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1), 'Function ' || quote_ident($1) || '() should not be security definer' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _agg($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _agg($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _agg($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _agg($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _agg($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _agg($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _agg($1), $2 ); $$ LANGUAGE sql; -- isnt_aggregate( function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _agg($1), 'Function ' || quote_ident($1) || '() should not be an aggregate function' ); $$ LANGUAGE sql; -- https://github.com/theory/pgtap/pull/99 -- hasnt_opclass( schema, name ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1, $2 ), 'Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_opclass( name ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1 ), 'Operator class ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- https://github.com/theory/pgtap/pull/101 -- check extension exists function with schema name CREATE OR REPLACE FUNCTION _ext_exists( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_extension ex JOIN pg_catalog.pg_namespace n ON ex.extnamespace = n.oid WHERE n.nspname = $1 AND ex.extname = $2 ); $$ LANGUAGE SQL; -- check extension exists function without schema name CREATE OR REPLACE FUNCTION _ext_exists( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_extension ex WHERE ex.extname = $1 ); $$ LANGUAGE SQL; -- has_extension( schema, name, description ) CREATE OR REPLACE FUNCTION has_extension( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_extension( schema, name ) CREATE OR REPLACE FUNCTION has_extension( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1, $2 ), 'Extension ' || quote_ident($2) || ' should exist in schema ' || quote_ident($1) ); $$ LANGUAGE SQL; -- has_extension( name, description ) CREATE OR REPLACE FUNCTION has_extension( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1 ), $2) $$ LANGUAGE SQL; -- has_extension( name ) CREATE OR REPLACE FUNCTION has_extension( NAME ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1 ), 'Extension ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_extension( schema, name, description ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_extension( schema, name ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1, $2 ), 'Extension ' || quote_ident($2) || ' should not exist in schema ' || quote_ident($1) ); $$ LANGUAGE SQL; -- hasnt_extension( name, description ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1 ), $2) $$ LANGUAGE SQL; -- hasnt_extension( name ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1 ), 'Extension ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- https://github.com/theory/pgtap/pull/119 -- throws_ok ( sql, errcode, errmsg, description ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, CHAR(5), TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE query TEXT := _query($1); errcode ALIAS FOR $2; errmsg ALIAS FOR $3; desctext ALIAS FOR $4; descr TEXT; BEGIN descr := COALESCE( desctext, 'threw ' || errcode || ': ' || errmsg, 'threw ' || errcode, 'threw ' || errmsg, 'threw an exception' ); EXECUTE query; RETURN ok( FALSE, descr ) || E'\n' || diag( ' caught: no exception' || E'\n wanted: ' || COALESCE( errcode, 'an exception' ) ); EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN IF (errcode IS NULL OR SQLSTATE = errcode) AND ( errmsg IS NULL OR SQLERRM = errmsg) THEN -- The expected errcode and/or message was thrown. RETURN ok( TRUE, descr ); ELSE -- This was not the expected errcode or errmsg. RETURN ok( FALSE, descr ) || E'\n' || diag( ' caught: ' || SQLSTATE || ': ' || SQLERRM || E'\n wanted: ' || COALESCE( errcode, 'an exception' ) || COALESCE( ': ' || errmsg, '') ); END IF; END; $$ LANGUAGE plpgsql; -- lives_ok( sql, description ) CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE code TEXT := _query($1); descr ALIAS FOR $2; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN EXECUTE code; RETURN ok( TRUE, descr ); EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN -- There should have been no exception. GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; RETURN ok( FALSE, descr ) || E'\n' || diag( ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) ); END; $$ LANGUAGE plpgsql; pgtap-1.3.2/sql/pgtap--0.97.0--0.98.0.sql.in000066400000000000000000000331641455775703000173310ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.98;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _rexists ( CHAR[], NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR[], NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE c.relkind = ANY($1) AND pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT _rexists(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME ) RETURNS BOOLEAN AS $$ SELECT _rexists(ARRAY[$1], $2); $$ LANGUAGE SQL; -- has_table( schema, table, description ) CREATE OR REPLACE FUNCTION has_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_table( schema, table ) CREATE OR REPLACE FUNCTION has_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_table( table, description ) CREATE OR REPLACE FUNCTION has_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_table( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_table( schema, table ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_table( table, description ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1 ), $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR[], NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname NOT IN('pg_all_foreign_keys', 'tap_funky', '__tresults___numb_seq', '__tcache___id_seq') EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR[], NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE pg_catalog.pg_table_is_visible(c.oid) AND n.nspname <> 'pg_catalog' AND c.relkind = ANY($1) AND c.relname NOT IN ('__tcache__', 'pg_all_foreign_keys', 'tap_funky', '__tresults___numb_seq', '__tcache___id_seq') EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR, NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT _extras(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR, NAME[] ) RETURNS NAME[] AS $$ SELECT _extras(ARRAY[$1], $2); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR[], NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR[], NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE pg_catalog.pg_table_is_visible(c.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind = ANY($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR, NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT _missing(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR, NAME[] ) RETURNS NAME[] AS $$ SELECT _missing(ARRAY[$1], $2); $$ LANGUAGE SQL; -- tables_are( schema, tables, description ) CREATE OR REPLACE FUNCTION tables_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1, $2), _missing('{r,p}'::char[], $1, $2), $3); $$ LANGUAGE SQL; -- tables_are( tables, description ) CREATE OR REPLACE FUNCTION tables_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1), _missing('{r,p}'::char[], $1), $2); $$ LANGUAGE SQL; -- tables_are( schema, tables ) CREATE OR REPLACE FUNCTION tables_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1, $2), _missing('{r,p}'::char[], $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct tables' ); $$ LANGUAGE SQL; -- tables_are( tables ) CREATE OR REPLACE FUNCTION tables_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1), _missing('{r,p}'::char[], $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR[], NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname = $3 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR[], NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c WHERE c.relkind = ANY($1) AND c.relname = $2 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME, NAME ) RETURNS NAME AS $$ SELECT _get_rel_owner(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME ) RETURNS NAME AS $$ SELECT _get_rel_owner(ARRAY[$1], $2); $$ LANGUAGE SQL; -- table_owner_is ( schema, table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('{r,p}'::char[], $1, $2); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- table_owner_is ( table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('{r,p}'::char[], $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- is_partitioned( schema, table, description ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1, $2), $3); $$ LANGUAGE sql; -- is_partitioned( schema, table ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1, $2), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be partitioned' ); $$ LANGUAGE sql; -- is_partitioned( table, description ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1), $2); $$ LANGUAGE sql; -- is_partitioned( table ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1), 'Table ' || quote_ident($1) || ' should be partitioned' ); $$ LANGUAGE sql; -- isnt_partitioned( schema, table, description ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1, $2), $3); $$ LANGUAGE sql; -- isnt_partitioned( schema, table ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1, $2), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not be partitioned' ); $$ LANGUAGE sql; -- isnt_partitioned( table, description ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1), $2); $$ LANGUAGE sql; -- isnt_partitioned( table ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1), 'Table ' || quote_ident($1) || ' should not be partitioned' ); $$ LANGUAGE sql; -- _partof( child_schema, child_table, parent_schema, parent_table ) CREATE OR REPLACE FUNCTION _partof ( NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace cn JOIN pg_catalog.pg_class cc ON cn.oid = cc.relnamespace JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid JOIN pg_catalog.pg_namespace pn ON pc.relnamespace = pn.oid WHERE cn.nspname = $1 AND cc.relname = $2 AND cc.relispartition AND pn.nspname = $3 AND pc.relname = $4 AND pc.relkind = 'p' ) $$ LANGUAGE sql; -- _partof( child_table, parent_table ) CREATE OR REPLACE FUNCTION _partof ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class cc JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid WHERE cc.relname = $1 AND cc.relispartition AND pc.relname = $2 AND pc.relkind = 'p' AND pg_catalog.pg_table_is_visible(cc.oid) AND pg_catalog.pg_table_is_visible(pc.oid) ) $$ LANGUAGE sql; -- is_partition_of( child_schema, child_table, parent_schema, parent_table, description ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2, $3, $4), $5); $$ LANGUAGE sql; -- is_partition_of( child_schema, child_table, parent_schema, parent_table ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2, $3, $4), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be a partition of ' || quote_ident($3) || '.' || quote_ident($4) ); $$ LANGUAGE sql; -- is_partition_of( child_table, parent_table, description ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2), $3); $$ LANGUAGE sql; -- is_partition_of( child_table, parent_table ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2), 'Table ' || quote_ident($1) || ' should be a partition of ' || quote_ident($2) ); $$ LANGUAGE sql; -- _parts(schema, table) CREATE OR REPLACE FUNCTION _parts( NAME, NAME ) RETURNS SETOF NAME AS $$ SELECT i.inhrelid::regclass::name FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent WHERE n.nspname = $1 AND c.relname = $2 AND c.relkind = 'p' $$ LANGUAGE SQL; -- _parts(table) CREATE OR REPLACE FUNCTION _parts( NAME ) RETURNS SETOF NAME AS $$ SELECT i.inhrelid::regclass::name FROM pg_catalog.pg_class c JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent WHERE c.relname = $1 AND c.relkind = 'p' AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- partitions_are( schema, table, partitions, description ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'partitions', ARRAY(SELECT _parts($1, $2) EXCEPT SELECT unnest($3)), ARRAY(SELECT unnest($3) EXCEPT SELECT _parts($1, $2)), $4 ); $$ LANGUAGE SQL; -- partitions_are( schema, table, partitions ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT partitions_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct partitions' ); $$ LANGUAGE SQL; -- partitions_are( table, partitions, description ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'partitions', ARRAY(SELECT _parts($1) EXCEPT SELECT unnest($2)), ARRAY(SELECT unnest($2) EXCEPT SELECT _parts($1)), $3 ); $$ LANGUAGE SQL; -- partitions_are( table, partitions ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT partitions_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct partitions' ); $$ LANGUAGE SQL; pgtap-1.3.2/sql/pgtap--0.98.0--0.99.0.sql.in000066400000000000000000000143451455775703000173330ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 0.99;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION pg_version_num() RETURNS integer AS $$ SELECT current_setting('server_version_num')::integer; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _ident_array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT quote_ident($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY $1[i] ), $2); $$ LANGUAGE SQL immutable; CREATE OR REPLACE FUNCTION _array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY $1[i] ), $2); $$ LANGUAGE SQL immutable; CREATE OR REPLACE FUNCTION _are ( text, name[], name[], TEXT ) RETURNS TEXT AS $$ DECLARE what ALIAS FOR $1; extras ALIAS FOR $2; missing ALIAS FOR $3; descr ALIAS FOR $4; msg TEXT := ''; res BOOLEAN := TRUE; BEGIN IF extras[1] IS NOT NULL THEN res = FALSE; msg := E'\n' || diag( ' Extra ' || what || E':\n ' || _ident_array_to_sorted_string( extras, E'\n ' ) ); END IF; IF missing[1] IS NOT NULL THEN res = FALSE; msg := msg || E'\n' || diag( ' Missing ' || what || E':\n ' || _ident_array_to_sorted_string( missing, E'\n ' ) ); END IF; RETURN ok(res, descr) || msg; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _areni ( text, text[], text[], TEXT ) RETURNS TEXT AS $$ DECLARE what ALIAS FOR $1; extras ALIAS FOR $2; missing ALIAS FOR $3; descr ALIAS FOR $4; msg TEXT := ''; res BOOLEAN := TRUE; BEGIN IF extras[1] IS NOT NULL THEN res = FALSE; msg := E'\n' || diag( ' Extra ' || what || E':\n ' || _array_to_sorted_string( extras, E'\n ' ) ); END IF; IF missing[1] IS NOT NULL THEN res = FALSE; msg := msg || E'\n' || diag( ' Missing ' || what || E':\n ' || _array_to_sorted_string( missing, E'\n ' ) ); END IF; RETURN ok(res, descr) || msg; END; $$ LANGUAGE plpgsql; -- Note: this fixes a bug in the 97->98 upgrade script -- table_owner_is ( table, user, description ) /* CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('{r,p}'::char[], $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; */ -- _hasc( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON c.relnamespace = n.oid JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid JOIN pg_catalog.pg_index i ON c.oid = i.indrelid WHERE i.indisprimary = true AND n.nspname = $1 AND c.relname = $2 AND x.contype = $3 ); $$ LANGUAGE sql; -- _hasc( table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid JOIN pg_catalog.pg_index i ON c.oid = i.indrelid WHERE i.indisprimary = true AND pg_table_is_visible(c.oid) AND c.relname = $1 AND x.contype = $2 ); $$ LANGUAGE sql; CREATE OR REPLACE VIEW tap_funky AS SELECT p.oid AS oid, n.nspname AS schema, p.proname AS name, pg_catalog.pg_get_userbyid(p.proowner) AS owner, array_to_string(p.proargtypes::regtype[], ',') AS args, CASE p.proretset WHEN TRUE THEN 'setof ' ELSE '' END || p.prorettype::regtype AS returns, p.prolang AS langoid, p.proisstrict AS is_strict, p.prokind AS kind, p.prosecdef AS is_definer, p.proretset AS returns_set, p.provolatile::char AS volatility, pg_catalog.pg_function_is_visible(p.oid) AS is_visible FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid ; CREATE OR REPLACE FUNCTION _agg ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = 'a' FROM tap_funky WHERE schema = $1 AND name = $2 AND args = array_to_string($3, ',') $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _agg ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT kind = 'a' FROM tap_funky WHERE schema = $1 AND name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _agg ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = 'a' FROM tap_funky WHERE name = $1 AND args = array_to_string($2, ',') AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _agg ( NAME ) RETURNS BOOLEAN AS $$ SELECT kind = 'a' FROM tap_funky WHERE name = $1 AND is_visible; $$ LANGUAGE SQL; -- _hasc( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON c.relnamespace = n.oid JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE n.nspname = $1 AND c.relname = $2 AND x.contype = $3 ); $$ LANGUAGE sql; -- _hasc( table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE pg_table_is_visible(c.oid) AND c.relname = $1 AND x.contype = $2 ); $$ LANGUAGE sql; pgtap-1.3.2/sql/pgtap--0.99.0--1.0.0.sql.in000066400000000000000000000615771455775703000172440ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 1.0;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY $1[i] ), $2); $$ LANGUAGE SQL immutable; -- policies_are( schema, table, policies[], description ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policies', ARRAY( SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 ), $4 ); $$ LANGUAGE SQL; -- policies_are( schema, table, policies[] ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policies_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct policies' ); $$ LANGUAGE SQL; -- policies_are( table, policies[], description ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policies', ARRAY( SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND n.nspname NOT IN ('pg_catalog', 'information_schema') ), $3 ); $$ LANGUAGE SQL; -- policies_are( table, policies[] ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policies_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct policies' ); $$ LANGUAGE SQL; -- policy_roles_are( schema, table, policy, roles[], description ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policy roles', ARRAY( SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 EXCEPT SELECT $4[i] FROM generate_series(1, array_upper($4, 1)) s(i) ), ARRAY( SELECT $4[i] FROM generate_series(1, array_upper($4, 1)) s(i) EXCEPT SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 ), $5 ); $$ LANGUAGE SQL; -- policy_roles_are( schema, table, policy, roles[] ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policy_roles_are( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct roles' ); $$ LANGUAGE SQL; -- policy_roles_are( table, policy, roles[], description ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policy roles', ARRAY( SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') ), $4 ); $$ LANGUAGE SQL; -- policy_roles_are( table, policy, roles[] ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policy_roles_are( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should have the correct roles' ); $$ LANGUAGE SQL; -- policy_cmd_is( schema, table, policy, command, description ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text, text ) RETURNS TEXT AS $$ DECLARE cmd text; BEGIN SELECT CASE pp.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' ELSE 'ALL' END FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 INTO cmd; RETURN is( cmd, upper($4), $5 ); END; $$ LANGUAGE plpgsql; -- policy_cmd_is( schema, table, policy, command ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT policy_cmd_is( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should apply to ' || upper($4) || ' command' ); $$ LANGUAGE sql; -- policy_cmd_is( table, policy, command, description ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text, text ) RETURNS TEXT AS $$ DECLARE cmd text; BEGIN SELECT CASE pp.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' ELSE 'ALL' END FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') INTO cmd; RETURN is( cmd, upper($3), $4 ); END; $$ LANGUAGE plpgsql; -- policy_cmd_is( table, policy, command ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text ) RETURNS TEXT AS $$ SELECT policy_cmd_is( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should apply to ' || upper($3) || ' command' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _funkargs ( NAME[] ) RETURNS TEXT AS $$ BEGIN RETURN array_to_string($1::regtype[], ','); EXCEPTION WHEN undefined_object THEN RETURN array_to_string($1, ','); END; $$ LANGUAGE PLPGSQL STABLE; CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible ); $$ LANGUAGE SQL; /* * Internal function to test whether the specified table in the specified schema * has an inheritance chain. Returns true or false. */ CREATE OR REPLACE FUNCTION _inherited( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = 'r' AND n.nspname = $1 AND c.relname = $2 AND c.relhassubclass = true ); $$ LANGUAGE SQL; /* * Internal function to test whether a specific table in the search_path has an * inheritance chain. Returns true or false. */ CREATE OR REPLACE FUNCTION _inherited( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE c.relkind = 'r' AND pg_catalog.pg_table_is_visible( c.oid ) AND c.relname = $1 AND c.relhassubclass = true ); $$ LANGUAGE SQL; -- has_inherited_tables( schema, table, description ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1, $2 ), $3); $$ LANGUAGE SQL; -- has_inherited_tables( schema, table ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1, $2 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should have descendents' ); $$ LANGUAGE SQL; -- has_inherited_tables( table, description ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1 ), $2 ); $$ LANGUAGE SQL; -- has_inherited_tables( table ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1 ), 'Table ' || quote_ident( $1 ) || ' should have descendents' ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( schema, table ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1, $2 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not have descendents' ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( table, description ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( table ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1 ), 'Table ' || quote_ident( $1 ) || ' should not have descendents' ); $$ LANGUAGE SQL; /* * Internal function to test whether the schema-qualified table is an ancestor of * the other schema-qualified table. The integer value is the length of the * inheritance chain: a direct ancestor has has a chain length of 1. */ CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS BOOLEAN AS $$ WITH RECURSIVE inheritance_chain AS ( -- select the ancestor tuple SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level FROM pg_catalog.pg_inherits i WHERE i.inhparent = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND n1.nspname = $1 ) UNION -- select the descendents SELECT i.inhrelid AS descendent_id, p.inheritance_level + 1 AS inheritance_level FROM pg_catalog.pg_inherits i JOIN inheritance_chain p ON p.descendent_id = i.inhparent WHERE i.inhrelid = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $4 AND n1.nspname = $3 ) ) SELECT EXISTS( SELECT true FROM inheritance_chain WHERE inheritance_level = COALESCE($5, inheritance_level) AND descendent_id = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $4 AND n1.nspname = $3 ) ); $$ LANGUAGE SQL; /* * Internal function to check if not-qualified tables * within the search_path are connected by an inheritance chain. */ CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, INT ) RETURNS BOOLEAN AS $$ WITH RECURSIVE inheritance_chain AS ( -- select the ancestor tuple SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level FROM pg_catalog.pg_inherits i WHERE i.inhparent = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $1 AND pg_catalog.pg_table_is_visible( c1.oid ) ) UNION -- select the descendents SELECT i.inhrelid AS descendent_id, p.inheritance_level + 1 AS inheritance_level FROM pg_catalog.pg_inherits i JOIN inheritance_chain p ON p.descendent_id = i.inhparent WHERE i.inhrelid = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND pg_catalog.pg_table_is_visible( c1.oid ) ) ) SELECT EXISTS( SELECT true FROM inheritance_chain WHERE inheritance_level = COALESCE($3, inheritance_level) AND descendent_id = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND pg_catalog.pg_table_is_visible( c1.oid ) ) ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be ancestor ' || $5 || ' for ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, NULL ), $5 ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be an ancestor of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, depth ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3 ), 'Table ' || quote_ident( $1 ) || ' should be ancestor ' || $3 || ' of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, NULL ), $3 ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || ' should be an ancestor of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be ancestor ' || $5 || ' for ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, NULL ), $5 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be an ancestor of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, depth ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3 ), 'Table ' || quote_ident( $1 ) || ' should not be ancestor ' || $3 || ' of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, NULL ), $3 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || ' should not be an ancestor of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, $5 ), $6 ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be descendent ' || $5 || ' from ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, NULL ), $5 ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be a descendent of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, $3 ), $4 ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, depth ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, $3 ), 'Table ' || quote_ident( $1 ) || ' should be descendent ' || $3 || ' from ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, NULL ), $3 ); $$ LANGUAGE SQL; -- is_descendent_of( table, table ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, NULL ), 'Table ' || quote_ident( $1 ) || ' should be a descendent of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, $5 ), $6 ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $3, $4, $1, $2, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be descendent ' || $5 || ' from ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, NULL ), $5 ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $3, $4, $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be a descendent of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $2, $1, $3 ), $4 ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, depth ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $2, $1, $3 ), 'Table ' || quote_ident( $1 ) || ' should not be descendent ' || $3 || ' from ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $2, $1, NULL ), $3 ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $2, $1, NULL ), 'Table ' || quote_ident( $1 ) || ' should not be a descendent of ' || quote_ident( $2) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _def_is( TEXT, TEXT, anyelement, TEXT ) RETURNS TEXT AS $$ DECLARE thing text; BEGIN -- Function or special SQL syntax. IF $1 ~ '^[^'']+[(]' OR $1 = ANY('{CURRENT_CATALOG,CURRENT_ROLE,CURRENT_SCHEMA,CURRENT_USER,SESSION_USER,USER}') THEN RETURN is( $1, $3, $4 ); END IF; EXECUTE 'SELECT is(' || COALESCE($1, 'NULL' || '::' || $2) || '::' || $2 || ', ' || COALESCE(quote_literal($3), 'NULL') || '::' || $2 || ', ' || COALESCE(quote_literal($4), 'NULL') || ')' INTO thing; RETURN thing; END; $$ LANGUAGE plpgsql; pgtap-1.3.2/sql/pgtap--1.0.0--1.1.0.sql000066400000000000000000000134371455775703000165270ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 1.1;' LANGUAGE SQL IMMUTABLE; -- These are now obsolete DROP FUNCTION col_not_null ( NAME, NAME ); DROP FUNCTION col_is_null ( NAME, NAME, NAME ); DROP FUNCTION col_is_null ( NAME, NAME ); -- _col_is_null( schema, table, column, desc, null ) CREATE OR REPLACE FUNCTION _col_is_null ( NAME, NAME, NAME, TEXT, bool ) RETURNS TEXT AS $$ DECLARE qcol CONSTANT text := quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3); c_desc CONSTANT text := coalesce( $4, 'Column ' || qcol || ' should ' || CASE WHEN $5 THEN 'be NOT' ELSE 'allow' END || ' NULL' ); BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( c_desc ) || E'\n' || diag (' Column ' || qcol || ' does not exist' ); END IF; RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3 AND a.attnotnull = $5 ), c_desc ); END; $$ LANGUAGE plpgsql; -- _col_is_null( table, column, desc, null ) CREATE OR REPLACE FUNCTION _col_is_null ( NAME, NAME, TEXT, bool ) RETURNS TEXT AS $$ DECLARE qcol CONSTANT text := quote_ident($1) || '.' || quote_ident($2); c_desc CONSTANT text := coalesce( $3, 'Column ' || qcol || ' should ' || CASE WHEN $4 THEN 'be NOT' ELSE 'allow' END || ' NULL' ); BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( c_desc ) || E'\n' || diag (' Column ' || qcol || ' does not exist' ); END IF; RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2 AND a.attnotnull = $4 ), c_desc ); END; $$ LANGUAGE plpgsql; -- col_not_null( schema, table, column, description ) -- col_not_null( schema, table, column ) CREATE OR REPLACE FUNCTION col_not_null ( schema_name NAME, table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, $4, true ); $$ LANGUAGE SQL; -- col_not_null( table, column, description ) -- col_not_null( table, column ) CREATE OR REPLACE FUNCTION col_not_null ( table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, true ); $$ LANGUAGE SQL; -- col_is_null( schema, table, column, description ) -- col_is_null( schema, table, column ) CREATE OR REPLACE FUNCTION col_is_null ( schema_name NAME, table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, $4, false ); $$ LANGUAGE SQL; -- col_is_null( table, column, description ) -- col_is_null( table, column ) CREATE OR REPLACE FUNCTION col_is_null ( table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, false ); $$ LANGUAGE SQL; -- _keys( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _keys ( NAME, NAME, CHAR ) RETURNS SETOF NAME[] AS $$ SELECT _pg_sv_column_array(x.conrelid,x.conkey) -- name[] doesn't support collation FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE n.nspname = $1 AND c.relname = $2 AND x.contype = $3 ORDER BY 1 $$ LANGUAGE sql; -- _keys( table, constraint_type ) CREATE OR REPLACE FUNCTION _keys ( NAME, CHAR ) RETURNS SETOF NAME[] AS $$ SELECT _pg_sv_column_array(x.conrelid,x.conkey) -- name[] doesn't support collation FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid AND c.relname = $1 AND x.contype = $2 WHERE pg_catalog.pg_table_is_visible(c.oid) ORDER BY 1 $$ LANGUAGE sql; -- finish DROP FUNCTION finish(); DROP FUNCTION _finish (INTEGER, INTEGER, INTEGER); CREATE OR REPLACE FUNCTION _finish (INTEGER, INTEGER, INTEGER, BOOLEAN DEFAULT NULL) RETURNS SETOF TEXT AS $$ DECLARE curr_test ALIAS FOR $1; exp_tests INTEGER := $2; num_faild ALIAS FOR $3; plural CHAR; raise_ex ALIAS FOR $4; BEGIN plural := CASE exp_tests WHEN 1 THEN '' ELSE 's' END; IF curr_test IS NULL THEN RAISE EXCEPTION '# No tests run!'; END IF; IF exp_tests = 0 OR exp_tests IS NULL THEN -- No plan. Output one now. exp_tests = curr_test; RETURN NEXT '1..' || exp_tests; END IF; IF curr_test <> exp_tests THEN RETURN NEXT diag( 'Looks like you planned ' || exp_tests || ' test' || plural || ' but ran ' || curr_test ); ELSIF num_faild > 0 THEN IF raise_ex THEN RAISE EXCEPTION '% test% failed of %', num_faild, CASE num_faild WHEN 1 THEN '' ELSE 's' END, exp_tests; END IF; RETURN NEXT diag( 'Looks like you failed ' || num_faild || ' test' || CASE num_faild WHEN 1 THEN '' ELSE 's' END || ' of ' || exp_tests ); ELSE END IF; RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION finish (exception_on_failure BOOLEAN DEFAULT NULL) RETURNS SETOF TEXT AS $$ SELECT * FROM _finish( _get('curr_test'), _get('plan'), num_failed(), $1 ); $$ LANGUAGE sql; pgtap-1.3.2/sql/pgtap--1.1.0--1.2.0.sql000066400000000000000000000731151455775703000165300ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT 1.2;' LANGUAGE SQL IMMUTABLE; -- isnt_member_of( role, members[], description ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE extra text[]; BEGIN IF NOT _has_role($1) THEN RETURN fail( $3 ) || E'\n' || diag ( ' Role ' || quote_ident($1) || ' does not exist' ); END IF; SELECT ARRAY( SELECT quote_ident($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) LEFT JOIN pg_catalog.pg_roles r ON rolname = $2[i] WHERE r.oid = ANY ( _grolist($1) ) ORDER BY s.i ) INTO extra; IF extra[1] IS NULL THEN RETURN ok( true, $3 ); END IF; RETURN ok( false, $3 ) || E'\n' || diag( ' Members, who should not be in ' || quote_ident($1) || E' role:\n ' || array_to_string( extra, E'\n ') ); END; $$ LANGUAGE plpgsql; -- isnt_member_of( role, member, description ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, ARRAY[$2], $3 ); $$ LANGUAGE SQL; -- isnt_member_of( role, members[] ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, $2, 'Should not have members of role ' || quote_ident($1) ); $$ LANGUAGE SQL; -- isnt_member_of( role, member ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, ARRAY[$2] ); $$ LANGUAGE SQL; -- has_view( schema, view ) CREATE OR REPLACE FUNCTION has_view ( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_view ($1, $2, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_view( schema, table ) CREATE OR REPLACE FUNCTION hasnt_view ( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_view( $1, $2, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _def_is( TEXT, TEXT, anyelement, TEXT ) RETURNS TEXT AS $$ DECLARE thing text; BEGIN -- Function, cast, or special SQL syntax. IF $1 ~ '^[^'']+[(]' OR $1 ~ '[)]::[^'']+$' OR $1 = ANY('{CURRENT_CATALOG,CURRENT_ROLE,CURRENT_SCHEMA,CURRENT_USER,SESSION_USER,USER,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,LOCALTIME,LOCALTIMESTAMP}') THEN RETURN is( $1, $3, $4 ); END IF; EXECUTE 'SELECT is(' || COALESCE($1, 'NULL' || '::' || $2) || '::' || $2 || ', ' || COALESCE(quote_literal($3), 'NULL') || '::' || $2 || ', ' || COALESCE(quote_literal($4), 'NULL') || ')' INTO thing; RETURN thing; END; $$ LANGUAGE plpgsql; -- results_eq( cursor, cursor, description ) CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor, text ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; have_rec RECORD; want_rec RECORD; have_found BOOLEAN; want_found BOOLEAN; rownum INTEGER := 1; err_msg text := 'details not available in pg <= 9.1'; BEGIN FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN RETURN ok( false, $3 ) || E'\n' || diag( ' Results differ beginning at row ' || rownum || E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END ); END IF; rownum = rownum + 1; FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; END LOOP; RETURN ok( true, $3 ); EXCEPTION WHEN datatype_mismatch THEN GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END END || E'\n ERROR: ' || err_msg ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION results_ne( refcursor, refcursor, text ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; have_rec RECORD; want_rec RECORD; have_found BOOLEAN; want_found BOOLEAN; err_msg text := 'details not available in pg <= 9.1'; BEGIN FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN RETURN ok( true, $3 ); ELSE FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; END IF; END LOOP; RETURN ok( false, $3 ); EXCEPTION WHEN datatype_mismatch THEN GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END END || E'\n ERROR: ' || err_msg ); END; $$ LANGUAGE plpgsql; -- hasnt_operator( left_type, schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4, $5 ), 'Operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',' || $4 || ') RETURNS ' || $5 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4 ), $5 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') should not exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3, $4), $5 ); $$ LANGUAGE SQL; -- hasnt_leftop( schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3, $4 ), 'Left operator ' || quote_ident($1) || '.' || $2 || '(NONE,' || $3 || ') RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') RETURNS ' || $3 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2), $3 ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') should not exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, schema, name, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, $3, NULL, $4), $5 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, schema, name, return_type ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, NULL, $4 ), 'Right operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',NONE) RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, NULL, $3), $4 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, return_type ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, NULL, $3 ), 'Right operator ' || $2 || '(' || $1 || ',NONE) RETURNS ' || $3 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, NULL), $3 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, NULL ), 'Right operator ' || $2 || '(' || $1 || ',NONE) should not exist' ); $$ LANGUAGE SQL; /* * tap_funky used to just be a simple view, but the problem with that is the * definition of pg_proc changed in version 11. Thanks to how pg_dump (and * hence pg_upgrade) works, this made it impossible to upgrade Postgres if * pgTap was installed. In order to fix that, we need code that will actually * work on both < PG11 and >= PG11. */ CREATE OR REPLACE FUNCTION _prokind( p_oid oid ) RETURNS "char" AS $$ BEGIN IF pg_version_num() >= 110000 THEN RETURN prokind FROM pg_catalog.pg_proc WHERE oid = p_oid; ELSE RETURN CASE WHEN proisagg THEN 'a' WHEN proiswindow THEN 'w' ELSE 'f' END FROM pg_catalog.pg_proc WHERE oid = p_oid; END IF; END; $$ LANGUAGE plpgsql STABLE; -- Returns true if the specified function exists and is the specified type, -- false if it exists and is not the specified type, and NULL if it does not -- exist. Types are f for a normal function, p for a procedure, a for an -- aggregate function, or w for a window function -- _type_func(type, schema, function, args[]) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE schema = $2 AND name = $3 AND args = array_to_string($4, ',') $$ LANGUAGE SQL; -- _type_func(type, schema, function) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE schema = $2 AND name = $3 $$ LANGUAGE SQL; -- _type_func(type, function, args[]) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE name = $2 AND args = array_to_string($3, ',') AND is_visible; $$ LANGUAGE SQL; -- _type_func(type, function) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE name = $2 AND is_visible; $$ LANGUAGE SQL; -- is_aggregate( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'a', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_aggregate( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('a', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( schema, function, description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_aggregate( schema, function ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( function, args[], description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_aggregate( function, args[] ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( function, description ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('a', $1), $2 ); $$ LANGUAGE sql; -- is_aggregate( function ) CREATE OR REPLACE FUNCTION is_aggregate( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('a', $1), 'Function ' || quote_ident($1) || '() should be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('a', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('a', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('a', $1), $2 ); $$ LANGUAGE sql; -- isnt_aggregate( function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('a', $1), 'Function ' || quote_ident($1) || '() should not be an aggregate function' ); $$ LANGUAGE sql; DROP FUNCTION _agg ( NAME ); DROP FUNCTION _agg ( NAME, NAME[] ); DROP FUNCTION _agg ( NAME, NAME ); DROP FUNCTION _agg ( NAME, NAME, NAME[] ); -- is_normal_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func('f', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_normal_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('f', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( schema, function, description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_normal_function( schema, function ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( function, args[], description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_normal_function( function, args[] ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( function, description ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('f', $1), $2 ); $$ LANGUAGE sql; -- is_normal_function( function ) CREATE OR REPLACE FUNCTION is_normal_function( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('f', $1), 'Function ' || quote_ident($1) || '() should be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('f', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_normal_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('f', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_normal_function( schema, function ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_normal_function( function, args[] ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( function, description ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('f', $1), $2 ); $$ LANGUAGE sql; -- isnt_normal_function( function ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('f', $1), 'Function ' || quote_ident($1) || '() should not be a normal function' ); $$ LANGUAGE sql; -- is_window( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'w', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_window( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('w', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a window function' ); $$ LANGUAGE sql; -- is_window( schema, function, description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_window( schema, function ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a window function' ); $$ LANGUAGE sql; -- is_window( function, args[], description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_window( function, args[] ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a window function' ); $$ LANGUAGE sql; -- is_window( function, description ) CREATE OR REPLACE FUNCTION is_window( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('w', $1), $2 ); $$ LANGUAGE sql; -- is_window( function ) CREATE OR REPLACE FUNCTION is_window( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('w', $1), 'Function ' || quote_ident($1) || '() should be a window function' ); $$ LANGUAGE sql; -- isnt_window( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('w', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_window( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('w', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_window( schema, function ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_window( function, args[] ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( function, description ) CREATE OR REPLACE FUNCTION isnt_window( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('w', $1), $2 ); $$ LANGUAGE sql; -- isnt_window( function ) CREATE OR REPLACE FUNCTION isnt_window( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('w', $1), 'Function ' || quote_ident($1) || '() should not be a window function' ); $$ LANGUAGE sql; -- is_procedure( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'p', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_procedure( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('p', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( schema, function, description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_procedure( schema, function ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( function, args[], description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_procedure( function, args[] ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( function, description ) CREATE OR REPLACE FUNCTION is_procedure( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('p', $1), $2 ); $$ LANGUAGE sql; -- is_procedure( function ) CREATE OR REPLACE FUNCTION is_procedure( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('p', $1), 'Function ' || quote_ident($1) || '() should be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('p', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_procedure( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('p', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_procedure( schema, function ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_procedure( function, args[] ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( function, description ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('p', $1), $2 ); $$ LANGUAGE sql; -- isnt_procedure( function ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('p', $1), 'Function ' || quote_ident($1) || '() should not be a procedure' ); $$ LANGUAGE sql; pgtap-1.3.2/sql/pgtap--1.2.0--1.3.0.sql000066400000000000000000000401571455775703000165320ustar00rootroot00000000000000CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) RETURNS SETOF TEXT AS $$ DECLARE startup ALIAS FOR $1; shutdown ALIAS FOR $2; setup ALIAS FOR $3; teardown ALIAS FOR $4; tests ALIAS FOR $5; tap TEXT; tfaild INTEGER := 0; ffaild INTEGER := 0; tnumb INTEGER := 0; fnumb INTEGER := 0; tok BOOLEAN := TRUE; BEGIN BEGIN -- No plan support. PERFORM * FROM no_plan(); FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; EXCEPTION -- Catch all exceptions and simply rethrow custom exceptions. This -- will roll back everything in the above block. WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; END; -- Record how startup tests have failed. tfaild := num_failed(); FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP -- What subtest are we running? RETURN NEXT diag_test_name('Subtest: ' || tests[i]); -- Reset the results. tok := TRUE; tnumb := COALESCE(_get('curr_test'), 0); IF tnumb > 0 THEN EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; PERFORM _set('curr_test', 0); PERFORM _set('failed', 0); END IF; DECLARE errstate text; errmsg text; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN BEGIN -- Run the setup functions. FOR tap IN SELECT * FROM _runem(setup, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the actual test function. FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the teardown functions. FOR tap IN SELECT * FROM _runem(teardown, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Emit the plan. fnumb := COALESCE(_get('curr_test'), 0); RETURN NEXT ' 1..' || fnumb; -- Emit any error messages. IF fnumb = 0 THEN RETURN NEXT ' # No tests run!'; tok = false; ELSE -- Report failures. ffaild := num_failed(); IF ffaild > 0 THEN tok := FALSE; RETURN NEXT ' ' || diag( 'Looks like you failed ' || ffaild || ' test' || CASE ffaild WHEN 1 THEN '' ELSE 's' END || ' of ' || fnumb ); END IF; END IF; EXCEPTION WHEN OTHERS THEN -- Something went wrong. Record that fact. errstate := SQLSTATE; errmsg := SQLERRM; GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; END; -- Always raise an exception to rollback any changes. RAISE EXCEPTION '__TAP_ROLLBACK__'; EXCEPTION WHEN raise_exception THEN IF errmsg IS NOT NULL THEN -- Something went wrong. Emit the error message. tok := FALSE; RETURN NEXT regexp_replace( diag('Test died: ' || _error_diag( errstate, errmsg, detail, hint, context, schname, tabname, colname, chkname, typname )), '^', ' ', 'gn'); errmsg := NULL; END IF; END; -- Restore the sequence. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; PERFORM _set('curr_test', tnumb); PERFORM _set('failed', tfaild); -- Record this test. RETURN NEXT ok(tok, tests[i]); IF NOT tok THEN tfaild := tfaild + 1; END IF; END LOOP; -- Run the shutdown functions. FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; -- Finish up. FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP RETURN NEXT tap; END LOOP; -- Clean up and return. PERFORM _cleanup(); RETURN; END; $$ LANGUAGE plpgsql; -- col_is_pk( schema, table, column[] ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should be a primary key' ); $$ LANGUAGE sql; -- col_is_pk( schema, table, column ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should be a primary key' ); $$ LANGUAGE sql; -- schemas_are( schemas, description ) CREATE OR REPLACE FUNCTION schemas_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'schemas', ARRAY( SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' ), $2 ); CREATE OR REPLACE FUNCTION _lang ( NAME, NAME, NAME[] ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.schema = $1 and f.name = $2 AND f.args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _lang ( NAME, NAME[] ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.name = $1 AND f.args = _funkargs($2) AND f.is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE schema = $2 AND name = $3 AND args = _funkargs($4) $$ LANGUAGE SQL; -- _type_func(type, function, args[]) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE name = $2 AND args = _funkargs($3) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _strict ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _strict ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _vol ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.schema = $1 and f.name = $2 AND f.args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _vol ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.name = $1 AND f.args = _funkargs($2) AND f.is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _typename ( NAME ) RETURNS TEXT AS $$ BEGIN RETURN $1::REGTYPE; EXCEPTION WHEN undefined_object THEN RETURN $1; END; $$ LANGUAGE PLPGSQL STABLE; CREATE OR REPLACE FUNCTION _quote_ident_like(TEXT, TEXT) RETURNS TEXT AS $$ DECLARE typname TEXT := _typename($1); pcision TEXT := COALESCE(substring($1 FROM '[(][^")]+[)]$'), ''); BEGIN -- Just return it if rhs isn't quoted. IF $2 !~ '"' THEN RETURN typname || pcision; END IF; -- Otherwise return it with the type part quoted. RETURN quote_ident(typname) || pcision; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _retval(TEXT) RETURNS TEXT AS $$ DECLARE setof TEXT := substring($1 FROM '^setof[[:space:]]+'); BEGIN IF setof IS NULL THEN RETURN _typename($1); END IF; RETURN setof || _typename(substring($1 FROM char_length(setof)+1)); END; $$ LANGUAGE plpgsql; -- function_returns( schema, function, args[], type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _returns($1, $2, $3), _retval($4), $5 ); $$ LANGUAGE SQL; -- function_returns( schema, function, type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _returns($1, $2), _retval($3), $4 ); $$ LANGUAGE SQL; -- function_returns( function, args[], type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _returns($1, $2), _retval($3), $4 ); $$ LANGUAGE SQL; -- function_returns( function, type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _returns($1), _retval($2), $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _types_are ( NAME, NAME[], TEXT, CHAR[] ) RETURNS TEXT AS $$ SELECT _are( 'types', ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) EXCEPT SELECT _typename($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT _typename($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) ), $3 ); $$ LANGUAGE SQL; -- types_are( types[], description ) CREATE OR REPLACE FUNCTION _types_are ( NAME[], TEXT, CHAR[] ) RETURNS TEXT AS $$ SELECT _are( 'types', ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) EXCEPT SELECT _typename($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT _typename($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) ), $2 ); $$ LANGUAGE SQL; -- _op_exists( left_type, schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $2 AND o.oprname = $3 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $4 IS NULL ELSE _cmp_types(o.oprright, _typename($4)) END AND _cmp_types(o.oprresult, $5) ); $$ LANGUAGE SQL; -- _op_exists( left_type, name, right_type, return_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o WHERE pg_catalog.pg_operator_is_visible(o.oid) AND o.oprname = $2 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $3 IS NULL ELSE _cmp_types(o.oprright, _typename($3)) END AND _cmp_types(o.oprresult, $4) ); $$ LANGUAGE SQL; -- _op_exists( left_type, name, right_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o WHERE pg_catalog.pg_operator_is_visible(o.oid) AND o.oprname = $2 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $3 IS NULL ELSE _cmp_types(o.oprright, _typename($3)) END ); $$ LANGUAGE SQL; pgtap-1.3.2/sql/pgtap--1.3.0--1.3.1.sql000066400000000000000000000143061455775703000165310ustar00rootroot00000000000000CREATE FUNCTION parse_type(type text, OUT typid oid, OUT typmod int4) RETURNS RECORD AS '$libdir/pgtap' LANGUAGE C STABLE STRICT; CREATE OR REPLACE FUNCTION format_type_string ( TEXT ) RETURNS TEXT AS $$ BEGIN RETURN format_type(p.typid, p.typmod) from parse_type($1) p; EXCEPTION WHEN OTHERS THEN RETURN NULL; END; $$ LANGUAGE PLPGSQL STABLE; -- col_type_is( schema, table, column, schema, type, description ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have_type TEXT := _get_col_ns_type($1, $2, $3); want_type TEXT; BEGIN IF have_type IS NULL THEN RETURN fail( $6 ) || E'\n' || diag ( ' Column ' || COALESCE(quote_ident($1) || '.', '') || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; IF quote_ident($4) = ANY(current_schemas(true)) THEN want_type := quote_ident($4) || '.' || format_type_string($5); ELSE want_type := format_type_string(quote_ident($4) || '.' || $5); END IF; IF want_type IS NULL THEN RETURN fail( $6 ) || E'\n' || diag ( ' Type ' || quote_ident($4) || '.' || $5 || ' does not exist' ); END IF; IF have_type = want_type THEN -- We're good to go. RETURN ok( true, $6 ); END IF; -- Wrong data type. tell 'em what we really got. RETURN ok( false, $6 ) || E'\n' || diag( ' have: ' || have_type || E'\n want: ' || want_type ); END; $$ LANGUAGE plpgsql; -- col_type_is( schema, table, column, schema, type ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_type_is( $1, $2, $3, $4, $5, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' should be type ' || quote_ident($4) || '.' || $5); $$ LANGUAGE SQL; -- col_type_is( schema, table, column, type, description ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have_type TEXT; want_type TEXT; BEGIN -- Get the data type. IF $1 IS NULL THEN have_type := _get_col_type($2, $3); ELSE have_type := _get_col_type($1, $2, $3); END IF; IF have_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Column ' || COALESCE(quote_ident($1) || '.', '') || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; want_type := format_type_string($4); IF want_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Type ' || $4 || ' does not exist' ); END IF; IF have_type = want_type THEN -- We're good to go. RETURN ok( true, $5 ); END IF; -- Wrong data type. tell 'em what we really got. RETURN ok( false, $5 ) || E'\n' || diag( ' have: ' || have_type || E'\n want: ' || want_type ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _cmp_types(oid, name) RETURNS BOOLEAN AS $$ SELECT pg_catalog.format_type($1, NULL) = _typename($2); $$ LANGUAGE sql; -- domain_type_is( schema, domain, schema, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, true); BEGIN IF actual_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; IF quote_ident($3) = ANY(current_schemas(true)) THEN RETURN is( actual_type, quote_ident($3) || '.' || _typename($4), $5); END IF; RETURN is( actual_type, _typename(quote_ident($3) || '.' || $4), $5); END; $$ LANGUAGE plpgsql; -- domain_type_is( schema, domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, false); BEGIN IF actual_type IS NULL THEN RETURN fail( $4 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; RETURN is( actual_type, _typename($3), $4 ); END; $$ LANGUAGE plpgsql; -- domain_type_is( domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1); BEGIN IF actual_type IS NULL THEN RETURN fail( $3 ) || E'\n' || diag ( ' Domain ' || $1 || ' does not exist' ); END IF; RETURN is( actual_type, _typename($2), $3 ); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( schema, domain, schema, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, true); BEGIN IF actual_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; IF quote_ident($3) = ANY(current_schemas(true)) THEN RETURN isnt( actual_type, quote_ident($3) || '.' || _typename($4), $5); END IF; RETURN isnt( actual_type, _typename(quote_ident($3) || '.' || $4), $5); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( schema, domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, false); BEGIN IF actual_type IS NULL THEN RETURN fail( $4 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; RETURN isnt( actual_type, _typename($3), $4 ); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1); BEGIN IF actual_type IS NULL THEN RETURN fail( $3 ) || E'\n' || diag ( ' Domain ' || $1 || ' does not exist' ); END IF; RETURN isnt( actual_type, _typename($2), $3 ); END; $$ LANGUAGE plpgsql; DROP FUNCTION _quote_ident_like(TEXT, TEXT); pgtap-1.3.2/sql/pgtap--1.3.1--1.3.2.sql000066400000000000000000000021531455775703000165300ustar00rootroot00000000000000DROP FUNCTION parse_type(type text, OUT typid oid, OUT typmod int4); CREATE OR REPLACE FUNCTION format_type_string ( TEXT ) RETURNS TEXT AS $$ DECLARE want_type TEXT := $1; typmodin_arg cstring[]; typmodin_func regproc; typmod int; BEGIN IF want_type::regtype = 'interval'::regtype THEN -- RAISE NOTICE 'cannot resolve: %', want_type; -- TODO RETURN want_type; END IF; -- Extract type modifier from type declaration and format as cstring[] literal. typmodin_arg := translate(substring(want_type FROM '[(][^")]+[)]'), '()', '{}'); -- Find typmodin function for want_type. SELECT typmodin INTO typmodin_func FROM pg_catalog.pg_type WHERE oid = want_type::regtype; IF typmodin_func = 0 THEN -- Easy: types without typemods. RETURN format_type(want_type::regtype, null); END IF; -- Get typemod via type-specific typmodin function. EXECUTE format('SELECT %I(%L)', typmodin_func, typmodin_arg) INTO typmod; RETURN format_type(want_type::regtype, typmod); EXCEPTION WHEN OTHERS THEN RETURN NULL; END; $$ LANGUAGE PLPGSQL STABLE; pgtap-1.3.2/sql/pgtap--unpackaged--0.91.0.sql000066400000000000000000001343571455775703000202720ustar00rootroot00000000000000ALTER EXTENSION pgtap ADD FUNCTION pg_version(); ALTER EXTENSION pgtap ADD FUNCTION pg_version_num(); ALTER EXTENSION pgtap ADD FUNCTION os_name(); ALTER EXTENSION pgtap ADD FUNCTION pgtap_version(); ALTER EXTENSION pgtap ADD FUNCTION plan( integer ); ALTER EXTENSION pgtap ADD FUNCTION no_plan(); ALTER EXTENSION pgtap ADD FUNCTION _get ( text ); ALTER EXTENSION pgtap ADD FUNCTION _get_latest ( text ); ALTER EXTENSION pgtap ADD FUNCTION _get_latest ( text, integer ); ALTER EXTENSION pgtap ADD FUNCTION _get_note ( text ); ALTER EXTENSION pgtap ADD FUNCTION _get_note ( integer ); ALTER EXTENSION pgtap ADD FUNCTION _set ( text, integer, text ); ALTER EXTENSION pgtap ADD FUNCTION _set ( text, integer ); ALTER EXTENSION pgtap ADD FUNCTION _set ( integer, integer ); ALTER EXTENSION pgtap ADD FUNCTION _add ( text, integer, text ); ALTER EXTENSION pgtap ADD FUNCTION _add ( text, integer ); ALTER EXTENSION pgtap ADD FUNCTION add_result ( bool, bool, text, text, text ); ALTER EXTENSION pgtap ADD FUNCTION num_failed (); ALTER EXTENSION pgtap ADD FUNCTION _finish ( INTEGER, INTEGER, INTEGER); ALTER EXTENSION pgtap ADD FUNCTION finish (); ALTER EXTENSION pgtap ADD FUNCTION diag ( msg text ); ALTER EXTENSION pgtap ADD FUNCTION diag ( msg anyelement ); ALTER EXTENSION pgtap ADD FUNCTION diag( VARIADIC text[] ); ALTER EXTENSION pgtap ADD FUNCTION diag( VARIADIC anyarray ); ALTER EXTENSION pgtap ADD FUNCTION ok ( boolean, text ); ALTER EXTENSION pgtap ADD FUNCTION ok ( boolean ); ALTER EXTENSION pgtap ADD FUNCTION is (anyelement, anyelement, text); ALTER EXTENSION pgtap ADD FUNCTION is (anyelement, anyelement); ALTER EXTENSION pgtap ADD FUNCTION isnt (anyelement, anyelement, text); ALTER EXTENSION pgtap ADD FUNCTION isnt (anyelement, anyelement); ALTER EXTENSION pgtap ADD FUNCTION _alike ( BOOLEAN, ANYELEMENT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION matches ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION matches ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION imatches ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION imatches ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION alike ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION alike ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION ialike ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION ialike ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION _unalike ( BOOLEAN, ANYELEMENT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION doesnt_match ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION doesnt_match ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION doesnt_imatch ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION doesnt_imatch ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION unalike ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION unalike ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION unialike ( anyelement, text, text ); ALTER EXTENSION pgtap ADD FUNCTION unialike ( anyelement, text ); ALTER EXTENSION pgtap ADD FUNCTION cmp_ok (anyelement, text, anyelement, text); ALTER EXTENSION pgtap ADD FUNCTION cmp_ok (anyelement, text, anyelement); ALTER EXTENSION pgtap ADD FUNCTION pass ( text ); ALTER EXTENSION pgtap ADD FUNCTION pass (); ALTER EXTENSION pgtap ADD FUNCTION fail ( text ); ALTER EXTENSION pgtap ADD FUNCTION fail (); ALTER EXTENSION pgtap ADD FUNCTION todo ( why text, how_many int ); ALTER EXTENSION pgtap ADD FUNCTION todo ( how_many int, why text ); ALTER EXTENSION pgtap ADD FUNCTION todo ( why text ); ALTER EXTENSION pgtap ADD FUNCTION todo ( how_many int ); ALTER EXTENSION pgtap ADD FUNCTION todo_start (text); ALTER EXTENSION pgtap ADD FUNCTION todo_start (); ALTER EXTENSION pgtap ADD FUNCTION in_todo (); ALTER EXTENSION pgtap ADD FUNCTION todo_end (); ALTER EXTENSION pgtap ADD FUNCTION _todo(); ALTER EXTENSION pgtap ADD FUNCTION skip ( why text, how_many int ); ALTER EXTENSION pgtap ADD FUNCTION skip ( text ); ALTER EXTENSION pgtap ADD FUNCTION skip( int, text ); ALTER EXTENSION pgtap ADD FUNCTION skip( int ); ALTER EXTENSION pgtap ADD FUNCTION _query( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, CHAR(5), TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, int4, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, int4, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ok ( TEXT, int4 ); ALTER EXTENSION pgtap ADD FUNCTION lives_ok ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION lives_ok ( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION performs_ok ( TEXT, NUMERIC, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION performs_ok ( TEXT, NUMERIC ); ALTER EXTENSION pgtap ADD FUNCTION performs_within ( TEXT, NUMERIC, NUMERIC, INT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION performs_within ( TEXT, NUMERIC, NUMERIC, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION performs_within ( TEXT, NUMERIC, NUMERIC, INT ); ALTER EXTENSION pgtap ADD FUNCTION performs_within ( TEXT, NUMERIC, NUMERIC ); ALTER EXTENSION pgtap ADD FUNCTION _rexists ( CHAR, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _rexists ( CHAR, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_table ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_table ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_table ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_table ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_table ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_table ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_view ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_view ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_view ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_view ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_view ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_view ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_sequence ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_sequence ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_sequence ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_sequence ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_sequence ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_sequence ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _cexists ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _cexists ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_column ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_column ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_column ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_column ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_column ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_column ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _col_is_null ( NAME, NAME, NAME, TEXT, bool ); ALTER EXTENSION pgtap ADD FUNCTION _col_is_null ( NAME, NAME, TEXT, bool ); ALTER EXTENSION pgtap ADD FUNCTION col_not_null ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_not_null ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_not_null ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_is_null ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_null ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_is_null ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION display_type ( OID, INTEGER ); ALTER EXTENSION pgtap ADD FUNCTION display_type ( NAME, OID, INTEGER ); ALTER EXTENSION pgtap ADD FUNCTION _get_col_type ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _get_col_type ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _get_col_ns_type ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _quote_ident_like(TEXT, TEXT); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_type_is ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _has_def ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _has_def ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_has_default ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_default ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_default ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_hasnt_default ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_hasnt_default ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_hasnt_default ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _def_is( TEXT, TEXT, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _cdi ( NAME, NAME, NAME, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _cdi ( NAME, NAME, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _cdi ( NAME, NAME, anyelement ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, NAME, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, anyelement ); ALTER EXTENSION pgtap ADD FUNCTION col_default_is ( NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION _hasc ( NAME, NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION _hasc ( NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION has_pk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_pk ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_pk ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_pk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_pk ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_pk ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _ident_array_to_string( name[], text ); ALTER EXTENSION pgtap ADD FUNCTION _pg_sv_column_array( OID, SMALLINT[] ); ALTER EXTENSION pgtap ADD FUNCTION _pg_sv_table_accessible( OID, OID ); ALTER EXTENSION pgtap ADD VIEW pg_all_foreign_keys; ALTER EXTENSION pgtap ADD FUNCTION _keys ( NAME, NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION _keys ( NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION _ckeys ( NAME, NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION _ckeys ( NAME, CHAR ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_pk ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_pk ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_fk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_fk ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_fk ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_fk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_fk ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_fk ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _fkexists ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _fkexists ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_fk ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_isnt_fk ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_unique ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_unique ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_unique ( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _constraint ( NAME, NAME, CHAR, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _constraint ( NAME, CHAR, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_is_unique ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_check ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_check ( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_check ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION col_has_check ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME[], NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME[], NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION fk_ok ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD VIEW tap_funky; ALTER EXTENSION pgtap ADD FUNCTION _got_func ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _got_func ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _got_func ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _got_func ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_function ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_function( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION has_function ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_function( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_function ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_function( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION has_function( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_function( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_function( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _pg_sv_type_array( OID[] ); ALTER EXTENSION pgtap ADD FUNCTION can ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION can ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION can ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION can ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _ikeys( NAME, NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION _ikeys( NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION _have_index( NAME, NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION _have_index( NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION _iexpr( NAME, NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION _iexpr( NAME, NAME); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME, NAME[], text ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME[], text ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _is_schema( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION has_index ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_index ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_index ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_index ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_index ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_unique ( NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION index_is_unique ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_unique ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_unique ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_primary ( NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION index_is_primary ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_primary ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_primary ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_clustered ( NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION is_clustered ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_clustered ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_clustered ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_type ( NAME, NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION index_is_type ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_type ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION index_is_type ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _trig ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _trig ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_trigger ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_trigger ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_trigger ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_trigger ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_trigger ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_trigger ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_trigger ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_trigger ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION trigger_is ( NAME, NAME, NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION trigger_is ( NAME, NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION trigger_is ( NAME, NAME, NAME, text ); ALTER EXTENSION pgtap ADD FUNCTION trigger_is ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_schema( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_schema( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_schema( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_schema( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_tablespace( NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_tablespace( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_tablespace( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_tablespace( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_tablespace( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _has_type( NAME, NAME, CHAR[] ); ALTER EXTENSION pgtap ADD FUNCTION _has_type( NAME, CHAR[] ); ALTER EXTENSION pgtap ADD FUNCTION has_type( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_type( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_type( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_type( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_type( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_type( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_type( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_type( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_domain( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_domain( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_domain( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_domain( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_domain( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_domain( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_domain( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_domain( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_enum( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_enum( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_enum( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_enum( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_enum( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_enum( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_enum( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_enum( NAME ); ALTER EXTENSION pgtap ADD FUNCTION enum_has_labels( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION enum_has_labels( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION enum_has_labels( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION enum_has_labels( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _has_role( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_role( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_role( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_role( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_role( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _has_user( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_user( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_user( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_user( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_user( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _is_super( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_superuser( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_superuser( NAME ); ALTER EXTENSION pgtap ADD FUNCTION isnt_superuser( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION isnt_superuser( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _has_group( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_group( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_group( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_group( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_group( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _grolist ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_member_of( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_member_of( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_member_of( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_member_of( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _cmp_types(oid, name); ALTER EXTENSION pgtap ADD FUNCTION _cast_exists ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _cast_exists ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _cast_exists ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_cast ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_cast ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _expand_context( char ); ALTER EXTENSION pgtap ADD FUNCTION _get_context( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION cast_context_is( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION cast_context_is( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _op_exists ( NAME, NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _op_exists ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _op_exists ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_operator ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_leftop ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_rightop ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _are ( text, name[], name[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION tablespaces_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION tablespaces_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION schemas_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION schemas_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _extras ( CHAR, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _extras ( CHAR, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _missing ( CHAR, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _missing ( CHAR, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION tables_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION tables_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION tables_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION tables_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION views_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION views_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION views_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION views_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION sequences_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION sequences_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION sequences_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION sequences_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION functions_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION functions_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION functions_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION functions_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION indexes_are( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION indexes_are( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION indexes_are( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION indexes_are( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION users_are( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION users_are( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION groups_are( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION groups_are( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION languages_are( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION languages_are( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _is_trusted( NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_language( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_language( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_language( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_language( NAME ); ALTER EXTENSION pgtap ADD FUNCTION language_is_trusted( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION language_is_trusted( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _opc_exists( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_opclass( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_opclass( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_opclass( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_opclass( NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_opclass( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_opclass( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_opclass( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_opclass( NAME ); ALTER EXTENSION pgtap ADD FUNCTION opclasses_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION opclasses_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION opclasses_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION opclasses_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION rules_are( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rules_are( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION rules_are( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rules_are( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _is_instead( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _is_instead( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_rule( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_rule( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION has_rule( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION has_rule( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_rule( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_rule( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_rule( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION hasnt_rule( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_instead( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_instead( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_instead( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_instead( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _expand_on( char ); ALTER EXTENSION pgtap ADD FUNCTION _contract_on( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _rule_on( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _rule_on( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_on( NAME, NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_on( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_on( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION rule_is_on( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _nosuch( NAME, NAME, NAME[]); ALTER EXTENSION pgtap ADD FUNCTION _func_compare( NAME, NAME, NAME[], anyelement, anyelement, TEXT); ALTER EXTENSION pgtap ADD FUNCTION _func_compare( NAME, NAME, NAME[], boolean, TEXT); ALTER EXTENSION pgtap ADD FUNCTION _func_compare( NAME, NAME, anyelement, anyelement, TEXT); ALTER EXTENSION pgtap ADD FUNCTION _func_compare( NAME, NAME, boolean, TEXT); ALTER EXTENSION pgtap ADD FUNCTION _lang ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _lang ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _lang ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _lang ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME, NAME[], NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME, NAME[], NAME ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME[], NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME[], NAME ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_lang_is( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _returns ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _returns ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _returns ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _returns ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION function_returns( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _definer ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _definer ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _definer ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _definer ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_definer ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_definer( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_definer ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_definer( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_definer ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_definer( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_definer( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_definer( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _agg ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _agg ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _agg ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _agg ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_aggregate( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _strict ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _strict ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _strict ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _strict ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_strict ( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_strict( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_strict ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_strict( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION is_strict ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_strict( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION is_strict( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_strict( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _expand_vol( char ); ALTER EXTENSION pgtap ADD FUNCTION _refine_vol( text ); ALTER EXTENSION pgtap ADD FUNCTION _vol ( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _vol ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _vol ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _vol ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME[], TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION volatility_is( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN ); ALTER EXTENSION pgtap ADD FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION check_test( TEXT, BOOLEAN, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION check_test( TEXT, BOOLEAN ); ALTER EXTENSION pgtap ADD FUNCTION findfuncs( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION findfuncs( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _runem( text[], boolean ); ALTER EXTENSION pgtap ADD FUNCTION _is_verbose(); ALTER EXTENSION pgtap ADD FUNCTION do_tap( name, text ); ALTER EXTENSION pgtap ADD FUNCTION do_tap( name ); ALTER EXTENSION pgtap ADD FUNCTION do_tap( text ); ALTER EXTENSION pgtap ADD FUNCTION do_tap( ); ALTER EXTENSION pgtap ADD FUNCTION _currtest(); ALTER EXTENSION pgtap ADD FUNCTION _cleanup(); ALTER EXTENSION pgtap ADD FUNCTION diag_test_name(TEXT); ALTER EXTENSION pgtap ADD FUNCTION _runner( text[], text[], text[], text[], text[] ); ALTER EXTENSION pgtap ADD FUNCTION runtests( NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION runtests( NAME ); ALTER EXTENSION pgtap ADD FUNCTION runtests( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION runtests( ); ALTER EXTENSION pgtap ADD FUNCTION _temptable ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _temptable ( anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _temptypes( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _docomp( TEXT, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _relcomp( TEXT, anyarray, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_eq( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_eq( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_eq( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_eq( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION bag_eq( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_eq( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_eq( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_eq( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION _do_ne( TEXT, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _relne( TEXT, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION _relne( TEXT, anyarray, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_ne( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_ne( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_ne( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_ne( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION bag_ne( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_ne( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_ne( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_ne( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_has( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_has( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_has( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_has( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_hasnt( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION set_hasnt( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_hasnt( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION bag_hasnt( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, refcursor, text ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, refcursor ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, refcursor, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( TEXT, refcursor ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_eq( refcursor, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, refcursor, text ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, refcursor ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, refcursor, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( TEXT, refcursor ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, anyarray, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION results_ne( refcursor, anyarray ); ALTER EXTENSION pgtap ADD FUNCTION isa_ok( anyelement, regtype, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION isa_ok( anyelement, regtype ); ALTER EXTENSION pgtap ADD FUNCTION is_empty( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION is_empty( TEXT ); ALTER EXTENSION pgtap ADD FUNCTION collect_tap( VARIADIC text[] ); ALTER EXTENSION pgtap ADD FUNCTION collect_tap( VARCHAR[] ); ALTER EXTENSION pgtap ADD FUNCTION _tlike ( BOOLEAN, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_like ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_like ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ilike ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_ilike ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_matching ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_matching ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_imatching ( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION throws_imatching ( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION roles_are( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION roles_are( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _types_are ( NAME, NAME[], TEXT, CHAR[] ); ALTER EXTENSION pgtap ADD FUNCTION types_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION types_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _types_are ( NAME[], TEXT, CHAR[] ); ALTER EXTENSION pgtap ADD FUNCTION types_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION types_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION domains_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domains_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION domains_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domains_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION enums_are ( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION enums_are ( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION enums_are ( NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION enums_are ( NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _dexists ( NAME, NAME ); ALTER EXTENSION pgtap ADD FUNCTION _dexists ( NAME ); ALTER EXTENSION pgtap ADD FUNCTION _get_dtype( NAME, TEXT, BOOLEAN ); ALTER EXTENSION pgtap ADD FUNCTION _get_dtype( NAME ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( NAME, TEXT, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( NAME, TEXT, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( NAME, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_is( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( NAME, TEXT, NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( NAME, TEXT, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( NAME, TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( NAME, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( TEXT, TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION domain_type_isnt( TEXT, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION row_eq( TEXT, anyelement, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION row_eq( TEXT, anyelement ); ALTER EXTENSION pgtap ADD FUNCTION triggers_are( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION triggers_are( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION triggers_are( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION triggers_are( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _areni ( text, text[], text[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION casts_are ( TEXT[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION casts_are ( TEXT[] ); ALTER EXTENSION pgtap ADD FUNCTION display_oper ( NAME, OID ); ALTER EXTENSION pgtap ADD FUNCTION operators_are( NAME, TEXT[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION operators_are ( NAME, TEXT[] ); ALTER EXTENSION pgtap ADD FUNCTION operators_are( TEXT[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION operators_are ( TEXT[] ); ALTER EXTENSION pgtap ADD FUNCTION columns_are( NAME, NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION columns_are( NAME, NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION columns_are( NAME, NAME[], TEXT ); ALTER EXTENSION pgtap ADD FUNCTION columns_are( NAME, NAME[] ); ALTER EXTENSION pgtap ADD FUNCTION _get_db_owner( NAME ); ALTER EXTENSION pgtap ADD FUNCTION db_owner_is ( NAME, NAME, TEXT ); ALTER EXTENSION pgtap ADD FUNCTION db_owner_is ( NAME, NAME ); pgtap-1.3.2/sql/pgtap.sql.in000066400000000000000000013165501455775703000157200ustar00rootroot00000000000000-- This file defines pgTAP, a collection of functions for TAP-based unit -- testing. It is distributed under the revised FreeBSD license. -- -- The home page for the pgTAP project is: -- -- https://pgtap.org/ CREATE OR REPLACE FUNCTION pg_version() RETURNS text AS 'SELECT current_setting(''server_version'')' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION pg_version_num() RETURNS integer AS $$ SELECT current_setting('server_version_num')::integer; $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION os_name() RETURNS TEXT AS 'SELECT ''__OS__''::text;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION pgtap_version() RETURNS NUMERIC AS 'SELECT __VERSION__;' LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION plan( integer ) RETURNS TEXT AS $$ DECLARE rcount INTEGER; BEGIN BEGIN EXECUTE ' CREATE TEMP SEQUENCE __tcache___id_seq; CREATE TEMP TABLE __tcache__ ( id INTEGER NOT NULL DEFAULT nextval(''__tcache___id_seq''), label TEXT NOT NULL, value INTEGER NOT NULL, note TEXT NOT NULL DEFAULT '''' ); CREATE UNIQUE INDEX __tcache___key ON __tcache__(id); GRANT ALL ON TABLE __tcache__ TO PUBLIC; GRANT ALL ON TABLE __tcache___id_seq TO PUBLIC; CREATE TEMP SEQUENCE __tresults___numb_seq; GRANT ALL ON TABLE __tresults___numb_seq TO PUBLIC; '; EXCEPTION WHEN duplicate_table THEN -- Raise an exception if there's already a plan. EXECUTE 'SELECT TRUE FROM __tcache__ WHERE label = ''plan'''; GET DIAGNOSTICS rcount = ROW_COUNT; IF rcount > 0 THEN RAISE EXCEPTION 'You tried to plan twice!'; END IF; END; -- Save the plan and return. PERFORM _set('plan', $1 ); PERFORM _set('failed', 0 ); RETURN '1..' || $1; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION no_plan() RETURNS SETOF boolean AS $$ BEGIN PERFORM plan(0); RETURN; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _get ( text ) RETURNS integer AS $$ DECLARE ret integer; BEGIN EXECUTE 'SELECT value FROM __tcache__ WHERE label = ' || quote_literal($1) || ' LIMIT 1' INTO ret; RETURN ret; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _get_latest ( text ) RETURNS integer[] AS $$ DECLARE ret integer[]; BEGIN EXECUTE 'SELECT ARRAY[id, value] FROM __tcache__ WHERE label = ' || quote_literal($1) || ' AND id = (SELECT MAX(id) FROM __tcache__ WHERE label = ' || quote_literal($1) || ') LIMIT 1' INTO ret; RETURN ret; EXCEPTION WHEN undefined_table THEN RAISE EXCEPTION 'You tried to run a test without a plan! Gotta have a plan'; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _get_latest ( text, integer ) RETURNS integer AS $$ DECLARE ret integer; BEGIN EXECUTE 'SELECT MAX(id) FROM __tcache__ WHERE label = ' || quote_literal($1) || ' AND value = ' || $2 INTO ret; RETURN ret; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _get_note ( text ) RETURNS text AS $$ DECLARE ret text; BEGIN EXECUTE 'SELECT note FROM __tcache__ WHERE label = ' || quote_literal($1) || ' LIMIT 1' INTO ret; RETURN ret; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _get_note ( integer ) RETURNS text AS $$ DECLARE ret text; BEGIN EXECUTE 'SELECT note FROM __tcache__ WHERE id = ' || $1 || ' LIMIT 1' INTO ret; RETURN ret; END; $$ LANGUAGE plpgsql strict; CREATE OR REPLACE FUNCTION _set ( text, integer, text ) RETURNS integer AS $$ DECLARE rcount integer; BEGIN EXECUTE 'UPDATE __tcache__ SET value = ' || $2 || CASE WHEN $3 IS NULL THEN '' ELSE ', note = ' || quote_literal($3) END || ' WHERE label = ' || quote_literal($1); GET DIAGNOSTICS rcount = ROW_COUNT; IF rcount = 0 THEN RETURN _add( $1, $2, $3 ); END IF; RETURN $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _set ( text, integer ) RETURNS integer AS $$ SELECT _set($1, $2, '') $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _set ( integer, integer ) RETURNS integer AS $$ BEGIN EXECUTE 'UPDATE __tcache__ SET value = ' || $2 || ' WHERE id = ' || $1; RETURN $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _add ( text, integer, text ) RETURNS integer AS $$ BEGIN EXECUTE 'INSERT INTO __tcache__ (label, value, note) values (' || quote_literal($1) || ', ' || $2 || ', ' || quote_literal(COALESCE($3, '')) || ')'; RETURN $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _add ( text, integer ) RETURNS integer AS $$ SELECT _add($1, $2, '') $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION add_result ( bool, bool, text, text, text ) RETURNS integer AS $$ BEGIN IF NOT $1 THEN PERFORM _set('failed', _get('failed') + 1); END IF; RETURN nextval('__tresults___numb_seq'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION num_failed () RETURNS INTEGER AS $$ SELECT _get('failed'); $$ LANGUAGE SQL strict; CREATE OR REPLACE FUNCTION _finish (INTEGER, INTEGER, INTEGER, BOOLEAN DEFAULT NULL) RETURNS SETOF TEXT AS $$ DECLARE curr_test ALIAS FOR $1; exp_tests INTEGER := $2; num_faild ALIAS FOR $3; plural CHAR; raise_ex ALIAS FOR $4; BEGIN plural := CASE exp_tests WHEN 1 THEN '' ELSE 's' END; IF curr_test IS NULL THEN RAISE EXCEPTION '# No tests run!'; END IF; IF exp_tests = 0 OR exp_tests IS NULL THEN -- No plan. Output one now. exp_tests = curr_test; RETURN NEXT '1..' || exp_tests; END IF; IF curr_test <> exp_tests THEN RETURN NEXT diag( 'Looks like you planned ' || exp_tests || ' test' || plural || ' but ran ' || curr_test ); ELSIF num_faild > 0 THEN IF raise_ex THEN RAISE EXCEPTION '% test% failed of %', num_faild, CASE num_faild WHEN 1 THEN '' ELSE 's' END, exp_tests; END IF; RETURN NEXT diag( 'Looks like you failed ' || num_faild || ' test' || CASE num_faild WHEN 1 THEN '' ELSE 's' END || ' of ' || exp_tests ); ELSE END IF; RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION finish (exception_on_failure BOOLEAN DEFAULT NULL) RETURNS SETOF TEXT AS $$ SELECT * FROM _finish( _get('curr_test'), _get('plan'), num_failed(), $1 ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION diag ( msg text ) RETURNS TEXT AS $$ SELECT '# ' || replace( replace( replace( $1, E'\r\n', E'\n# ' ), E'\n', E'\n# ' ), E'\r', E'\n# ' ); $$ LANGUAGE sql strict; CREATE OR REPLACE FUNCTION diag ( msg anyelement ) RETURNS TEXT AS $$ SELECT diag($1::text); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION diag( VARIADIC text[] ) RETURNS TEXT AS $$ SELECT diag(array_to_string($1, '')); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION diag( VARIADIC anyarray ) RETURNS TEXT AS $$ SELECT diag(array_to_string($1, '')); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION ok ( boolean, text ) RETURNS TEXT AS $$ DECLARE aok ALIAS FOR $1; descr text := $2; test_num INTEGER; todo_why TEXT; ok BOOL; BEGIN todo_why := _todo(); ok := CASE WHEN aok = TRUE THEN aok WHEN todo_why IS NULL THEN COALESCE(aok, false) ELSE TRUE END; IF _get('plan') IS NULL THEN RAISE EXCEPTION 'You tried to run a test without a plan! Gotta have a plan'; END IF; test_num := add_result( ok, COALESCE(aok, false), descr, CASE WHEN todo_why IS NULL THEN '' ELSE 'todo' END, COALESCE(todo_why, '') ); RETURN (CASE aok WHEN TRUE THEN '' ELSE 'not ' END) || 'ok ' || _set( 'curr_test', test_num ) || CASE descr WHEN '' THEN '' ELSE COALESCE( ' - ' || substr(diag( descr ), 3), '' ) END || COALESCE( ' ' || diag( 'TODO ' || todo_why ), '') || CASE aok WHEN TRUE THEN '' ELSE E'\n' || diag('Failed ' || CASE WHEN todo_why IS NULL THEN '' ELSE '(TODO) ' END || 'test ' || test_num || CASE descr WHEN '' THEN '' ELSE COALESCE(': "' || descr || '"', '') END ) || CASE WHEN aok IS NULL THEN E'\n' || diag(' (test result was NULL)') ELSE '' END END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION ok ( boolean ) RETURNS TEXT AS $$ SELECT ok( $1, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION is (anyelement, anyelement, text) RETURNS TEXT AS $$ DECLARE result BOOLEAN; output TEXT; BEGIN -- Would prefer $1 IS NOT DISTINCT FROM, but that's not supported by 8.1. result := NOT $1 IS DISTINCT FROM $2; output := ok( result, $3 ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( ' have: ' || CASE WHEN $1 IS NULL THEN 'NULL' ELSE $1::text END || E'\n want: ' || CASE WHEN $2 IS NULL THEN 'NULL' ELSE $2::text END ) END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION is (anyelement, anyelement) RETURNS TEXT AS $$ SELECT is( $1, $2, NULL); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION isnt (anyelement, anyelement, text) RETURNS TEXT AS $$ DECLARE result BOOLEAN; output TEXT; BEGIN result := $1 IS DISTINCT FROM $2; output := ok( result, $3 ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( ' have: ' || COALESCE( $1::text, 'NULL' ) || E'\n want: anything else' ) END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION isnt (anyelement, anyelement) RETURNS TEXT AS $$ SELECT isnt( $1, $2, NULL); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _alike ( BOOLEAN, ANYELEMENT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE result ALIAS FOR $1; got ALIAS FOR $2; rx ALIAS FOR $3; descr ALIAS FOR $4; output TEXT; BEGIN output := ok( result, descr ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( ' ' || COALESCE( quote_literal(got), 'NULL' ) || E'\n doesn''t match: ' || COALESCE( quote_literal(rx), 'NULL' ) ) END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION matches ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~ $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION matches ( anyelement, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~ $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION imatches ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~* $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION imatches ( anyelement, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~* $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION alike ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~~ $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION alike ( anyelement, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~~ $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION ialike ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~~* $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION ialike ( anyelement, text ) RETURNS TEXT AS $$ SELECT _alike( $1 ~~* $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _unalike ( BOOLEAN, ANYELEMENT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE result ALIAS FOR $1; got ALIAS FOR $2; rx ALIAS FOR $3; descr ALIAS FOR $4; output TEXT; BEGIN output := ok( result, descr ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( ' ' || COALESCE( quote_literal(got), 'NULL' ) || E'\n matches: ' || COALESCE( quote_literal(rx), 'NULL' ) ) END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION doesnt_match ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~ $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION doesnt_match ( anyelement, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~ $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION doesnt_imatch ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~* $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION doesnt_imatch ( anyelement, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~* $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION unalike ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~~ $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION unalike ( anyelement, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~~ $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION unialike ( anyelement, text, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~~* $2, $1, $2, $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION unialike ( anyelement, text ) RETURNS TEXT AS $$ SELECT _unalike( $1 !~~* $2, $1, $2, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION cmp_ok (anyelement, text, anyelement, text) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; op ALIAS FOR $2; want ALIAS FOR $3; descr ALIAS FOR $4; result BOOLEAN; output TEXT; BEGIN EXECUTE 'SELECT ' || COALESCE(quote_literal( have ), 'NULL') || '::' || pg_typeof(have) || ' ' || op || ' ' || COALESCE(quote_literal( want ), 'NULL') || '::' || pg_typeof(want) INTO result; output := ok( COALESCE(result, FALSE), descr ); RETURN output || CASE result WHEN TRUE THEN '' ELSE E'\n' || diag( ' ' || COALESCE( quote_literal(have), 'NULL' ) || E'\n ' || op || E'\n ' || COALESCE( quote_literal(want), 'NULL' ) ) END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION cmp_ok (anyelement, text, anyelement) RETURNS TEXT AS $$ SELECT cmp_ok( $1, $2, $3, NULL ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION pass ( text ) RETURNS TEXT AS $$ SELECT ok( TRUE, $1 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION pass () RETURNS TEXT AS $$ SELECT ok( TRUE, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION fail ( text ) RETURNS TEXT AS $$ SELECT ok( FALSE, $1 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION fail () RETURNS TEXT AS $$ SELECT ok( FALSE, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION todo ( why text, how_many int ) RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', COALESCE(how_many, 1), COALESCE(why, '')); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo ( how_many int, why text ) RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', COALESCE(how_many, 1), COALESCE(why, '')); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo ( why text ) RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', 1, COALESCE(why, '')); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo ( how_many int ) RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', COALESCE(how_many, 1), ''); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo_start (text) RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', -1, COALESCE($1, '')); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo_start () RETURNS SETOF BOOLEAN AS $$ BEGIN PERFORM _add('todo', -1, ''); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION in_todo () RETURNS BOOLEAN AS $$ DECLARE todos integer; BEGIN todos := _get('todo'); RETURN CASE WHEN todos IS NULL THEN FALSE ELSE TRUE END; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION todo_end () RETURNS SETOF BOOLEAN AS $$ DECLARE id integer; BEGIN id := _get_latest( 'todo', -1 ); IF id IS NULL THEN RAISE EXCEPTION 'todo_end() called without todo_start()'; END IF; EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || id; RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _todo() RETURNS TEXT AS $$ DECLARE todos INT[]; note text; BEGIN -- Get the latest id and value, because todo() might have been called -- again before the todos ran out for the first call to todo(). This -- allows them to nest. todos := _get_latest('todo'); IF todos IS NULL THEN -- No todos. RETURN NULL; END IF; IF todos[2] = 0 THEN -- Todos depleted. Clean up. EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || todos[1]; RETURN NULL; END IF; -- Decrement the count of counted todos and return the reason. IF todos[2] <> -1 THEN PERFORM _set(todos[1], todos[2] - 1); END IF; note := _get_note(todos[1]); IF todos[2] = 1 THEN -- This was the last todo, so delete the record. EXECUTE 'DELETE FROM __tcache__ WHERE id = ' || todos[1]; END IF; RETURN note; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION skip ( why text, how_many int ) RETURNS TEXT AS $$ DECLARE output TEXT[]; BEGIN output := '{}'; FOR i IN 1..how_many LOOP output = array_append( output, ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE( ' ' || why, '') ) ); END LOOP; RETURN array_to_string(output, E'\n'); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION skip ( text ) RETURNS TEXT AS $$ SELECT ok( TRUE ) || ' ' || diag( 'SKIP' || COALESCE(' ' || $1, '') ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION skip( int, text ) RETURNS TEXT AS 'SELECT skip($2, $1)' LANGUAGE sql; CREATE OR REPLACE FUNCTION skip( int ) RETURNS TEXT AS 'SELECT skip(NULL, $1)' LANGUAGE sql; CREATE OR REPLACE FUNCTION _query( TEXT ) RETURNS TEXT AS $$ SELECT CASE WHEN $1 LIKE '"%' OR $1 !~ '[[:space:]]' THEN 'EXECUTE ' || $1 ELSE $1 END; $$ LANGUAGE SQL; -- throws_ok ( sql, errcode, errmsg, description ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, CHAR(5), TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE query TEXT := _query($1); errcode ALIAS FOR $2; errmsg ALIAS FOR $3; desctext ALIAS FOR $4; descr TEXT; BEGIN descr := COALESCE( desctext, 'threw ' || errcode || ': ' || errmsg, 'threw ' || errcode, 'threw ' || errmsg, 'threw an exception' ); EXECUTE query; RETURN ok( FALSE, descr ) || E'\n' || diag( ' caught: no exception' || E'\n wanted: ' || COALESCE( errcode, 'an exception' ) ); EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN IF (errcode IS NULL OR SQLSTATE = errcode) AND ( errmsg IS NULL OR SQLERRM = errmsg) THEN -- The expected errcode and/or message was thrown. RETURN ok( TRUE, descr ); ELSE -- This was not the expected errcode or errmsg. RETURN ok( FALSE, descr ) || E'\n' || diag( ' caught: ' || SQLSTATE || ': ' || SQLERRM || E'\n wanted: ' || COALESCE( errcode, 'an exception' ) || COALESCE( ': ' || errmsg, '') ); END IF; END; $$ LANGUAGE plpgsql; -- throws_ok ( sql, errcode, errmsg ) -- throws_ok ( sql, errmsg, description ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN IF octet_length($2) = 5 THEN RETURN throws_ok( $1, $2::char(5), $3, NULL ); ELSE RETURN throws_ok( $1, NULL, $2, $3 ); END IF; END; $$ LANGUAGE plpgsql; -- throws_ok ( query, errcode ) -- throws_ok ( query, errmsg ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN IF octet_length($2) = 5 THEN RETURN throws_ok( $1, $2::char(5), NULL, NULL ); ELSE RETURN throws_ok( $1, NULL, $2, NULL ); END IF; END; $$ LANGUAGE plpgsql; -- throws_ok ( sql ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT ) RETURNS TEXT AS $$ SELECT throws_ok( $1, NULL, NULL, NULL ); $$ LANGUAGE SQL; -- Magically cast integer error codes. -- throws_ok ( sql, errcode, errmsg, description ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT throws_ok( $1, $2::char(5), $3, $4 ); $$ LANGUAGE SQL; -- throws_ok ( sql, errcode, errmsg ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4, TEXT ) RETURNS TEXT AS $$ SELECT throws_ok( $1, $2::char(5), $3, NULL ); $$ LANGUAGE SQL; -- throws_ok ( sql, errcode ) CREATE OR REPLACE FUNCTION throws_ok ( TEXT, int4 ) RETURNS TEXT AS $$ SELECT throws_ok( $1, $2::char(5), NULL, NULL ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _error_diag( TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT COALESCE( COALESCE( NULLIF($1, '') || ': ', '' ) || COALESCE( NULLIF($2, ''), '' ), 'NO ERROR FOUND' ) || COALESCE(E'\n DETAIL: ' || nullif($3, ''), '') || COALESCE(E'\n HINT: ' || nullif($4, ''), '') || COALESCE(E'\n SCHEMA: ' || nullif($6, ''), '') || COALESCE(E'\n TABLE: ' || nullif($7, ''), '') || COALESCE(E'\n COLUMN: ' || nullif($8, ''), '') || COALESCE(E'\n CONSTRAINT: ' || nullif($9, ''), '') || COALESCE(E'\n TYPE: ' || nullif($10, ''), '') -- We need to manually indent all the context lines || COALESCE(E'\n CONTEXT:\n' || regexp_replace(NULLIF( $5, ''), '^', ' ', 'gn' ), ''); $$ LANGUAGE sql IMMUTABLE; -- lives_ok( sql, description ) CREATE OR REPLACE FUNCTION lives_ok ( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE code TEXT := _query($1); descr ALIAS FOR $2; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN EXECUTE code; RETURN ok( TRUE, descr ); EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN -- There should have been no exception. GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; RETURN ok( FALSE, descr ) || E'\n' || diag( ' died: ' || _error_diag(SQLSTATE, SQLERRM, detail, hint, context, schname, tabname, colname, chkname, typname) ); END; $$ LANGUAGE plpgsql; -- lives_ok( sql ) CREATE OR REPLACE FUNCTION lives_ok ( TEXT ) RETURNS TEXT AS $$ SELECT lives_ok( $1, NULL ); $$ LANGUAGE SQL; -- performs_ok ( sql, milliseconds, description ) CREATE OR REPLACE FUNCTION performs_ok ( TEXT, NUMERIC, TEXT ) RETURNS TEXT AS $$ DECLARE query TEXT := _query($1); max_time ALIAS FOR $2; descr ALIAS FOR $3; starts_at TEXT; act_time NUMERIC; BEGIN starts_at := timeofday(); EXECUTE query; act_time := extract( millisecond from timeofday()::timestamptz - starts_at::timestamptz); IF act_time < max_time THEN RETURN ok(TRUE, descr); END IF; RETURN ok( FALSE, descr ) || E'\n' || diag( ' runtime: ' || act_time || ' ms' || E'\n exceeds: ' || max_time || ' ms' ); END; $$ LANGUAGE plpgsql; -- performs_ok ( sql, milliseconds ) CREATE OR REPLACE FUNCTION performs_ok ( TEXT, NUMERIC ) RETURNS TEXT AS $$ SELECT performs_ok( $1, $2, 'Should run in less than ' || $2 || ' ms' ); $$ LANGUAGE sql; -- Convenience function to run a query many times and returns -- the middle set of those times as defined by the last argument -- e.g. _time_trials('SELECT 1', 100, 0.8) will execute 'SELECT 1' -- 100 times, and return the execution times for the middle 80 runs -- -- I could have left this logic in performs_within, but I have -- plans to hook into this function for other purposes outside -- of pgTAP CREATE TYPE _time_trial_type AS (a_time NUMERIC); CREATE OR REPLACE FUNCTION _time_trials(TEXT, INT, NUMERIC) RETURNS SETOF _time_trial_type AS $$ DECLARE query TEXT := _query($1); iterations ALIAS FOR $2; return_percent ALIAS FOR $3; start_time TEXT; act_time NUMERIC; times NUMERIC[]; offset_it INT; limit_it INT; offset_percent NUMERIC; a_time _time_trial_type; BEGIN -- Execute the query over and over FOR i IN 1..iterations LOOP start_time := timeofday(); EXECUTE query; -- Store the execution time for the run in an array of times times[i] := extract(millisecond from timeofday()::timestamptz - start_time::timestamptz); END LOOP; offset_percent := (1.0 - return_percent) / 2.0; -- Ensure that offset skips the bottom X% of runs, or set it to 0 SELECT GREATEST((offset_percent * iterations)::int, 0) INTO offset_it; -- Ensure that with limit the query to returning only the middle X% of runs SELECT GREATEST((return_percent * iterations)::int, 1) INTO limit_it; FOR a_time IN SELECT times[i] FROM generate_series(array_lower(times, 1), array_upper(times, 1)) i ORDER BY 1 OFFSET offset_it LIMIT limit_it LOOP RETURN NEXT a_time; END LOOP; END; $$ LANGUAGE plpgsql; -- performs_within( sql, average_milliseconds, within, iterations, description ) CREATE OR REPLACE FUNCTION performs_within(TEXT, NUMERIC, NUMERIC, INT, TEXT) RETURNS TEXT AS $$ DECLARE query TEXT := _query($1); expected_avg ALIAS FOR $2; within ALIAS FOR $3; iterations ALIAS FOR $4; descr ALIAS FOR $5; avg_time NUMERIC; BEGIN SELECT avg(a_time) FROM _time_trials(query, iterations, 0.8) t1 INTO avg_time; IF abs(avg_time - expected_avg) < within THEN RETURN ok(TRUE, descr); END IF; RETURN ok(FALSE, descr) || E'\n' || diag(' average runtime: ' || avg_time || ' ms' || E'\n desired average: ' || expected_avg || ' +/- ' || within || ' ms' ); END; $$ LANGUAGE plpgsql; -- performs_within( sql, average_milliseconds, within, iterations ) CREATE OR REPLACE FUNCTION performs_within(TEXT, NUMERIC, NUMERIC, INT) RETURNS TEXT AS $$ SELECT performs_within( $1, $2, $3, $4, 'Should run within ' || $2 || ' +/- ' || $3 || ' ms'); $$ LANGUAGE sql; -- performs_within( sql, average_milliseconds, within, description ) CREATE OR REPLACE FUNCTION performs_within(TEXT, NUMERIC, NUMERIC, TEXT) RETURNS TEXT AS $$ SELECT performs_within( $1, $2, $3, 10, $4 ); $$ LANGUAGE sql; -- performs_within( sql, average_milliseconds, within ) CREATE OR REPLACE FUNCTION performs_within(TEXT, NUMERIC, NUMERIC) RETURNS TEXT AS $$ SELECT performs_within( $1, $2, $3, 10, 'Should run within ' || $2 || ' +/- ' || $3 || ' ms'); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _relexists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _relexists ( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 ); $$ LANGUAGE SQL; -- has_relation( schema, relation, description ) CREATE OR REPLACE FUNCTION has_relation ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _relexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_relation( relation, description ) CREATE OR REPLACE FUNCTION has_relation ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _relexists( $1 ), $2 ); $$ LANGUAGE SQL; -- has_relation( relation ) CREATE OR REPLACE FUNCTION has_relation ( NAME ) RETURNS TEXT AS $$ SELECT has_relation( $1, 'Relation ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_relation( schema, relation, description ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _relexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_relation( relation, description ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _relexists( $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_relation( relation ) CREATE OR REPLACE FUNCTION hasnt_relation ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_relation( $1, 'Relation ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR[], NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR[], NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE c.relkind = ANY($1) AND pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT _rexists(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rexists ( CHAR, NAME ) RETURNS BOOLEAN AS $$ SELECT _rexists(ARRAY[$1], $2); $$ LANGUAGE SQL; -- has_table( schema, table, description ) CREATE OR REPLACE FUNCTION has_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_table( schema, table ) CREATE OR REPLACE FUNCTION has_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_table( table, description ) CREATE OR REPLACE FUNCTION has_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( '{r,p}'::char[], $1 ), $2 ); $$ LANGUAGE SQL; -- has_table( table ) CREATE OR REPLACE FUNCTION has_table ( NAME ) RETURNS TEXT AS $$ SELECT has_table( $1, 'Table ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_table( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_table( schema, table ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1, $2 ), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_table( table, description ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( '{r,p}'::char[], $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_table( table ) CREATE OR REPLACE FUNCTION hasnt_table ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_table( $1, 'Table ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- has_view( schema, view, description ) CREATE OR REPLACE FUNCTION has_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'v', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_view( schema, view ) CREATE OR REPLACE FUNCTION has_view ( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_view ( $1, $2, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_view( view, description ) CREATE OR REPLACE FUNCTION has_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'v', $1 ), $2 ); $$ LANGUAGE SQL; -- has_view( view ) CREATE OR REPLACE FUNCTION has_view ( NAME ) RETURNS TEXT AS $$ SELECT has_view( $1, 'View ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_view( schema, view, description ) CREATE OR REPLACE FUNCTION hasnt_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'v', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_view( schema, table ) CREATE OR REPLACE FUNCTION hasnt_view ( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_view( $1, $2, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_view( view, description ) CREATE OR REPLACE FUNCTION hasnt_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'v', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_view( view ) CREATE OR REPLACE FUNCTION hasnt_view ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_view( $1, 'View ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- has_sequence( schema, sequence, description ) CREATE OR REPLACE FUNCTION has_sequence ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'S', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_sequence( schema, sequence ) CREATE OR REPLACE FUNCTION has_sequence ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'S', $1, $2 ), 'Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_sequence( sequence, description ) CREATE OR REPLACE FUNCTION has_sequence ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'S', $1 ), $2 ); $$ LANGUAGE SQL; -- has_sequence( sequence ) CREATE OR REPLACE FUNCTION has_sequence ( NAME ) RETURNS TEXT AS $$ SELECT has_sequence( $1, 'Sequence ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_sequence( schema, sequence, description ) CREATE OR REPLACE FUNCTION hasnt_sequence ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'S', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_sequence( sequence, description ) CREATE OR REPLACE FUNCTION hasnt_sequence ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'S', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_sequence( sequence ) CREATE OR REPLACE FUNCTION hasnt_sequence ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_sequence( $1, 'Sequence ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- has_foreign_table( schema, table, description ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_foreign_table( schema, table ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1, $2 ), 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_foreign_table( table, description ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'f', $1 ), $2 ); $$ LANGUAGE SQL; -- has_foreign_table( table ) CREATE OR REPLACE FUNCTION has_foreign_table ( NAME ) RETURNS TEXT AS $$ SELECT has_foreign_table( $1, 'Foreign table ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_foreign_table( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_foreign_table( schema, table ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1, $2 ), 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_foreign_table( table, description ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'f', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_foreign_table( table ) CREATE OR REPLACE FUNCTION hasnt_foreign_table ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_foreign_table( $1, 'Foreign table ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- has_composite( schema, type, description ) CREATE OR REPLACE FUNCTION has_composite ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'c', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_composite( type, description ) CREATE OR REPLACE FUNCTION has_composite ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'c', $1 ), $2 ); $$ LANGUAGE SQL; -- has_composite( type ) CREATE OR REPLACE FUNCTION has_composite ( NAME ) RETURNS TEXT AS $$ SELECT has_composite( $1, 'Composite type ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_composite( schema, type, description ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'c', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_composite( type, description ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'c', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_composite( type ) CREATE OR REPLACE FUNCTION hasnt_composite ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_composite( $1, 'Composite type ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _cexists ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _cexists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE c.relname = $1 AND pg_catalog.pg_table_is_visible(c.oid) AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2 ); $$ LANGUAGE SQL; -- has_column( schema, table, column, description ) CREATE OR REPLACE FUNCTION has_column ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _cexists( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- has_column( table, column, description ) CREATE OR REPLACE FUNCTION has_column ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _cexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_column( table, column ) CREATE OR REPLACE FUNCTION has_column ( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_column( $1, $2, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_column( schema, table, column, description ) CREATE OR REPLACE FUNCTION hasnt_column ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _cexists( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- hasnt_column( table, column, description ) CREATE OR REPLACE FUNCTION hasnt_column ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _cexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_column( table, column ) CREATE OR REPLACE FUNCTION hasnt_column ( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_column( $1, $2, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- _col_is_null( schema, table, column, desc, null ) CREATE OR REPLACE FUNCTION _col_is_null ( NAME, NAME, NAME, TEXT, bool ) RETURNS TEXT AS $$ DECLARE qcol CONSTANT text := quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3); c_desc CONSTANT text := coalesce( $4, 'Column ' || qcol || ' should ' || CASE WHEN $5 THEN 'be NOT' ELSE 'allow' END || ' NULL' ); BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( c_desc ) || E'\n' || diag (' Column ' || qcol || ' does not exist' ); END IF; RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3 AND a.attnotnull = $5 ), c_desc ); END; $$ LANGUAGE plpgsql; -- _col_is_null( table, column, desc, null ) CREATE OR REPLACE FUNCTION _col_is_null ( NAME, NAME, TEXT, bool ) RETURNS TEXT AS $$ DECLARE qcol CONSTANT text := quote_ident($1) || '.' || quote_ident($2); c_desc CONSTANT text := coalesce( $3, 'Column ' || qcol || ' should ' || CASE WHEN $4 THEN 'be NOT' ELSE 'allow' END || ' NULL' ); BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( c_desc ) || E'\n' || diag (' Column ' || qcol || ' does not exist' ); END IF; RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2 AND a.attnotnull = $4 ), c_desc ); END; $$ LANGUAGE plpgsql; -- col_not_null( schema, table, column, description ) -- col_not_null( schema, table, column ) CREATE OR REPLACE FUNCTION col_not_null ( schema_name NAME, table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, $4, true ); $$ LANGUAGE SQL; -- col_not_null( table, column, description ) -- col_not_null( table, column ) CREATE OR REPLACE FUNCTION col_not_null ( table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, true ); $$ LANGUAGE SQL; -- col_is_null( schema, table, column, description ) -- col_is_null( schema, table, column ) CREATE OR REPLACE FUNCTION col_is_null ( schema_name NAME, table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, $4, false ); $$ LANGUAGE SQL; -- col_is_null( table, column, description ) -- col_is_null( table, column ) CREATE OR REPLACE FUNCTION col_is_null ( table_name NAME, column_name NAME, description TEXT DEFAULT NULL ) RETURNS TEXT AS $$ SELECT _col_is_null( $1, $2, $3, false ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_type ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attname = $3 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_type ( NAME, NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON a.attrelid = c.oid WHERE pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attname = $2 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_col_ns_type ( NAME, NAME, NAME ) RETURNS TEXT AS $$ -- Always include the namespace. SELECT CASE WHEN pg_catalog.pg_type_is_visible(t.oid) THEN quote_ident(tn.nspname) || '.' ELSE '' END || pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid JOIN pg_catalog.pg_type t ON a.atttypid = t.oid JOIN pg_catalog.pg_namespace tn ON t.typnamespace = tn.oid WHERE n.nspname = $1 AND c.relname = $2 AND a.attname = $3 AND attnum > 0 AND NOT a.attisdropped $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _typename ( NAME ) RETURNS TEXT AS $$ BEGIN RETURN $1::REGTYPE; EXCEPTION WHEN undefined_object THEN RETURN $1; END; $$ LANGUAGE PLPGSQL STABLE; CREATE OR REPLACE FUNCTION format_type_string ( TEXT ) RETURNS TEXT AS $$ DECLARE want_type TEXT := $1; typmodin_arg cstring[]; typmodin_func regproc; typmod int; BEGIN IF want_type::regtype = 'interval'::regtype THEN -- RAISE NOTICE 'cannot resolve: %', want_type; -- TODO RETURN want_type; END IF; -- Extract type modifier from type declaration and format as cstring[] literal. typmodin_arg := translate(substring(want_type FROM '[(][^")]+[)]'), '()', '{}'); -- Find typmodin function for want_type. SELECT typmodin INTO typmodin_func FROM pg_catalog.pg_type WHERE oid = want_type::regtype; IF typmodin_func = 0 THEN -- Easy: types without typemods. RETURN format_type(want_type::regtype, null); END IF; -- Get typemod via type-specific typmodin function. EXECUTE format('SELECT %I(%L)', typmodin_func, typmodin_arg) INTO typmod; RETURN format_type(want_type::regtype, typmod); EXCEPTION WHEN OTHERS THEN RETURN NULL; END; $$ LANGUAGE PLPGSQL STABLE; -- col_type_is( schema, table, column, schema, type, description ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have_type TEXT := _get_col_ns_type($1, $2, $3); want_type TEXT; BEGIN IF have_type IS NULL THEN RETURN fail( $6 ) || E'\n' || diag ( ' Column ' || COALESCE(quote_ident($1) || '.', '') || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; IF quote_ident($4) = ANY(current_schemas(true)) THEN want_type := quote_ident($4) || '.' || format_type_string($5); ELSE want_type := format_type_string(quote_ident($4) || '.' || $5); END IF; IF want_type IS NULL THEN RETURN fail( $6 ) || E'\n' || diag ( ' Type ' || quote_ident($4) || '.' || $5 || ' does not exist' ); END IF; IF have_type = want_type THEN -- We're good to go. RETURN ok( true, $6 ); END IF; -- Wrong data type. tell 'em what we really got. RETURN ok( false, $6 ) || E'\n' || diag( ' have: ' || have_type || E'\n want: ' || want_type ); END; $$ LANGUAGE plpgsql; -- col_type_is( schema, table, column, schema, type ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_type_is( $1, $2, $3, $4, $5, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' should be type ' || quote_ident($4) || '.' || $5); $$ LANGUAGE SQL; -- col_type_is( schema, table, column, type, description ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have_type TEXT; want_type TEXT; BEGIN -- Get the data type. IF $1 IS NULL THEN have_type := _get_col_type($2, $3); ELSE have_type := _get_col_type($1, $2, $3); END IF; IF have_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Column ' || COALESCE(quote_ident($1) || '.', '') || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; want_type := format_type_string($4); IF want_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Type ' || $4 || ' does not exist' ); END IF; IF have_type = want_type THEN -- We're good to go. RETURN ok( true, $5 ); END IF; -- Wrong data type. tell 'em what we really got. RETURN ok( false, $5 ) || E'\n' || diag( ' have: ' || have_type || E'\n want: ' || want_type ); END; $$ LANGUAGE plpgsql; -- col_type_is( schema, table, column, type ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_type_is( $1, $2, $3, $4, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' should be type ' || $4 ); $$ LANGUAGE SQL; -- col_type_is( table, column, type, description ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT col_type_is( NULL, $1, $2, $3, $4 ); $$ LANGUAGE SQL; -- col_type_is( table, column, type ) CREATE OR REPLACE FUNCTION col_type_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_type_is( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should be type ' || $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _has_def ( NAME, NAME, NAME ) RETURNS boolean AS $$ SELECT a.atthasdef FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3 $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_def ( NAME, NAME ) RETURNS boolean AS $$ SELECT a.atthasdef FROM pg_catalog.pg_class c JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE sql; -- col_has_default( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_has_default ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; RETURN ok( _has_def( $1, $2, $3 ), $4 ); END $$ LANGUAGE plpgsql; -- col_has_default( table, column, description ) CREATE OR REPLACE FUNCTION col_has_default ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( $3 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN ok( _has_def( $1, $2 ), $3 ); END; $$ LANGUAGE plpgsql; -- col_has_default( table, column ) CREATE OR REPLACE FUNCTION col_has_default ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_has_default( $1, $2, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should have a default' ); $$ LANGUAGE SQL; -- col_hasnt_default( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_hasnt_default ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; RETURN ok( NOT _has_def( $1, $2, $3 ), $4 ); END; $$ LANGUAGE plpgsql; -- col_hasnt_default( table, column, description ) CREATE OR REPLACE FUNCTION col_hasnt_default ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( $3 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN ok( NOT _has_def( $1, $2 ), $3 ); END; $$ LANGUAGE plpgsql; -- col_hasnt_default( table, column ) CREATE OR REPLACE FUNCTION col_hasnt_default ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_hasnt_default( $1, $2, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should not have a default' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _def_is( TEXT, TEXT, anyelement, TEXT ) RETURNS TEXT AS $$ DECLARE thing text; BEGIN -- Function, cast, or special SQL syntax. IF $1 ~ '^[^'']+[(]' OR $1 ~ '[)]::[^'']+$' OR $1 = ANY('{CURRENT_CATALOG,CURRENT_ROLE,CURRENT_SCHEMA,CURRENT_USER,SESSION_USER,USER,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,LOCALTIME,LOCALTIMESTAMP}') THEN RETURN is( $1, $3, $4 ); END IF; EXECUTE 'SELECT is(' || COALESCE($1, 'NULL' || '::' || $2) || '::' || $2 || ', ' || COALESCE(quote_literal($3), 'NULL') || '::' || $2 || ', ' || COALESCE(quote_literal($4), 'NULL') || ')' INTO thing; RETURN thing; END; $$ LANGUAGE plpgsql; -- _cdi( schema, table, column, default, description ) CREATE OR REPLACE FUNCTION _cdi ( NAME, NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2, $3 ) THEN RETURN fail( $5 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); END IF; IF NOT _has_def( $1, $2, $3 ) THEN RETURN fail( $5 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' has no default' ); END IF; RETURN _def_is( pg_catalog.pg_get_expr(d.adbin, d.adrelid), pg_catalog.format_type(a.atttypid, a.atttypmod), $4, $5 ) FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c, pg_catalog.pg_attribute a, pg_catalog.pg_attrdef d WHERE n.oid = c.relnamespace AND c.oid = a.attrelid AND a.atthasdef AND a.attrelid = d.adrelid AND a.attnum = d.adnum AND n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $3; END; $$ LANGUAGE plpgsql; -- _cdi( table, column, default, description ) CREATE OR REPLACE FUNCTION _cdi ( NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ BEGIN IF NOT _cexists( $1, $2 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; IF NOT _has_def( $1, $2 ) THEN RETURN fail( $4 ) || E'\n' || diag (' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' has no default' ); END IF; RETURN _def_is( pg_catalog.pg_get_expr(d.adbin, d.adrelid), pg_catalog.format_type(a.atttypid, a.atttypmod), $3, $4 ) FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a, pg_catalog.pg_attrdef d WHERE c.oid = a.attrelid AND pg_table_is_visible(c.oid) AND a.atthasdef AND a.attrelid = d.adrelid AND a.attnum = d.adnum AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped AND a.attname = $2; END; $$ LANGUAGE plpgsql; -- _cdi( table, column, default ) CREATE OR REPLACE FUNCTION _cdi ( NAME, NAME, anyelement ) RETURNS TEXT AS $$ SELECT col_default_is( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || ' should default to ' || COALESCE( quote_literal($3), 'NULL') ); $$ LANGUAGE sql; -- col_default_is( schema, table, column, default, description ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3, $4, $5 ); $$ LANGUAGE sql; -- col_default_is( schema, table, column, default, description ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3, $4, $5 ); $$ LANGUAGE sql; -- col_default_is( table, column, default, description ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, anyelement, TEXT ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3, $4 ); $$ LANGUAGE sql; -- col_default_is( table, column, default, description ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3, $4 ); $$ LANGUAGE sql; -- col_default_is( table, column, default ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, anyelement ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3 ); $$ LANGUAGE sql; -- col_default_is( table, column, default::text ) CREATE OR REPLACE FUNCTION col_default_is ( NAME, NAME, text ) RETURNS TEXT AS $$ SELECT _cdi( $1, $2, $3 ); $$ LANGUAGE sql; -- _hasc( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON c.relnamespace = n.oid JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE n.nspname = $1 AND c.relname = $2 AND x.contype = $3 ); $$ LANGUAGE sql; -- _hasc( table, constraint_type ) CREATE OR REPLACE FUNCTION _hasc ( NAME, CHAR ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE pg_table_is_visible(c.oid) AND c.relname = $1 AND x.contype = $2 ); $$ LANGUAGE sql; -- has_pk( schema, table, description ) CREATE OR REPLACE FUNCTION has_pk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, $2, 'p' ), $3 ); $$ LANGUAGE sql; -- has_pk( schema, table ) CREATE OR REPLACE FUNCTION has_pk ( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_pk( $1, $2, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have a primary key' ); $$ LANGUAGE sql; -- has_pk( table, description ) CREATE OR REPLACE FUNCTION has_pk ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, 'p' ), $2 ); $$ LANGUAGE sql; -- has_pk( table ) CREATE OR REPLACE FUNCTION has_pk ( NAME ) RETURNS TEXT AS $$ SELECT has_pk( $1, 'Table ' || quote_ident($1) || ' should have a primary key' ); $$ LANGUAGE sql; -- hasnt_pk( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_pk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _hasc( $1, $2, 'p' ), $3 ); $$ LANGUAGE sql; -- hasnt_pk( table, description ) CREATE OR REPLACE FUNCTION hasnt_pk ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _hasc( $1, 'p' ), $2 ); $$ LANGUAGE sql; -- hasnt_pk( table ) CREATE OR REPLACE FUNCTION hasnt_pk ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_pk( $1, 'Table ' || quote_ident($1) || ' should not have a primary key' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _ident_array_to_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT quote_ident($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY i ), $2); $$ LANGUAGE SQL immutable; -- Borrowed from newsysviews: https://www.postgresql.org/ftp/projects/pgFoundry/newsysviews/ CREATE OR REPLACE FUNCTION _pg_sv_column_array( OID, SMALLINT[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT a.attname FROM pg_catalog.pg_attribute a JOIN generate_series(1, array_upper($2, 1)) s(i) ON a.attnum = $2[i] WHERE attrelid = $1 ORDER BY i ) $$ LANGUAGE SQL stable; -- Borrowed from newsysviews: https://www.postgresql.org/ftp/projects/pgFoundry/newsysviews/ CREATE OR REPLACE FUNCTION _pg_sv_table_accessible( OID, OID ) RETURNS BOOLEAN AS $$ SELECT CASE WHEN has_schema_privilege($1, 'USAGE') THEN ( has_table_privilege($2, 'SELECT') OR has_table_privilege($2, 'INSERT') or has_table_privilege($2, 'UPDATE') OR has_table_privilege($2, 'DELETE') OR has_table_privilege($2, 'RULE') OR has_table_privilege($2, 'REFERENCES') OR has_table_privilege($2, 'TRIGGER') ) ELSE FALSE END; $$ LANGUAGE SQL immutable strict; -- Borrowed from newsysviews: https://www.postgresql.org/ftp/projects/pgFoundry/newsysviews/ CREATE OR REPLACE VIEW pg_all_foreign_keys AS SELECT n1.nspname AS fk_schema_name, c1.relname AS fk_table_name, k1.conname AS fk_constraint_name, c1.oid AS fk_table_oid, _pg_sv_column_array(k1.conrelid,k1.conkey) AS fk_columns, n2.nspname AS pk_schema_name, c2.relname AS pk_table_name, k2.conname AS pk_constraint_name, c2.oid AS pk_table_oid, ci.relname AS pk_index_name, _pg_sv_column_array(k1.confrelid,k1.confkey) AS pk_columns, CASE k1.confmatchtype WHEN 'f' THEN 'FULL' WHEN 'p' THEN 'PARTIAL' WHEN 'u' THEN 'NONE' else null END AS match_type, CASE k1.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' WHEN 'r' THEN 'RESTRICT' else null END AS on_delete, CASE k1.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'c' THEN 'CASCADE' WHEN 'd' THEN 'SET DEFAULT' WHEN 'n' THEN 'SET NULL' WHEN 'r' THEN 'RESTRICT' ELSE NULL END AS on_update, k1.condeferrable AS is_deferrable, k1.condeferred AS is_deferred FROM pg_catalog.pg_constraint k1 JOIN pg_catalog.pg_namespace n1 ON (n1.oid = k1.connamespace) JOIN pg_catalog.pg_class c1 ON (c1.oid = k1.conrelid) JOIN pg_catalog.pg_class c2 ON (c2.oid = k1.confrelid) JOIN pg_catalog.pg_namespace n2 ON (n2.oid = c2.relnamespace) JOIN pg_catalog.pg_depend d ON ( d.classid = 'pg_constraint'::regclass AND d.objid = k1.oid AND d.objsubid = 0 AND d.deptype = 'n' AND d.refclassid = 'pg_class'::regclass AND d.refobjsubid=0 ) JOIN pg_catalog.pg_class ci ON (ci.oid = d.refobjid AND ci.relkind = 'i') LEFT JOIN pg_depend d2 ON ( d2.classid = 'pg_class'::regclass AND d2.objid = ci.oid AND d2.objsubid = 0 AND d2.deptype = 'i' AND d2.refclassid = 'pg_constraint'::regclass AND d2.refobjsubid = 0 ) LEFT JOIN pg_catalog.pg_constraint k2 ON ( k2.oid = d2.refobjid AND k2.contype IN ('p', 'u') ) WHERE k1.conrelid != 0 AND k1.confrelid != 0 AND k1.contype = 'f' AND _pg_sv_table_accessible(n1.oid, c1.oid); -- _keys( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _keys ( NAME, NAME, CHAR ) RETURNS SETOF NAME[] AS $$ SELECT _pg_sv_column_array(x.conrelid,x.conkey) -- name[] doesn't support collation FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid WHERE n.nspname = $1 AND c.relname = $2 AND x.contype = $3 ORDER BY 1 $$ LANGUAGE sql; -- _keys( table, constraint_type ) CREATE OR REPLACE FUNCTION _keys ( NAME, CHAR ) RETURNS SETOF NAME[] AS $$ SELECT _pg_sv_column_array(x.conrelid,x.conkey) -- name[] doesn't support collation FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint x ON c.oid = x.conrelid AND c.relname = $1 AND x.contype = $2 WHERE pg_catalog.pg_table_is_visible(c.oid) ORDER BY 1 $$ LANGUAGE sql; -- _ckeys( schema, table, constraint_type ) CREATE OR REPLACE FUNCTION _ckeys ( NAME, NAME, CHAR ) RETURNS NAME[] AS $$ SELECT * FROM _keys($1, $2, $3) LIMIT 1; $$ LANGUAGE sql; -- _ckeys( table, constraint_type ) CREATE OR REPLACE FUNCTION _ckeys ( NAME, CHAR ) RETURNS NAME[] AS $$ SELECT * FROM _keys($1, $2) LIMIT 1; $$ LANGUAGE sql; -- col_is_pk( schema, table, column[], description ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( _ckeys( $1, $2, 'p' ), $3, $4 ); $$ LANGUAGE sql; -- col_is_pk( schema, table, column[] ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, $3, 'Columns ' || quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should be a primary key' ); $$ LANGUAGE sql; -- col_is_pk( table, column[], description ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( _ckeys( $1, 'p' ), $2, $3 ); $$ LANGUAGE sql; -- col_is_pk( table, column[] ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should be a primary key' ); $$ LANGUAGE sql; -- col_is_pk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_is_pk( schema, table, column ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, $3, 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '(' || quote_ident($3) || ') should be a primary key' ); $$ LANGUAGE sql; -- col_is_pk( table, column, description ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_is_pk( table, column ) CREATE OR REPLACE FUNCTION col_is_pk ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_pk( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should be a primary key' ); $$ LANGUAGE sql; -- col_isnt_pk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT isnt( _ckeys( $1, $2, 'p' ), $3, $4 ); $$ LANGUAGE sql; -- col_isnt_pk( table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT isnt( _ckeys( $1, 'p' ), $2, $3 ); $$ LANGUAGE sql; -- col_isnt_pk( table, column[] ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_isnt_pk( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should not be a primary key' ); $$ LANGUAGE sql; -- col_isnt_pk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_isnt_pk( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_isnt_pk( table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_isnt_pk( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_isnt_pk( table, column ) CREATE OR REPLACE FUNCTION col_isnt_pk ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_isnt_pk( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should not be a primary key' ); $$ LANGUAGE sql; -- has_fk( schema, table, description ) CREATE OR REPLACE FUNCTION has_fk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, $2, 'f' ), $3 ); $$ LANGUAGE sql; -- has_fk( table, description ) CREATE OR REPLACE FUNCTION has_fk ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, 'f' ), $2 ); $$ LANGUAGE sql; -- has_fk( table ) CREATE OR REPLACE FUNCTION has_fk ( NAME ) RETURNS TEXT AS $$ SELECT has_fk( $1, 'Table ' || quote_ident($1) || ' should have a foreign key constraint' ); $$ LANGUAGE sql; -- hasnt_fk( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_fk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _hasc( $1, $2, 'f' ), $3 ); $$ LANGUAGE sql; -- hasnt_fk( table, description ) CREATE OR REPLACE FUNCTION hasnt_fk ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _hasc( $1, 'f' ), $2 ); $$ LANGUAGE sql; -- hasnt_fk( table ) CREATE OR REPLACE FUNCTION hasnt_fk ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_fk( $1, 'Table ' || quote_ident($1) || ' should not have a foreign key constraint' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _fkexists ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM pg_all_foreign_keys WHERE fk_schema_name = $1 AND quote_ident(fk_table_name) = quote_ident($2) AND fk_columns = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _fkexists ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM pg_all_foreign_keys WHERE quote_ident(fk_table_name) = quote_ident($1) AND pg_catalog.pg_table_is_visible(fk_table_oid) AND fk_columns = $2 ); $$ LANGUAGE SQL; -- col_is_fk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE names text[]; BEGIN IF _fkexists($1, $2, $3) THEN RETURN pass( $4 ); END IF; -- Try to show the columns. SELECT ARRAY( SELECT _ident_array_to_string(fk_columns, ', ') FROM pg_all_foreign_keys WHERE fk_schema_name = $1 AND fk_table_name = $2 ORDER BY fk_columns ) INTO names; IF names[1] IS NOT NULL THEN RETURN fail($4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || E' has foreign key constraints on these columns:\n ' || array_to_string( names, E'\n ' ) ); END IF; -- No FKs in this table. RETURN fail($4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' has no foreign key columns' ); END; $$ LANGUAGE plpgsql; -- col_is_fk( table, column, description ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE names text[]; BEGIN IF _fkexists($1, $2) THEN RETURN pass( $3 ); END IF; -- Try to show the columns. SELECT ARRAY( SELECT _ident_array_to_string(fk_columns, ', ') FROM pg_all_foreign_keys WHERE fk_table_name = $1 ORDER BY fk_columns ) INTO names; IF NAMES[1] IS NOT NULL THEN RETURN fail($3) || E'\n' || diag( ' Table ' || quote_ident($1) || E' has foreign key constraints on these columns:\n ' || array_to_string( names, E'\n ' ) ); END IF; -- No FKs in this table. RETURN fail($3) || E'\n' || diag( ' Table ' || quote_ident($1) || ' has no foreign key columns' ); END; $$ LANGUAGE plpgsql; -- col_is_fk( table, column[] ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_fk( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should be a foreign key' ); $$ LANGUAGE sql; -- col_is_fk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_fk( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_is_fk( table, column, description ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_fk( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_is_fk( table, column ) CREATE OR REPLACE FUNCTION col_is_fk ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_fk( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should be a foreign key' ); $$ LANGUAGE sql; -- col_isnt_fk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _fkexists( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- col_isnt_fk( table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _fkexists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- col_isnt_fk( table, column[] ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_isnt_fk( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should not be a foreign key' ); $$ LANGUAGE sql; -- col_isnt_fk( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_isnt_fk( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_isnt_fk( table, column, description ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_isnt_fk( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_isnt_fk( table, column ) CREATE OR REPLACE FUNCTION col_isnt_fk ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_isnt_fk( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should not be a foreign key' ); $$ LANGUAGE sql; -- has_unique( schema, table, description ) CREATE OR REPLACE FUNCTION has_unique ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, $2, 'u' ), $3 ); $$ LANGUAGE sql; -- has_unique( table, description ) CREATE OR REPLACE FUNCTION has_unique ( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, 'u' ), $2 ); $$ LANGUAGE sql; -- has_unique( table ) CREATE OR REPLACE FUNCTION has_unique ( TEXT ) RETURNS TEXT AS $$ SELECT has_unique( $1, 'Table ' || quote_ident($1) || ' should have a unique constraint' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _constraint ( NAME, NAME, CHAR, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE akey NAME[]; keys TEXT[] := '{}'; have TEXT; BEGIN FOR akey IN SELECT * FROM _keys($1, $2, $3) LOOP IF akey = $4 THEN RETURN pass($5); END IF; keys = keys || akey::text; END LOOP; IF array_upper(keys, 0) = 1 THEN have := 'No ' || $6 || ' constraints'; ELSE have := array_to_string(keys, E'\n '); END IF; RETURN fail($5) || E'\n' || diag( ' have: ' || have || E'\n want: ' || CASE WHEN $4 IS NULL THEN 'NULL' ELSE $4::text END ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _constraint ( NAME, CHAR, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE akey NAME[]; keys TEXT[] := '{}'; have TEXT; BEGIN FOR akey IN SELECT * FROM _keys($1, $2) LOOP IF akey = $3 THEN RETURN pass($4); END IF; keys = keys || akey::text; END LOOP; IF array_upper(keys, 0) = 1 THEN have := 'No ' || $5 || ' constraints'; ELSE have := array_to_string(keys, E'\n '); END IF; RETURN fail($4) || E'\n' || diag( ' have: ' || have || E'\n want: ' || CASE WHEN $3 IS NULL THEN 'NULL' ELSE $3::text END ); END; $$ LANGUAGE plpgsql; -- col_is_unique( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _constraint( $1, $2, 'u', $3, $4, 'unique' ); $$ LANGUAGE sql; -- col_is_unique( schema, table, column[] ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, $3, 'Columns ' || quote_ident($2) || '(' || _ident_array_to_string($3, ', ') || ') should have a unique constraint' ); $$ LANGUAGE sql; -- col_is_unique( scheam, table, column ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, ARRAY[$3], 'Column ' || quote_ident($2) || '(' || quote_ident($3) || ') should have a unique constraint' ); $$ LANGUAGE sql; -- col_is_unique( table, column, description ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _constraint( $1, 'u', $2, $3, 'unique' ); $$ LANGUAGE sql; -- col_is_unique( table, column[] ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should have a unique constraint' ); $$ LANGUAGE sql; -- col_is_unique( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_is_unique( table, column, description ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_is_unique( table, column ) CREATE OR REPLACE FUNCTION col_is_unique ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_is_unique( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should have a unique constraint' ); $$ LANGUAGE sql; -- has_check( schema, table, description ) CREATE OR REPLACE FUNCTION has_check ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, $2, 'c' ), $3 ); $$ LANGUAGE sql; -- has_check( table, description ) CREATE OR REPLACE FUNCTION has_check ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _hasc( $1, 'c' ), $2 ); $$ LANGUAGE sql; -- has_check( table ) CREATE OR REPLACE FUNCTION has_check ( NAME ) RETURNS TEXT AS $$ SELECT has_check( $1, 'Table ' || quote_ident($1) || ' should have a check constraint' ); $$ LANGUAGE sql; -- col_has_check( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _constraint( $1, $2, 'c', $3, $4, 'check' ); $$ LANGUAGE sql; -- col_has_check( table, column, description ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _constraint( $1, 'c', $2, $3, 'check' ); $$ LANGUAGE sql; -- col_has_check( table, column[] ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT col_has_check( $1, $2, 'Columns ' || quote_ident($1) || '(' || _ident_array_to_string($2, ', ') || ') should have a check constraint' ); $$ LANGUAGE sql; -- col_has_check( schema, table, column, description ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_has_check( $1, $2, ARRAY[$3], $4 ); $$ LANGUAGE sql; -- col_has_check( table, column, description ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT col_has_check( $1, ARRAY[$2], $3 ); $$ LANGUAGE sql; -- col_has_check( table, column ) CREATE OR REPLACE FUNCTION col_has_check ( NAME, NAME ) RETURNS TEXT AS $$ SELECT col_has_check( $1, $2, 'Column ' || quote_ident($1) || '(' || quote_ident($2) || ') should have a check constraint' ); $$ LANGUAGE sql; -- fk_ok( fk_schema, fk_table, fk_column[], pk_schema, pk_table, pk_column[], description ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME[], NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE sch name; tab name; cols name[]; BEGIN SELECT pk_schema_name, pk_table_name, pk_columns FROM pg_all_foreign_keys WHERE fk_schema_name = $1 AND fk_table_name = $2 AND fk_columns = $3 INTO sch, tab, cols; RETURN is( -- have quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string( $3, ', ' ) || ') REFERENCES ' || COALESCE ( sch || '.' || tab || '(' || _ident_array_to_string( cols, ', ' ) || ')', 'NOTHING' ), -- want quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string( $3, ', ' ) || ') REFERENCES ' || $4 || '.' || $5 || '(' || _ident_array_to_string( $6, ', ' ) || ')', $7 ); END; $$ LANGUAGE plpgsql; -- fk_ok( fk_table, fk_column[], pk_table, pk_column[], description ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE tab name; cols name[]; BEGIN SELECT pk_table_name, pk_columns FROM pg_all_foreign_keys WHERE fk_table_name = $1 AND fk_columns = $2 AND pg_catalog.pg_table_is_visible(fk_table_oid) INTO tab, cols; RETURN is( -- have $1 || '(' || _ident_array_to_string( $2, ', ' ) || ') REFERENCES ' || COALESCE( tab || '(' || _ident_array_to_string( cols, ', ' ) || ')', 'NOTHING'), -- want $1 || '(' || _ident_array_to_string( $2, ', ' ) || ') REFERENCES ' || $3 || '(' || _ident_array_to_string( $4, ', ' ) || ')', $5 ); END; $$ LANGUAGE plpgsql; -- fk_ok( fk_schema, fk_table, fk_column[], fk_schema, pk_table, pk_column[] ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME[], NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT fk_ok( $1, $2, $3, $4, $5, $6, quote_ident($1) || '.' || quote_ident($2) || '(' || _ident_array_to_string( $3, ', ' ) || ') should reference ' || $4 || '.' || $5 || '(' || _ident_array_to_string( $6, ', ' ) || ')' ); $$ LANGUAGE sql; -- fk_ok( fk_table, fk_column[], pk_table, pk_column[] ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME[], NAME, NAME[] ) RETURNS TEXT AS $$ SELECT fk_ok( $1, $2, $3, $4, $1 || '(' || _ident_array_to_string( $2, ', ' ) || ') should reference ' || $3 || '(' || _ident_array_to_string( $4, ', ' ) || ')' ); $$ LANGUAGE sql; -- fk_ok( fk_schema, fk_table, fk_column, pk_schema, pk_table, pk_column, description ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT fk_ok( $1, $2, ARRAY[$3], $4, $5, ARRAY[$6], $7 ); $$ LANGUAGE sql; -- fk_ok( fk_schema, fk_table, fk_column, pk_schema, pk_table, pk_column ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT fk_ok( $1, $2, ARRAY[$3], $4, $5, ARRAY[$6] ); $$ LANGUAGE sql; -- fk_ok( fk_table, fk_column, pk_table, pk_column, description ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT fk_ok( $1, ARRAY[$2], $3, ARRAY[$4], $5 ); $$ LANGUAGE sql; -- fk_ok( fk_table, fk_column, pk_table, pk_column ) CREATE OR REPLACE FUNCTION fk_ok ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT fk_ok( $1, ARRAY[$2], $3, ARRAY[$4] ); $$ LANGUAGE sql; /* * tap_funky used to just be a simple view, but the problem with that is the * definition of pg_proc changed in version 11. Thanks to how pg_dump (and * hence pg_upgrade) works, this made it impossible to upgrade Postgres if * pgTap was installed. In order to fix that, we need code that will actually * work on both < PG11 and >= PG11. */ CREATE OR REPLACE FUNCTION _prokind( p_oid oid ) RETURNS "char" AS $$ BEGIN IF pg_version_num() >= 110000 THEN RETURN prokind FROM pg_catalog.pg_proc WHERE oid = p_oid; ELSE RETURN CASE WHEN proisagg THEN 'a' WHEN proiswindow THEN 'w' ELSE 'f' END FROM pg_catalog.pg_proc WHERE oid = p_oid; END IF; END; $$ LANGUAGE plpgsql STABLE; CREATE OR REPLACE VIEW tap_funky AS SELECT p.oid AS oid, n.nspname AS schema, p.proname AS name, pg_catalog.pg_get_userbyid(p.proowner) AS owner, array_to_string(p.proargtypes::regtype[], ',') AS args, CASE p.proretset WHEN TRUE THEN 'setof ' ELSE '' END || p.prorettype::regtype AS returns, p.prolang AS langoid, p.proisstrict AS is_strict, _prokind(p.oid) AS kind, p.prosecdef AS is_definer, p.proretset AS returns_set, p.provolatile::char AS volatility, pg_catalog.pg_function_is_visible(p.oid) AS is_visible FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid ; CREATE OR REPLACE FUNCTION _funkargs ( NAME[] ) RETURNS TEXT AS $$ BEGIN RETURN array_to_string($1::regtype[], ','); EXCEPTION WHEN undefined_object THEN RETURN array_to_string($1, ','); END; $$ LANGUAGE PLPGSQL STABLE; CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE schema = $1 AND name = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _got_func ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _got_func ( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT TRUE FROM tap_funky WHERE name = $1 AND is_visible); $$ LANGUAGE SQL; -- has_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION has_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- has_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION has_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should exist' ); $$ LANGUAGE sql; -- has_function( schema, function, description ) CREATE OR REPLACE FUNCTION has_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2), $3 ); $$ LANGUAGE SQL; -- has_function( schema, function ) CREATE OR REPLACE FUNCTION has_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should exist' ); $$ LANGUAGE sql; -- has_function( function, args[], description ) CREATE OR REPLACE FUNCTION has_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2), $3 ); $$ LANGUAGE SQL; -- has_function( function, args[] ) CREATE OR REPLACE FUNCTION has_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _got_func($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should exist' ); $$ LANGUAGE sql; -- has_function( function, description ) CREATE OR REPLACE FUNCTION has_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _got_func($1), $2 ); $$ LANGUAGE sql; -- has_function( function ) CREATE OR REPLACE FUNCTION has_function( NAME ) RETURNS TEXT AS $$ SELECT ok( _got_func($1), 'Function ' || quote_ident($1) || '() should exist' ); $$ LANGUAGE sql; -- hasnt_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION hasnt_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- hasnt_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION hasnt_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not exist' ); $$ LANGUAGE sql; -- hasnt_function( schema, function, description ) CREATE OR REPLACE FUNCTION hasnt_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2), $3 ); $$ LANGUAGE SQL; -- hasnt_function( schema, function ) CREATE OR REPLACE FUNCTION hasnt_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not exist' ); $$ LANGUAGE sql; -- hasnt_function( function, args[], description ) CREATE OR REPLACE FUNCTION hasnt_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2), $3 ); $$ LANGUAGE SQL; -- hasnt_function( function, args[] ) CREATE OR REPLACE FUNCTION hasnt_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not exist' ); $$ LANGUAGE sql; -- hasnt_function( function, description ) CREATE OR REPLACE FUNCTION hasnt_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1), $2 ); $$ LANGUAGE sql; -- hasnt_function( function ) CREATE OR REPLACE FUNCTION hasnt_function( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _got_func($1), 'Function ' || quote_ident($1) || '() should not exist' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _pg_sv_type_array( OID[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT t.typname FROM pg_catalog.pg_type t JOIN generate_series(1, array_upper($1, 1)) s(i) ON t.oid = $1[i] ORDER BY i ) $$ LANGUAGE SQL stable; -- can( schema, functions[], description ) CREATE OR REPLACE FUNCTION can ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE missing text[]; BEGIN SELECT ARRAY( SELECT quote_ident($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) LEFT JOIN tap_funky ON name = $2[i] AND schema = $1 WHERE oid IS NULL GROUP BY $2[i], s.i ORDER BY MIN(s.i) ) INTO missing; IF missing[1] IS NULL THEN RETURN ok( true, $3 ); END IF; RETURN ok( false, $3 ) || E'\n' || diag( ' ' || quote_ident($1) || '.' || array_to_string( missing, E'() missing\n ' || quote_ident($1) || '.') || '() missing' ); END; $$ LANGUAGE plpgsql; -- can( schema, functions[] ) CREATE OR REPLACE FUNCTION can ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT can( $1, $2, 'Schema ' || quote_ident($1) || ' can' ); $$ LANGUAGE sql; -- can( functions[], description ) CREATE OR REPLACE FUNCTION can ( NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE missing text[]; BEGIN SELECT ARRAY( SELECT quote_ident($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) LEFT JOIN pg_catalog.pg_proc p ON $1[i] = p.proname AND pg_catalog.pg_function_is_visible(p.oid) WHERE p.oid IS NULL ORDER BY s.i ) INTO missing; IF missing[1] IS NULL THEN RETURN ok( true, $2 ); END IF; RETURN ok( false, $2 ) || E'\n' || diag( ' ' || array_to_string( missing, E'() missing\n ') || '() missing' ); END; $$ LANGUAGE plpgsql; -- can( functions[] ) CREATE OR REPLACE FUNCTION can ( NAME[] ) RETURNS TEXT AS $$ SELECT can( $1, 'Schema ' || _ident_array_to_string(current_schemas(true), ' or ') || ' can' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _ikeys( NAME, NAME, NAME) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT pg_catalog.pg_get_indexdef( ci.oid, s.i + 1, false) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace JOIN generate_series(0, current_setting('max_index_keys')::int - 1) s(i) ON x.indkey[s.i] IS NOT NULL WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 ORDER BY s.i ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _ikeys( NAME, NAME) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT pg_catalog.pg_get_indexdef( ci.oid, s.i + 1, false) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN generate_series(0, current_setting('max_index_keys')::int - 1) s(i) ON x.indkey[s.i] IS NOT NULL WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) ORDER BY s.i ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _have_index( NAME, NAME, NAME) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE n.nspname = $1 AND ct.relname = $2 AND ci.relname = $3 ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _have_index( NAME, NAME) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) ); $$ LANGUAGE sql; -- has_index( schema, table, index, columns[], description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME[], text ) RETURNS TEXT AS $$ DECLARE index_cols name[]; BEGIN index_cols := _ikeys($1, $2, $3 ); IF index_cols IS NULL OR index_cols = '{}'::name[] THEN RETURN ok( false, $5 ) || E'\n' || diag( 'Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' not found'); END IF; RETURN is( quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( index_cols, ', ' ) || ')', quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( $4, ', ' ) || ')', $5 ); END; $$ LANGUAGE plpgsql; -- has_index( schema, table, index, columns[] ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT has_index( $1, $2, $3, $4, 'Index ' || quote_ident($3) || ' should exist' ); $$ LANGUAGE sql; -- has_index( schema, table, index, column, description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT has_index( $1, $2, $3, ARRAY[$4], $5 ); $$ LANGUAGE sql; -- has_index( schema, table, index, column ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT has_index( $1, $2, $3, $4, 'Index ' || quote_ident($3) || ' should exist' ); $$ LANGUAGE sql; -- has_index( table, index, columns[], description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME[], text ) RETURNS TEXT AS $$ DECLARE index_cols name[]; BEGIN index_cols := _ikeys($1, $2 ); IF index_cols IS NULL OR index_cols = '{}'::name[] THEN RETURN ok( false, $4 ) || E'\n' || diag( 'Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' not found'); END IF; RETURN is( quote_ident($2) || ' ON ' || quote_ident($1) || '(' || array_to_string( index_cols, ', ' ) || ')', quote_ident($2) || ' ON ' || quote_ident($1) || '(' || array_to_string( $3, ', ' ) || ')', $4 ); END; $$ LANGUAGE plpgsql; -- has_index( table, index, columns[] ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT has_index( $1, $2, $3, 'Index ' || quote_ident($2) || ' should exist' ); $$ LANGUAGE sql; -- _is_schema( schema ) CREATE OR REPLACE FUNCTION _is_schema( NAME ) returns boolean AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace WHERE nspname = $1 ); $$ LANGUAGE sql; -- has_index( table, index, column/expression, description ) -- has_index( schema, table, index, column/expression ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT CASE WHEN _is_schema( $1 ) THEN -- Looking for schema.table index. ok ( _have_index( $1, $2, $3 ), $4) ELSE -- Looking for particular columns. has_index( $1, $2, ARRAY[$3], $4 ) END; $$ LANGUAGE sql; -- has_index( table, index, column/expression ) -- has_index( schema, table, index ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, NAME ) RETURNS TEXT AS $$ BEGIN IF _is_schema($1) THEN -- ( schema, table, index ) RETURN ok( _have_index( $1, $2, $3 ), 'Index ' || quote_ident($3) || ' should exist' ); ELSE -- ( table, index, column/expression ) RETURN has_index( $1, $2, $3, 'Index ' || quote_ident($2) || ' should exist' ); END IF; END; $$ LANGUAGE plpgsql; -- has_index( table, index, description ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME, text ) RETURNS TEXT AS $$ SELECT CASE WHEN $3 LIKE '%(%' THEN has_index( $1, $2, $3::name ) ELSE ok( _have_index( $1, $2 ), $3 ) END; $$ LANGUAGE sql; -- has_index( table, index ) CREATE OR REPLACE FUNCTION has_index ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _have_index( $1, $2 ), 'Index ' || quote_ident($2) || ' should exist' ); $$ LANGUAGE sql; -- hasnt_index( schema, table, index, description ) CREATE OR REPLACE FUNCTION hasnt_index ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ BEGIN RETURN ok( NOT _have_index( $1, $2, $3 ), $4 ); END; $$ LANGUAGE plpgSQL; -- hasnt_index( schema, table, index ) CREATE OR REPLACE FUNCTION hasnt_index ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _have_index( $1, $2, $3 ), 'Index ' || quote_ident($3) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_index( table, index, description ) CREATE OR REPLACE FUNCTION hasnt_index ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _have_index( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_index( table, index ) CREATE OR REPLACE FUNCTION hasnt_index ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _have_index( $1, $2 ), 'Index ' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _is_indexed( NAME, NAME, TEXT[] ) RETURNS BOOL AS $$ SELECT EXISTS( SELECT TRUE FROM ( SELECT _ikeys(coalesce($1, n.nspname), $2, ci.relname) AS cols FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ($1 IS NULL OR n.nspname = $1) AND ct.relname = $2 ) icols WHERE cols = $3 ) $$ LANGUAGE sql; -- is_indexed( schema, table, columns[], description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_indexed($1, $2, $3), $4 ); $$ LANGUAGE sql; -- is_indexed( schema, table, columns[] ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _is_indexed($1, $2, $3), 'Should have an index on ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string( $3, ', ' ) || ')' ); $$ LANGUAGE sql; -- is_indexed( table, columns[], description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_indexed(NULL, $1, $2), $3 ); $$ LANGUAGE sql; -- is_indexed( table, columns[] ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _is_indexed(NULL, $1, $2), 'Should have an index on ' || quote_ident($1) || '(' || array_to_string( $2, ', ' ) || ')' ); $$ LANGUAGE sql; -- is_indexed( schema, table, column, description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok ( _is_indexed( $1, $2, ARRAY[$3]::NAME[]), $4); $$ LANGUAGE sql; -- is_indexed( schema, table, column ) -- is_indexed( table, column, description ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT CASE WHEN _is_schema( $1 ) THEN -- Looking for schema.table index. is_indexed( $1, $2, ARRAY[$3]::NAME[] ) ELSE -- Looking for particular columns. is_indexed( $1, ARRAY[$2]::NAME[], $3 ) END; $$ LANGUAGE sql; -- is_indexed( table, column ) CREATE OR REPLACE FUNCTION is_indexed ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok ( _is_indexed( NULL, $1, ARRAY[$2]::NAME[]) ); $$ LANGUAGE sql; -- index_is_unique( schema, table, index, description ) CREATE OR REPLACE FUNCTION index_is_unique ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisunique FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 INTO res; RETURN ok( COALESCE(res, false), $4 ); END; $$ LANGUAGE plpgsql; -- index_is_unique( schema, table, index ) CREATE OR REPLACE FUNCTION index_is_unique ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_is_unique( $1, $2, $3, 'Index ' || quote_ident($3) || ' should be unique' ); $$ LANGUAGE sql; -- index_is_unique( table, index ) CREATE OR REPLACE FUNCTION index_is_unique ( NAME, NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisunique FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) INTO res; RETURN ok( COALESCE(res, false), 'Index ' || quote_ident($2) || ' should be unique' ); END; $$ LANGUAGE plpgsql; -- index_is_unique( index ) CREATE OR REPLACE FUNCTION index_is_unique ( NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisunique FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid WHERE ci.relname = $1 AND pg_catalog.pg_table_is_visible(ct.oid) INTO res; RETURN ok( COALESCE(res, false), 'Index ' || quote_ident($1) || ' should be unique' ); END; $$ LANGUAGE plpgsql; -- index_is_primary( schema, table, index, description ) CREATE OR REPLACE FUNCTION index_is_primary ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisprimary FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 INTO res; RETURN ok( COALESCE(res, false), $4 ); END; $$ LANGUAGE plpgsql; -- index_is_primary( schema, table, index ) CREATE OR REPLACE FUNCTION index_is_primary ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_is_primary( $1, $2, $3, 'Index ' || quote_ident($3) || ' should be on a primary key' ); $$ LANGUAGE sql; -- index_is_primary( table, index ) CREATE OR REPLACE FUNCTION index_is_primary ( NAME, NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisprimary FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) INTO res; RETURN ok( COALESCE(res, false), 'Index ' || quote_ident($2) || ' should be on a primary key' ); END; $$ LANGUAGE plpgsql; -- index_is_primary( index ) CREATE OR REPLACE FUNCTION index_is_primary ( NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisprimary FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid WHERE ci.relname = $1 AND pg_catalog.pg_table_is_visible(ct.oid) INTO res; RETURN ok( COALESCE(res, false), 'Index ' || quote_ident($1) || ' should be on a primary key' ); END; $$ LANGUAGE plpgsql; -- is_clustered( schema, table, index, description ) CREATE OR REPLACE FUNCTION is_clustered ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisclustered FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 INTO res; RETURN ok( COALESCE(res, false), $4 ); END; $$ LANGUAGE plpgsql; -- is_clustered( schema, table, index ) CREATE OR REPLACE FUNCTION is_clustered ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT is_clustered( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be clustered on index ' || quote_ident($3) ); $$ LANGUAGE sql; -- is_clustered( table, index ) CREATE OR REPLACE FUNCTION is_clustered ( NAME, NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisclustered FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 INTO res; RETURN ok( COALESCE(res, false), 'Table ' || quote_ident($1) || ' should be clustered on index ' || quote_ident($2) ); END; $$ LANGUAGE plpgsql; -- is_clustered( index ) CREATE OR REPLACE FUNCTION is_clustered ( NAME ) RETURNS TEXT AS $$ DECLARE res boolean; BEGIN SELECT x.indisclustered FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ci.relname = $1 INTO res; RETURN ok( COALESCE(res, false), 'Table should be clustered on index ' || quote_ident($1) ); END; $$ LANGUAGE plpgsql; -- index_is_type( schema, table, index, type, description ) CREATE OR REPLACE FUNCTION index_is_type ( NAME, NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE aname name; BEGIN SELECT am.amname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace JOIN pg_catalog.pg_am am ON ci.relam = am.oid WHERE ct.relname = $2 AND ci.relname = $3 AND n.nspname = $1 INTO aname; return is( aname, $4, $5 ); END; $$ LANGUAGE plpgsql; -- index_is_type( schema, table, index, type ) CREATE OR REPLACE FUNCTION index_is_type ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_is_type( $1, $2, $3, $4, 'Index ' || quote_ident($3) || ' should be a ' || quote_ident($4) || ' index' ); $$ LANGUAGE SQL; -- index_is_type( table, index, type ) CREATE OR REPLACE FUNCTION index_is_type ( NAME, NAME, NAME ) RETURNS TEXT AS $$ DECLARE aname name; BEGIN SELECT am.amname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_am am ON ci.relam = am.oid WHERE ct.relname = $1 AND ci.relname = $2 INTO aname; return is( aname, $3, 'Index ' || quote_ident($2) || ' should be a ' || quote_ident($3) || ' index' ); END; $$ LANGUAGE plpgsql; -- index_is_type( index, type ) CREATE OR REPLACE FUNCTION index_is_type ( NAME, NAME ) RETURNS TEXT AS $$ DECLARE aname name; BEGIN SELECT am.amname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_am am ON ci.relam = am.oid WHERE ci.relname = $1 INTO aname; return is( aname, $2, 'Index ' || quote_ident($1) || ' should be a ' || quote_ident($2) || ' index' ); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _trig ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND t.tgname = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _trig ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid WHERE c.relname = $1 AND t.tgname = $2 AND pg_catalog.pg_table_is_visible(c.oid) ); $$ LANGUAGE SQL; -- has_trigger( schema, table, trigger, description ) CREATE OR REPLACE FUNCTION has_trigger ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _trig($1, $2, $3), $4); $$ LANGUAGE SQL; -- has_trigger( schema, table, trigger ) CREATE OR REPLACE FUNCTION has_trigger ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT has_trigger( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have trigger ' || quote_ident($3) ); $$ LANGUAGE sql; -- has_trigger( table, trigger, description ) CREATE OR REPLACE FUNCTION has_trigger ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _trig($1, $2), $3); $$ LANGUAGE sql; -- has_trigger( table, trigger ) CREATE OR REPLACE FUNCTION has_trigger ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _trig($1, $2), 'Table ' || quote_ident($1) || ' should have trigger ' || quote_ident($2)); $$ LANGUAGE SQL; -- hasnt_trigger( schema, table, trigger, description ) CREATE OR REPLACE FUNCTION hasnt_trigger ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _trig($1, $2, $3), $4); $$ LANGUAGE SQL; -- hasnt_trigger( schema, table, trigger ) CREATE OR REPLACE FUNCTION hasnt_trigger ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _trig($1, $2, $3), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not have trigger ' || quote_ident($3) ); $$ LANGUAGE sql; -- hasnt_trigger( table, trigger, description ) CREATE OR REPLACE FUNCTION hasnt_trigger ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _trig($1, $2), $3); $$ LANGUAGE sql; -- hasnt_trigger( table, trigger ) CREATE OR REPLACE FUNCTION hasnt_trigger ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _trig($1, $2), 'Table ' || quote_ident($1) || ' should not have trigger ' || quote_ident($2)); $$ LANGUAGE SQL; -- trigger_is( schema, table, trigger, schema, function, description ) CREATE OR REPLACE FUNCTION trigger_is ( NAME, NAME, NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE pname text; BEGIN SELECT quote_ident(ni.nspname) || '.' || quote_ident(p.proname) FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class ct ON ct.oid = t.tgrelid JOIN pg_catalog.pg_namespace nt ON nt.oid = ct.relnamespace JOIN pg_catalog.pg_proc p ON p.oid = t.tgfoid JOIN pg_catalog.pg_namespace ni ON ni.oid = p.pronamespace WHERE nt.nspname = $1 AND ct.relname = $2 AND t.tgname = $3 INTO pname; RETURN is( pname, quote_ident($4) || '.' || quote_ident($5), $6 ); END; $$ LANGUAGE plpgsql; -- trigger_is( schema, table, trigger, schema, function ) CREATE OR REPLACE FUNCTION trigger_is ( NAME, NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT trigger_is( $1, $2, $3, $4, $5, 'Trigger ' || quote_ident($3) || ' should call ' || quote_ident($4) || '.' || quote_ident($5) || '()' ); $$ LANGUAGE sql; -- trigger_is( table, trigger, function, description ) CREATE OR REPLACE FUNCTION trigger_is ( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ DECLARE pname text; BEGIN SELECT p.proname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class ct ON ct.oid = t.tgrelid JOIN pg_catalog.pg_proc p ON p.oid = t.tgfoid WHERE ct.relname = $1 AND t.tgname = $2 AND pg_catalog.pg_table_is_visible(ct.oid) INTO pname; RETURN is( pname, $3::text, $4 ); END; $$ LANGUAGE plpgsql; -- trigger_is( table, trigger, function ) CREATE OR REPLACE FUNCTION trigger_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT trigger_is( $1, $2, $3, 'Trigger ' || quote_ident($2) || ' should call ' || quote_ident($3) || '()' ); $$ LANGUAGE sql; -- has_schema( schema, description ) CREATE OR REPLACE FUNCTION has_schema( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( EXISTS( SELECT true FROM pg_catalog.pg_namespace WHERE nspname = $1 ), $2 ); $$ LANGUAGE sql; -- has_schema( schema ) CREATE OR REPLACE FUNCTION has_schema( NAME ) RETURNS TEXT AS $$ SELECT has_schema( $1, 'Schema ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE sql; -- hasnt_schema( schema, description ) CREATE OR REPLACE FUNCTION hasnt_schema( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT EXISTS( SELECT true FROM pg_catalog.pg_namespace WHERE nspname = $1 ), $2 ); $$ LANGUAGE sql; -- hasnt_schema( schema ) CREATE OR REPLACE FUNCTION hasnt_schema( NAME ) RETURNS TEXT AS $$ SELECT hasnt_schema( $1, 'Schema ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE sql; -- has_tablespace( tablespace, location, description ) CREATE OR REPLACE FUNCTION has_tablespace( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN IF pg_version_num() >= 90200 THEN RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 AND pg_tablespace_location(oid) = $2 ), $3 ); ELSE RETURN ok( EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 AND spclocation = $2 ), $3 ); END IF; END; $$ LANGUAGE plpgsql; -- has_tablespace( tablespace, description ) CREATE OR REPLACE FUNCTION has_tablespace( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 ), $2 ); $$ LANGUAGE sql; -- has_tablespace( tablespace ) CREATE OR REPLACE FUNCTION has_tablespace( NAME ) RETURNS TEXT AS $$ SELECT has_tablespace( $1, 'Tablespace ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE sql; -- hasnt_tablespace( tablespace, description ) CREATE OR REPLACE FUNCTION hasnt_tablespace( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT EXISTS( SELECT true FROM pg_catalog.pg_tablespace WHERE spcname = $1 ), $2 ); $$ LANGUAGE sql; -- hasnt_tablespace( tablespace ) CREATE OR REPLACE FUNCTION hasnt_tablespace( NAME ) RETURNS TEXT AS $$ SELECT hasnt_tablespace( $1, 'Tablespace ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_type( NAME, NAME, CHAR[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.typisdefined AND n.nspname = $1 AND t.typname = $2 AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_type( NAME, CHAR[] ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_type t WHERE t.typisdefined AND pg_catalog.pg_type_is_visible(t.oid) AND t.typname = $1 AND t.typtype = ANY( COALESCE($2, ARRAY['b', 'c', 'd', 'p', 'e']) ) ); $$ LANGUAGE sql; -- has_type( schema, type, description ) CREATE OR REPLACE FUNCTION has_type( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, $2, NULL ), $3 ); $$ LANGUAGE sql; -- has_type( schema, type ) CREATE OR REPLACE FUNCTION has_type( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_type( $1, $2, 'Type ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE sql; -- has_type( type, description ) CREATE OR REPLACE FUNCTION has_type( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, NULL ), $2 ); $$ LANGUAGE sql; -- has_type( type ) CREATE OR REPLACE FUNCTION has_type( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, NULL ), ('Type ' || quote_ident($1) || ' should exist')::text ); $$ LANGUAGE sql; -- hasnt_type( schema, type, description ) CREATE OR REPLACE FUNCTION hasnt_type( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, $2, NULL ), $3 ); $$ LANGUAGE sql; -- hasnt_type( schema, type ) CREATE OR REPLACE FUNCTION hasnt_type( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_type( $1, $2, 'Type ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE sql; -- hasnt_type( type, description ) CREATE OR REPLACE FUNCTION hasnt_type( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, NULL ), $2 ); $$ LANGUAGE sql; -- hasnt_type( type ) CREATE OR REPLACE FUNCTION hasnt_type( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, NULL ), ('Type ' || quote_ident($1) || ' should not exist')::text ); $$ LANGUAGE sql; -- has_domain( schema, domain, description ) CREATE OR REPLACE FUNCTION has_domain( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, $2, ARRAY['d'] ), $3 ); $$ LANGUAGE sql; -- has_domain( schema, domain ) CREATE OR REPLACE FUNCTION has_domain( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_domain( $1, $2, 'Domain ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE sql; -- has_domain( domain, description ) CREATE OR REPLACE FUNCTION has_domain( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, ARRAY['d'] ), $2 ); $$ LANGUAGE sql; -- has_domain( domain ) CREATE OR REPLACE FUNCTION has_domain( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, ARRAY['d'] ), ('Domain ' || quote_ident($1) || ' should exist')::text ); $$ LANGUAGE sql; -- hasnt_domain( schema, domain, description ) CREATE OR REPLACE FUNCTION hasnt_domain( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, $2, ARRAY['d'] ), $3 ); $$ LANGUAGE sql; -- hasnt_domain( schema, domain ) CREATE OR REPLACE FUNCTION hasnt_domain( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_domain( $1, $2, 'Domain ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE sql; -- hasnt_domain( domain, description ) CREATE OR REPLACE FUNCTION hasnt_domain( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, ARRAY['d'] ), $2 ); $$ LANGUAGE sql; -- hasnt_domain( domain ) CREATE OR REPLACE FUNCTION hasnt_domain( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, ARRAY['d'] ), ('Domain ' || quote_ident($1) || ' should not exist')::text ); $$ LANGUAGE sql; -- has_enum( schema, enum, description ) CREATE OR REPLACE FUNCTION has_enum( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, $2, ARRAY['e'] ), $3 ); $$ LANGUAGE sql; -- has_enum( schema, enum ) CREATE OR REPLACE FUNCTION has_enum( NAME, NAME ) RETURNS TEXT AS $$ SELECT has_enum( $1, $2, 'Enum ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE sql; -- has_enum( enum, description ) CREATE OR REPLACE FUNCTION has_enum( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, ARRAY['e'] ), $2 ); $$ LANGUAGE sql; -- has_enum( enum ) CREATE OR REPLACE FUNCTION has_enum( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_type( $1, ARRAY['e'] ), ('Enum ' || quote_ident($1) || ' should exist')::text ); $$ LANGUAGE sql; -- hasnt_enum( schema, enum, description ) CREATE OR REPLACE FUNCTION hasnt_enum( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, $2, ARRAY['e'] ), $3 ); $$ LANGUAGE sql; -- hasnt_enum( schema, enum ) CREATE OR REPLACE FUNCTION hasnt_enum( NAME, NAME ) RETURNS TEXT AS $$ SELECT hasnt_enum( $1, $2, 'Enum ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE sql; -- hasnt_enum( enum, description ) CREATE OR REPLACE FUNCTION hasnt_enum( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, ARRAY['e'] ), $2 ); $$ LANGUAGE sql; -- hasnt_enum( enum ) CREATE OR REPLACE FUNCTION hasnt_enum( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_type( $1, ARRAY['e'] ), ('Enum ' || quote_ident($1) || ' should not exist')::text ); $$ LANGUAGE sql; -- enum_has_labels( schema, enum, labels, description ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( ARRAY( SELECT e.enumlabel FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE t.typisdefined AND n.nspname = $1 AND t.typname = $2 AND t.typtype = 'e' ORDER BY e.enumsortorder ), $3, $4 ); $$ LANGUAGE sql; -- enum_has_labels( schema, enum, labels ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT enum_has_labels( $1, $2, $3, 'Enum ' || quote_ident($1) || '.' || quote_ident($2) || ' should have labels (' || array_to_string( $3, ', ' ) || ')' ); $$ LANGUAGE sql; -- enum_has_labels( enum, labels, description ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT is( ARRAY( SELECT e.enumlabel FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid WHERE t.typisdefined AND pg_catalog.pg_type_is_visible(t.oid) AND t.typname = $1 AND t.typtype = 'e' ORDER BY e.enumsortorder ), $2, $3 ); $$ LANGUAGE sql; -- enum_has_labels( enum, labels ) CREATE OR REPLACE FUNCTION enum_has_labels( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT enum_has_labels( $1, $2, 'Enum ' || quote_ident($1) || ' should have labels (' || array_to_string( $2, ', ' ) || ')' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_role( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_roles WHERE rolname = $1 ); $$ LANGUAGE sql STRICT; -- has_role( role, description ) CREATE OR REPLACE FUNCTION has_role( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_role($1), $2 ); $$ LANGUAGE sql; -- has_role( role ) CREATE OR REPLACE FUNCTION has_role( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_role($1), 'Role ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE sql; -- hasnt_role( role, description ) CREATE OR REPLACE FUNCTION hasnt_role( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_role($1), $2 ); $$ LANGUAGE sql; -- hasnt_role( role ) CREATE OR REPLACE FUNCTION hasnt_role( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_role($1), 'Role ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_user( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_user WHERE usename = $1); $$ LANGUAGE sql STRICT; -- has_user( user, description ) CREATE OR REPLACE FUNCTION has_user( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_user($1), $2 ); $$ LANGUAGE sql; -- has_user( user ) CREATE OR REPLACE FUNCTION has_user( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_user( $1 ), 'User ' || quote_ident($1) || ' should exist'); $$ LANGUAGE sql; -- hasnt_user( user, description ) CREATE OR REPLACE FUNCTION hasnt_user( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_user($1), $2 ); $$ LANGUAGE sql; -- hasnt_user( user ) CREATE OR REPLACE FUNCTION hasnt_user( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_user( $1 ), 'User ' || quote_ident($1) || ' should not exist'); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _is_super( NAME ) RETURNS BOOLEAN AS $$ SELECT rolsuper FROM pg_catalog.pg_roles WHERE rolname = $1 $$ LANGUAGE sql STRICT; -- is_superuser( user, description ) CREATE OR REPLACE FUNCTION is_superuser( NAME, TEXT ) RETURNS TEXT AS $$ DECLARE is_super boolean := _is_super($1); BEGIN IF is_super IS NULL THEN RETURN fail( $2 ) || E'\n' || diag( ' User ' || quote_ident($1) || ' does not exist') ; END IF; RETURN ok( is_super, $2 ); END; $$ LANGUAGE plpgsql; -- is_superuser( user ) CREATE OR REPLACE FUNCTION is_superuser( NAME ) RETURNS TEXT AS $$ SELECT is_superuser( $1, 'User ' || quote_ident($1) || ' should be a super user' ); $$ LANGUAGE sql; -- isnt_superuser( user, description ) CREATE OR REPLACE FUNCTION isnt_superuser( NAME, TEXT ) RETURNS TEXT AS $$ DECLARE is_super boolean := _is_super($1); BEGIN IF is_super IS NULL THEN RETURN fail( $2 ) || E'\n' || diag( ' User ' || quote_ident($1) || ' does not exist') ; END IF; RETURN ok( NOT is_super, $2 ); END; $$ LANGUAGE plpgsql; -- isnt_superuser( user ) CREATE OR REPLACE FUNCTION isnt_superuser( NAME ) RETURNS TEXT AS $$ SELECT isnt_superuser( $1, 'User ' || quote_ident($1) || ' should not be a super user' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _has_group( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_group WHERE groname = $1 ); $$ LANGUAGE sql STRICT; -- has_group( group, description ) CREATE OR REPLACE FUNCTION has_group( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _has_group($1), $2 ); $$ LANGUAGE sql; -- has_group( group ) CREATE OR REPLACE FUNCTION has_group( NAME ) RETURNS TEXT AS $$ SELECT ok( _has_group($1), 'Group ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE sql; -- hasnt_group( group, description ) CREATE OR REPLACE FUNCTION hasnt_group( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _has_group($1), $2 ); $$ LANGUAGE sql; -- hasnt_group( group ) CREATE OR REPLACE FUNCTION hasnt_group( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _has_group($1), 'Group ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _grolist ( NAME ) RETURNS oid[] AS $$ SELECT ARRAY( SELECT member FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles r ON m.roleid = r.oid WHERE r.rolname = $1 ); $$ LANGUAGE sql; -- is_member_of( role, members[], description ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE missing text[]; BEGIN IF NOT _has_role($1) THEN RETURN fail( $3 ) || E'\n' || diag ( ' Role ' || quote_ident($1) || ' does not exist' ); END IF; SELECT ARRAY( SELECT quote_ident($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) LEFT JOIN pg_catalog.pg_roles r ON rolname = $2[i] WHERE r.oid IS NULL OR NOT r.oid = ANY ( _grolist($1) ) ORDER BY s.i ) INTO missing; IF missing[1] IS NULL THEN RETURN ok( true, $3 ); END IF; RETURN ok( false, $3 ) || E'\n' || diag( ' Members missing from the ' || quote_ident($1) || E' role:\n ' || array_to_string( missing, E'\n ') ); END; $$ LANGUAGE plpgsql; -- is_member_of( role, member, description ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT is_member_of( $1, ARRAY[$2], $3 ); $$ LANGUAGE SQL; -- is_member_of( role, members[] ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT is_member_of( $1, $2, 'Should have members of role ' || quote_ident($1) ); $$ LANGUAGE SQL; -- is_member_of( role, member ) CREATE OR REPLACE FUNCTION is_member_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT is_member_of( $1, ARRAY[$2] ); $$ LANGUAGE SQL; -- isnt_member_of( role, members[], description ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE extra text[]; BEGIN IF NOT _has_role($1) THEN RETURN fail( $3 ) || E'\n' || diag ( ' Role ' || quote_ident($1) || ' does not exist' ); END IF; SELECT ARRAY( SELECT quote_ident($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) LEFT JOIN pg_catalog.pg_roles r ON rolname = $2[i] WHERE r.oid = ANY ( _grolist($1) ) ORDER BY s.i ) INTO extra; IF extra[1] IS NULL THEN RETURN ok( true, $3 ); END IF; RETURN ok( false, $3 ) || E'\n' || diag( ' Members, who should not be in ' || quote_ident($1) || E' role:\n ' || array_to_string( extra, E'\n ') ); END; $$ LANGUAGE plpgsql; -- isnt_member_of( role, member, description ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, ARRAY[$2], $3 ); $$ LANGUAGE SQL; -- isnt_member_of( role, members[] ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, $2, 'Should not have members of role ' || quote_ident($1) ); $$ LANGUAGE SQL; -- isnt_member_of( role, member ) CREATE OR REPLACE FUNCTION isnt_member_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT isnt_member_of( $1, ARRAY[$2] ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _cmp_types(oid, name) RETURNS BOOLEAN AS $$ SELECT pg_catalog.format_type($1, NULL) = _typename($2); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _cast_exists ( NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_cast c JOIN pg_catalog.pg_proc p ON c.castfunc = p.oid JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid WHERE _cmp_types(castsource, $1) AND _cmp_types(casttarget, $2) AND n.nspname = $3 AND p.proname = $4 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _cast_exists ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_cast c JOIN pg_catalog.pg_proc p ON c.castfunc = p.oid WHERE _cmp_types(castsource, $1) AND _cmp_types(casttarget, $2) AND p.proname = $3 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _cast_exists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_cast c WHERE _cmp_types(castsource, $1) AND _cmp_types(casttarget, $2) ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type, schema, function, description ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2, $3, $4 ), $5 ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type, schema, function ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2, $3, $4 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') WITH FUNCTION ' || quote_ident($3) || '.' || quote_ident($4) || '() should exist' ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type, function, description ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type, function ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2, $3 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') WITH FUNCTION ' || quote_ident($3) || '() should exist' ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type, description ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_cast( source_type, target_type ) CREATE OR REPLACE FUNCTION has_cast ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _cast_exists( $1, $2 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') should exist' ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type, schema, function, description ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2, $3, $4 ), $5 ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type, schema, function ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2, $3, $4 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') WITH FUNCTION ' || quote_ident($3) || '.' || quote_ident($4) || '() should not exist' ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type, function, description ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type, function ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2, $3 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') WITH FUNCTION ' || quote_ident($3) || '() should not exist' ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type, description ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_cast( source_type, target_type ) CREATE OR REPLACE FUNCTION hasnt_cast ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _cast_exists( $1, $2 ), 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _expand_context( char ) RETURNS text AS $$ SELECT CASE $1 WHEN 'i' THEN 'implicit' WHEN 'a' THEN 'assignment' WHEN 'e' THEN 'explicit' ELSE 'unknown' END $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _get_context( NAME, NAME ) RETURNS "char" AS $$ SELECT c.castcontext FROM pg_catalog.pg_cast c WHERE _cmp_types(castsource, $1) AND _cmp_types(casttarget, $2) $$ LANGUAGE SQL; -- cast_context_is( source_type, target_type, context, description ) CREATE OR REPLACE FUNCTION cast_context_is( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE want char = substring(LOWER($3) FROM 1 FOR 1); have char := _get_context($1, $2); BEGIN IF have IS NOT NULL THEN RETURN is( _expand_context(have), _expand_context(want), $4 ); END IF; RETURN ok( false, $4 ) || E'\n' || diag( ' Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') does not exist' ); END; $$ LANGUAGE plpgsql; -- cast_context_is( source_type, target_type, context ) CREATE OR REPLACE FUNCTION cast_context_is( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT cast_context_is( $1, $2, $3, 'Cast (' || quote_ident($1) || ' AS ' || quote_ident($2) || ') context should be ' || _expand_context(substring(LOWER($3) FROM 1 FOR 1)) ); $$ LANGUAGE SQL; -- _op_exists( left_type, schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $2 AND o.oprname = $3 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $4 IS NULL ELSE _cmp_types(o.oprright, _typename($4)) END AND _cmp_types(o.oprresult, $5) ); $$ LANGUAGE SQL; -- _op_exists( left_type, name, right_type, return_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o WHERE pg_catalog.pg_operator_is_visible(o.oid) AND o.oprname = $2 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $3 IS NULL ELSE _cmp_types(o.oprright, _typename($3)) END AND _cmp_types(o.oprresult, $4) ); $$ LANGUAGE SQL; -- _op_exists( left_type, name, right_type ) CREATE OR REPLACE FUNCTION _op_exists ( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_operator o WHERE pg_catalog.pg_operator_is_visible(o.oid) AND o.oprname = $2 AND CASE o.oprkind WHEN 'l' THEN $1 IS NULL ELSE _cmp_types(o.oprleft, _typename($1)) END AND CASE o.oprkind WHEN 'r' THEN $3 IS NULL ELSE _cmp_types(o.oprright, _typename($3)) END ); $$ LANGUAGE SQL; -- has_operator( left_type, schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- has_operator( left_type, schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3, $4, $5 ), 'Operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',' || $4 || ') RETURNS ' || $5 || ' should exist' ); $$ LANGUAGE SQL; -- has_operator( left_type, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3, $4 ), $5 ); $$ LANGUAGE SQL; -- has_operator( left_type, name, right_type, return_type ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3, $4 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') RETURNS ' || $4 || ' should exist' ); $$ LANGUAGE SQL; -- has_operator( left_type, name, right_type, description ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- has_operator( left_type, name, right_type ) CREATE OR REPLACE FUNCTION has_operator ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') should exist' ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4, $5 ), 'Operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',' || $4 || ') RETURNS ' || $5 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4 ), $5 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, $4 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type, description ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- hasnt_operator( left_type, name, right_type ) CREATE OR REPLACE FUNCTION hasnt_operator ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3 ), 'Operator ' || $2 || '(' || $1 || ',' || $3 || ') should not exist' ); $$ LANGUAGE SQL; -- has_leftop( schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2, $3, $4), $5 ); $$ LANGUAGE SQL; -- has_leftop( schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2, $3, $4 ), 'Left operator ' || quote_ident($1) || '.' || $2 || '(NONE,' || $3 || ') RETURNS ' || $4 || ' should exist' ); $$ LANGUAGE SQL; -- has_leftop( name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- has_leftop( name, right_type, return_type ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2, $3 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') RETURNS ' || $3 || ' should exist' ); $$ LANGUAGE SQL; -- has_leftop( name, right_type, description ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2), $3 ); $$ LANGUAGE SQL; -- has_leftop( name, right_type ) CREATE OR REPLACE FUNCTION has_leftop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists(NULL, $1, $2 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') should exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( schema, name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3, $4), $5 ); $$ LANGUAGE SQL; -- hasnt_leftop( schema, name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3, $4 ), 'Left operator ' || quote_ident($1) || '.' || $2 || '(NONE,' || $3 || ') RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, return_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2, $3 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') RETURNS ' || $3 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type, description ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2), $3 ); $$ LANGUAGE SQL; -- hasnt_leftop( name, right_type ) CREATE OR REPLACE FUNCTION hasnt_leftop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists(NULL, $1, $2 ), 'Left operator ' || $1 || '(NONE,' || $2 || ') should not exist' ); $$ LANGUAGE SQL; -- has_rightop( left_type, schema, name, return_type, description ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists( $1, $2, $3, NULL, $4), $5 ); $$ LANGUAGE SQL; -- has_rightop( left_type, schema, name, return_type ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, $3, NULL, $4 ), 'Right operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',NONE) RETURNS ' || $4 || ' should exist' ); $$ LANGUAGE SQL; -- has_rightop( left_type, name, return_type, description ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists( $1, $2, NULL, $3), $4 ); $$ LANGUAGE SQL; -- has_rightop( left_type, name, return_type ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, NULL, $3 ), 'Right operator ' || $2 || '(' || $1 || ',NONE) RETURNS ' || $3 || ' should exist' ); $$ LANGUAGE SQL; -- has_rightop( left_type, name, description ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _op_exists( $1, $2, NULL), $3 ); $$ LANGUAGE SQL; -- has_rightop( left_type, name ) CREATE OR REPLACE FUNCTION has_rightop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _op_exists($1, $2, NULL ), 'Right operator ' || $2 || '(' || $1 || ',NONE) should exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, schema, name, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, $3, NULL, $4), $5 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, schema, name, return_type ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, $3, NULL, $4 ), 'Right operator ' || quote_ident($2) || '.' || $3 || '(' || $1 || ',NONE) RETURNS ' || $4 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, return_type, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, NULL, $3), $4 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, return_type ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, NULL, $3 ), 'Right operator ' || $2 || '(' || $1 || ',NONE) RETURNS ' || $3 || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name, description ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists( $1, $2, NULL), $3 ); $$ LANGUAGE SQL; -- hasnt_rightop( left_type, name ) CREATE OR REPLACE FUNCTION hasnt_rightop ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _op_exists($1, $2, NULL ), 'Right operator ' || $2 || '(' || $1 || ',NONE) should not exist' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _are ( text, name[], name[], TEXT ) RETURNS TEXT AS $$ DECLARE what ALIAS FOR $1; extras ALIAS FOR $2; missing ALIAS FOR $3; descr ALIAS FOR $4; msg TEXT := ''; res BOOLEAN := TRUE; BEGIN IF extras[1] IS NOT NULL THEN res = FALSE; msg := E'\n' || diag( ' Extra ' || what || E':\n ' || _ident_array_to_sorted_string( extras, E'\n ' ) ); END IF; IF missing[1] IS NOT NULL THEN res = FALSE; msg := msg || E'\n' || diag( ' Missing ' || what || E':\n ' || _ident_array_to_sorted_string( missing, E'\n ' ) ); END IF; RETURN ok(res, descr) || msg; END; $$ LANGUAGE plpgsql; -- tablespaces_are( tablespaces, description ) CREATE OR REPLACE FUNCTION tablespaces_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'tablespaces', ARRAY( SELECT spcname FROM pg_catalog.pg_tablespace EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT spcname FROM pg_catalog.pg_tablespace ), $2 ); $$ LANGUAGE SQL; -- tablespaces_are( tablespaces ) CREATE OR REPLACE FUNCTION tablespaces_are ( NAME[] ) RETURNS TEXT AS $$ SELECT tablespaces_are( $1, 'There should be the correct tablespaces' ); $$ LANGUAGE SQL; -- schemas_are( schemas, description ) CREATE OR REPLACE FUNCTION schemas_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'schemas', ARRAY( SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg\_%' AND nspname <> 'information_schema' ), $2 ); $$ LANGUAGE SQL; -- schemas_are( schemas ) CREATE OR REPLACE FUNCTION schemas_are ( NAME[] ) RETURNS TEXT AS $$ SELECT schemas_are( $1, 'There should be the correct schemas' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR[], NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname NOT IN('pg_all_foreign_keys', 'tap_funky', '__tresults___numb_seq', '__tcache___id_seq') EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR[], NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE pg_catalog.pg_table_is_visible(c.oid) AND n.nspname <> 'pg_catalog' AND c.relkind = ANY($1) AND c.relname NOT IN ('__tcache__', 'pg_all_foreign_keys', 'tap_funky', '__tresults___numb_seq', '__tcache___id_seq') EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR, NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT _extras(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extras ( CHAR, NAME[] ) RETURNS NAME[] AS $$ SELECT _extras(ARRAY[$1], $2); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR[], NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR[], NAME[] ) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT c.relname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE pg_catalog.pg_table_is_visible(c.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind = ANY($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR, NAME, NAME[] ) RETURNS NAME[] AS $$ SELECT _missing(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _missing ( CHAR, NAME[] ) RETURNS NAME[] AS $$ SELECT _missing(ARRAY[$1], $2); $$ LANGUAGE SQL; -- tables_are( schema, tables, description ) CREATE OR REPLACE FUNCTION tables_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1, $2), _missing('{r,p}'::char[], $1, $2), $3); $$ LANGUAGE SQL; -- tables_are( tables, description ) CREATE OR REPLACE FUNCTION tables_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1), _missing('{r,p}'::char[], $1), $2); $$ LANGUAGE SQL; -- tables_are( schema, tables ) CREATE OR REPLACE FUNCTION tables_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1, $2), _missing('{r,p}'::char[], $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct tables' ); $$ LANGUAGE SQL; -- tables_are( tables ) CREATE OR REPLACE FUNCTION tables_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'tables', _extras('{r,p}'::char[], $1), _missing('{r,p}'::char[], $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables' ); $$ LANGUAGE SQL; -- views_are( schema, views, description ) CREATE OR REPLACE FUNCTION views_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'views', _extras('v', $1, $2), _missing('v', $1, $2), $3); $$ LANGUAGE SQL; -- views_are( views, description ) CREATE OR REPLACE FUNCTION views_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'views', _extras('v', $1), _missing('v', $1), $2); $$ LANGUAGE SQL; -- views_are( schema, views ) CREATE OR REPLACE FUNCTION views_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'views', _extras('v', $1, $2), _missing('v', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct views' ); $$ LANGUAGE SQL; -- views_are( views ) CREATE OR REPLACE FUNCTION views_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'views', _extras('v', $1), _missing('v', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views' ); $$ LANGUAGE SQL; -- sequences_are( schema, sequences, description ) CREATE OR REPLACE FUNCTION sequences_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'sequences', _extras('S', $1, $2), _missing('S', $1, $2), $3); $$ LANGUAGE SQL; -- sequences_are( sequences, description ) CREATE OR REPLACE FUNCTION sequences_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'sequences', _extras('S', $1), _missing('S', $1), $2); $$ LANGUAGE SQL; -- sequences_are( schema, sequences ) CREATE OR REPLACE FUNCTION sequences_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'sequences', _extras('S', $1, $2), _missing('S', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct sequences' ); $$ LANGUAGE SQL; -- sequences_are( sequences ) CREATE OR REPLACE FUNCTION sequences_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'sequences', _extras('S', $1), _missing('S', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct sequences' ); $$ LANGUAGE SQL; -- functions_are( schema, functions[], description ) CREATE OR REPLACE FUNCTION functions_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'functions', ARRAY( SELECT name FROM tap_funky WHERE schema = $1 EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT name FROM tap_funky WHERE schema = $1 ), $3 ); $$ LANGUAGE SQL; -- functions_are( schema, functions[] ) CREATE OR REPLACE FUNCTION functions_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT functions_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct functions' ); $$ LANGUAGE SQL; -- functions_are( functions[], description ) CREATE OR REPLACE FUNCTION functions_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'functions', ARRAY( SELECT name FROM tap_funky WHERE is_visible AND schema NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT name FROM tap_funky WHERE is_visible AND schema NOT IN ('pg_catalog', 'information_schema') ), $2 ); $$ LANGUAGE SQL; -- functions_are( functions[] ) CREATE OR REPLACE FUNCTION functions_are ( NAME[] ) RETURNS TEXT AS $$ SELECT functions_are( $1, 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct functions' ); $$ LANGUAGE SQL; -- indexes_are( schema, table, indexes[], description ) CREATE OR REPLACE FUNCTION indexes_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'indexes', ARRAY( SELECT ci.relname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $2 AND n.nspname = $1 EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT ci.relname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $2 AND n.nspname = $1 ), $4 ); $$ LANGUAGE SQL; -- indexes_are( schema, table, indexes[] ) CREATE OR REPLACE FUNCTION indexes_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT indexes_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct indexes' ); $$ LANGUAGE SQL; -- indexes_are( table, indexes[], description ) CREATE OR REPLACE FUNCTION indexes_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'indexes', ARRAY( SELECT ci.relname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $1 AND pg_catalog.pg_table_is_visible(ct.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT ci.relname FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE ct.relname = $1 AND pg_catalog.pg_table_is_visible(ct.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') ), $3 ); $$ LANGUAGE SQL; -- indexes_are( table, indexes[] ) CREATE OR REPLACE FUNCTION indexes_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT indexes_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct indexes' ); $$ LANGUAGE SQL; -- users_are( users[], description ) CREATE OR REPLACE FUNCTION users_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'users', ARRAY( SELECT usename FROM pg_catalog.pg_user EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT usename FROM pg_catalog.pg_user ), $2 ); $$ LANGUAGE SQL; -- users_are( users[] ) CREATE OR REPLACE FUNCTION users_are( NAME[] ) RETURNS TEXT AS $$ SELECT users_are( $1, 'There should be the correct users' ); $$ LANGUAGE SQL; -- groups_are( groups[], description ) CREATE OR REPLACE FUNCTION groups_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'groups', ARRAY( SELECT groname FROM pg_catalog.pg_group EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT groname FROM pg_catalog.pg_group ), $2 ); $$ LANGUAGE SQL; -- groups_are( groups[] ) CREATE OR REPLACE FUNCTION groups_are( NAME[] ) RETURNS TEXT AS $$ SELECT groups_are( $1, 'There should be the correct groups' ); $$ LANGUAGE SQL; -- languages_are( languages[], description ) CREATE OR REPLACE FUNCTION languages_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'languages', ARRAY( SELECT lanname FROM pg_catalog.pg_language WHERE lanispl EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT lanname FROM pg_catalog.pg_language WHERE lanispl ), $2 ); $$ LANGUAGE SQL; -- languages_are( languages[] ) CREATE OR REPLACE FUNCTION languages_are( NAME[] ) RETURNS TEXT AS $$ SELECT languages_are( $1, 'There should be the correct procedural languages' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _is_trusted( NAME ) RETURNS BOOLEAN AS $$ SELECT lanpltrusted FROM pg_catalog.pg_language WHERE lanname = $1; $$ LANGUAGE SQL; -- has_language( language, description) CREATE OR REPLACE FUNCTION has_language( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_trusted($1) IS NOT NULL, $2 ); $$ LANGUAGE SQL; -- has_language( language ) CREATE OR REPLACE FUNCTION has_language( NAME ) RETURNS TEXT AS $$ SELECT ok( _is_trusted($1) IS NOT NULL, 'Procedural language ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_language( language, description) CREATE OR REPLACE FUNCTION hasnt_language( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_trusted($1) IS NULL, $2 ); $$ LANGUAGE SQL; -- hasnt_language( language ) CREATE OR REPLACE FUNCTION hasnt_language( NAME ) RETURNS TEXT AS $$ SELECT ok( _is_trusted($1) IS NULL, 'Procedural language ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- language_is_trusted( language, description ) CREATE OR REPLACE FUNCTION language_is_trusted( NAME, TEXT ) RETURNS TEXT AS $$ DECLARE is_trusted boolean := _is_trusted($1); BEGIN IF is_trusted IS NULL THEN RETURN fail( $2 ) || E'\n' || diag( ' Procedural language ' || quote_ident($1) || ' does not exist') ; END IF; RETURN ok( is_trusted, $2 ); END; $$ LANGUAGE plpgsql; -- language_is_trusted( language ) CREATE OR REPLACE FUNCTION language_is_trusted( NAME ) RETURNS TEXT AS $$ SELECT language_is_trusted($1, 'Procedural language ' || quote_ident($1) || ' should be trusted' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _opc_exists( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 AND oc.opcname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _opc_exists( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_opclass oc WHERE oc.opcname = $1 AND pg_opclass_is_visible(oid) ); $$ LANGUAGE SQL; -- has_opclass( schema, name, description ) CREATE OR REPLACE FUNCTION has_opclass( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_opclass( schema, name ) CREATE OR REPLACE FUNCTION has_opclass( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1, $2 ), 'Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' should exist' ); $$ LANGUAGE SQL; -- has_opclass( name, description ) CREATE OR REPLACE FUNCTION has_opclass( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1 ), $2) $$ LANGUAGE SQL; -- has_opclass( name ) CREATE OR REPLACE FUNCTION has_opclass( NAME ) RETURNS TEXT AS $$ SELECT ok( _opc_exists( $1 ), 'Operator class ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_opclass( schema, name, description ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_opclass( schema, name ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1, $2 ), 'Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' should not exist' ); $$ LANGUAGE SQL; -- hasnt_opclass( name, description ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1 ), $2) $$ LANGUAGE SQL; -- hasnt_opclass( name ) CREATE OR REPLACE FUNCTION hasnt_opclass( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _opc_exists( $1 ), 'Operator class ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- opclasses_are( schema, opclasses[], description ) CREATE OR REPLACE FUNCTION opclasses_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'operator classes', ARRAY( SELECT oc.opcname FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT oc.opcname FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 ), $3 ); $$ LANGUAGE SQL; -- opclasses_are( schema, opclasses[] ) CREATE OR REPLACE FUNCTION opclasses_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT opclasses_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct operator classes' ); $$ LANGUAGE SQL; -- opclasses_are( opclasses[], description ) CREATE OR REPLACE FUNCTION opclasses_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'operator classes', ARRAY( SELECT oc.opcname FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_opclass_is_visible(oc.oid) EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT oc.opcname FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_opclass_is_visible(oc.oid) ), $2 ); $$ LANGUAGE SQL; -- opclasses_are( opclasses[] ) CREATE OR REPLACE FUNCTION opclasses_are ( NAME[] ) RETURNS TEXT AS $$ SELECT opclasses_are( $1, 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct operator classes' ); $$ LANGUAGE SQL; -- rules_are( schema, table, rules[], description ) CREATE OR REPLACE FUNCTION rules_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'rules', ARRAY( SELECT r.rulename FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE c.relname = $2 AND n.nspname = $1 EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT r.rulename FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE c.relname = $2 AND n.nspname = $1 ), $4 ); $$ LANGUAGE SQL; -- rules_are( schema, table, rules[] ) CREATE OR REPLACE FUNCTION rules_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT rules_are( $1, $2, $3, 'Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct rules' ); $$ LANGUAGE SQL; -- rules_are( table, rules[], description ) CREATE OR REPLACE FUNCTION rules_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'rules', ARRAY( SELECT r.rulename FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_table_is_visible(c.oid) EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT r.rulename FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid AND c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_table_is_visible(c.oid) ), $3 ); $$ LANGUAGE SQL; -- rules_are( table, rules[] ) CREATE OR REPLACE FUNCTION rules_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT rules_are( $1, $2, 'Relation ' || quote_ident($1) || ' should have the correct rules' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _is_instead( NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT r.is_instead FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE r.rulename = $3 AND c.relname = $2 AND n.nspname = $1 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _is_instead( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT r.is_instead FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class WHERE r.rulename = $2 AND c.relname = $1 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- has_rule( schema, table, rule, description ) CREATE OR REPLACE FUNCTION has_rule( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2, $3) IS NOT NULL, $4 ); $$ LANGUAGE SQL; -- has_rule( schema, table, rule ) CREATE OR REPLACE FUNCTION has_rule( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2, $3) IS NOT NULL, 'Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should have rule ' || quote_ident($3) ); $$ LANGUAGE SQL; -- has_rule( table, rule, description ) CREATE OR REPLACE FUNCTION has_rule( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2) IS NOT NULL, $3 ); $$ LANGUAGE SQL; -- has_rule( table, rule ) CREATE OR REPLACE FUNCTION has_rule( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2) IS NOT NULL, 'Relation ' || quote_ident($1) || ' should have rule ' || quote_ident($2) ); $$ LANGUAGE SQL; -- hasnt_rule( schema, table, rule, description ) CREATE OR REPLACE FUNCTION hasnt_rule( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2, $3) IS NULL, $4 ); $$ LANGUAGE SQL; -- hasnt_rule( schema, table, rule ) CREATE OR REPLACE FUNCTION hasnt_rule( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2, $3) IS NULL, 'Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should not have rule ' || quote_ident($3) ); $$ LANGUAGE SQL; -- hasnt_rule( table, rule, description ) CREATE OR REPLACE FUNCTION hasnt_rule( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2) IS NULL, $3 ); $$ LANGUAGE SQL; -- hasnt_rule( table, rule ) CREATE OR REPLACE FUNCTION hasnt_rule( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _is_instead($1, $2) IS NULL, 'Relation ' || quote_ident($1) || ' should not have rule ' || quote_ident($2) ); $$ LANGUAGE SQL; -- rule_is_instead( schema, table, rule, description ) CREATE OR REPLACE FUNCTION rule_is_instead( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE is_it boolean := _is_instead($1, $2, $3); BEGIN IF is_it IS NOT NULL THEN RETURN ok( is_it, $4 ); END IF; RETURN ok( FALSE, $4 ) || E'\n' || diag( ' Rule ' || quote_ident($3) || ' does not exist' ); END; $$ LANGUAGE plpgsql; -- rule_is_instead( schema, table, rule ) CREATE OR REPLACE FUNCTION rule_is_instead( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT rule_is_instead( $1, $2, $3, 'Rule ' || quote_ident($3) || ' on relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should be an INSTEAD rule' ); $$ LANGUAGE SQL; -- rule_is_instead( table, rule, description ) CREATE OR REPLACE FUNCTION rule_is_instead( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE is_it boolean := _is_instead($1, $2); BEGIN IF is_it IS NOT NULL THEN RETURN ok( is_it, $3 ); END IF; RETURN ok( FALSE, $3 ) || E'\n' || diag( ' Rule ' || quote_ident($2) || ' does not exist' ); END; $$ LANGUAGE plpgsql; -- rule_is_instead( table, rule ) CREATE OR REPLACE FUNCTION rule_is_instead( NAME, NAME ) RETURNS TEXT AS $$ SELECT rule_is_instead($1, $2, 'Rule ' || quote_ident($2) || ' on relation ' || quote_ident($1) || ' should be an INSTEAD rule' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _expand_on( char ) RETURNS text AS $$ SELECT CASE $1 WHEN '1' THEN 'SELECT' WHEN '2' THEN 'UPDATE' WHEN '3' THEN 'INSERT' WHEN '4' THEN 'DELETE' ELSE 'UNKNOWN' END $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _contract_on( TEXT ) RETURNS "char" AS $$ SELECT CASE substring(LOWER($1) FROM 1 FOR 1) WHEN 's' THEN '1'::"char" WHEN 'u' THEN '2'::"char" WHEN 'i' THEN '3'::"char" WHEN 'd' THEN '4'::"char" ELSE '0'::"char" END $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _rule_on( NAME, NAME, NAME ) RETURNS "char" AS $$ SELECT r.ev_type FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE r.rulename = $3 AND c.relname = $2 AND n.nspname = $1 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _rule_on( NAME, NAME ) RETURNS "char" AS $$ SELECT r.ev_type FROM pg_catalog.pg_rewrite r JOIN pg_catalog.pg_class c ON c.oid = r.ev_class WHERE r.rulename = $2 AND c.relname = $1 $$ LANGUAGE SQL; -- rule_is_on( schema, table, rule, event, description ) CREATE OR REPLACE FUNCTION rule_is_on( NAME, NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE want char := _contract_on($4); have char := _rule_on($1, $2, $3); BEGIN IF have IS NOT NULL THEN RETURN is( _expand_on(have), _expand_on(want), $5 ); END IF; RETURN ok( false, $5 ) || E'\n' || diag( ' Rule ' || quote_ident($3) || ' does not exist on ' || quote_ident($1) || '.' || quote_ident($2) ); END; $$ LANGUAGE plpgsql; -- rule_is_on( schema, table, rule, event ) CREATE OR REPLACE FUNCTION rule_is_on( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT rule_is_on( $1, $2, $3, $4, 'Rule ' || quote_ident($3) || ' should be on ' || _expand_on(_contract_on($4)::char) || ' to ' || quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- rule_is_on( table, rule, event, description ) CREATE OR REPLACE FUNCTION rule_is_on( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE want char := _contract_on($3); have char := _rule_on($1, $2); BEGIN IF have IS NOT NULL THEN RETURN is( _expand_on(have), _expand_on(want), $4 ); END IF; RETURN ok( false, $4 ) || E'\n' || diag( ' Rule ' || quote_ident($2) || ' does not exist on ' || quote_ident($1) ); END; $$ LANGUAGE plpgsql; -- rule_is_on( table, rule, event ) CREATE OR REPLACE FUNCTION rule_is_on( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT rule_is_on( $1, $2, $3, 'Rule ' || quote_ident($2) || ' should be on ' || _expand_on(_contract_on($3)::char) || ' to ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _nosuch( NAME, NAME, NAME[]) RETURNS TEXT AS $$ SELECT E'\n' || diag( ' Function ' || CASE WHEN $1 IS NOT NULL THEN quote_ident($1) || '.' ELSE '' END || quote_ident($2) || '(' || array_to_string($3, ', ') || ') does not exist' ); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _func_compare( NAME, NAME, NAME[], anyelement, anyelement, TEXT) RETURNS TEXT AS $$ SELECT CASE WHEN $4 IS NULL THEN ok( FALSE, $6 ) || _nosuch($1, $2, $3) ELSE is( $4, $5, $6 ) END; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _func_compare( NAME, NAME, NAME[], boolean, TEXT) RETURNS TEXT AS $$ SELECT CASE WHEN $4 IS NULL THEN ok( FALSE, $5 ) || _nosuch($1, $2, $3) ELSE ok( $4, $5 ) END; $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _func_compare( NAME, NAME, anyelement, anyelement, TEXT) RETURNS TEXT AS $$ SELECT CASE WHEN $3 IS NULL THEN ok( FALSE, $5 ) || _nosuch($1, $2, '{}') ELSE is( $3, $4, $5 ) END; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _func_compare( NAME, NAME, boolean, TEXT) RETURNS TEXT AS $$ SELECT CASE WHEN $3 IS NULL THEN ok( FALSE, $4 ) || _nosuch($1, $2, '{}') ELSE ok( $3, $4 ) END; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _lang ( NAME, NAME, NAME[] ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.schema = $1 and f.name = $2 AND f.args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _lang ( NAME, NAME ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.schema = $1 and f.name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _lang ( NAME, NAME[] ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.name = $1 AND f.args = _funkargs($2) AND f.is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _lang ( NAME ) RETURNS NAME AS $$ SELECT l.lanname FROM tap_funky f JOIN pg_catalog.pg_language l ON f.langoid = l.oid WHERE f.name = $1 AND f.is_visible; $$ LANGUAGE SQL; -- function_lang_is( schema, function, args[], language, description ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _lang($1, $2, $3), $4, $5 ); $$ LANGUAGE SQL; -- function_lang_is( schema, function, args[], language ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_lang_is( $1, $2, $3, $4, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be written in ' || quote_ident($4) ); $$ LANGUAGE SQL; -- function_lang_is( schema, function, language, description ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _lang($1, $2), $3, $4 ); $$ LANGUAGE SQL; -- function_lang_is( schema, function, language ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT function_lang_is( $1, $2, $3, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be written in ' || quote_ident($3) ); $$ LANGUAGE SQL; -- function_lang_is( function, args[], language, description ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _lang($1, $2), $3, $4 ); $$ LANGUAGE SQL; -- function_lang_is( function, args[], language ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_lang_is( $1, $2, $3, 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be written in ' || quote_ident($3) ); $$ LANGUAGE SQL; -- function_lang_is( function, language, description ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _lang($1), $2, $3 ); $$ LANGUAGE SQL; -- function_lang_is( function, language ) CREATE OR REPLACE FUNCTION function_lang_is( NAME, NAME ) RETURNS TEXT AS $$ SELECT function_lang_is( $1, $2, 'Function ' || quote_ident($1) || '() should be written in ' || quote_ident($2) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME, NAME ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE schema = $1 AND name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _returns ( NAME ) RETURNS TEXT AS $$ SELECT returns FROM tap_funky WHERE name = $1 AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _retval(TEXT) RETURNS TEXT AS $$ DECLARE setof TEXT := substring($1 FROM '^setof[[:space:]]+'); BEGIN IF setof IS NULL THEN RETURN _typename($1); END IF; RETURN setof || _typename(substring($1 FROM char_length(setof)+1)); END; $$ LANGUAGE plpgsql; -- function_returns( schema, function, args[], type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _returns($1, $2, $3), _retval($4), $5 ); $$ LANGUAGE SQL; -- function_returns( schema, function, args[], type ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT function_returns( $1, $2, $3, $4, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should return ' || $4 ); $$ LANGUAGE SQL; -- function_returns( schema, function, type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _returns($1, $2), _retval($3), $4 ); $$ LANGUAGE SQL; -- function_returns( schema, function, type ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT function_returns( $1, $2, $3, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should return ' || $3 ); $$ LANGUAGE SQL; -- function_returns( function, args[], type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _returns($1, $2), _retval($3), $4 ); $$ LANGUAGE SQL; -- function_returns( function, args[], type ) CREATE OR REPLACE FUNCTION function_returns( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT function_returns( $1, $2, $3, 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should return ' || $3 ); $$ LANGUAGE SQL; -- function_returns( function, type, description ) CREATE OR REPLACE FUNCTION function_returns( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _returns($1), _retval($2), $3 ); $$ LANGUAGE SQL; -- function_returns( function, type ) CREATE OR REPLACE FUNCTION function_returns( NAME, TEXT ) RETURNS TEXT AS $$ SELECT function_returns( $1, $2, 'Function ' || quote_ident($1) || '() should return ' || $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE schema = $1 AND name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _definer ( NAME ) RETURNS BOOLEAN AS $$ SELECT is_definer FROM tap_funky WHERE name = $1 AND is_visible; $$ LANGUAGE SQL; -- is_definer( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_definer ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _definer($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_definer( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_definer( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _definer($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be security definer' ); $$ LANGUAGE sql; -- is_definer( schema, function, description ) CREATE OR REPLACE FUNCTION is_definer ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- is_definer( schema, function ) CREATE OR REPLACE FUNCTION is_definer( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _definer($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be security definer' ); $$ LANGUAGE sql; -- is_definer( function, args[], description ) CREATE OR REPLACE FUNCTION is_definer ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- is_definer( function, args[] ) CREATE OR REPLACE FUNCTION is_definer( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _definer($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be security definer' ); $$ LANGUAGE sql; -- is_definer( function, description ) CREATE OR REPLACE FUNCTION is_definer( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _definer($1), $2 ); $$ LANGUAGE sql; -- is_definer( function ) CREATE OR REPLACE FUNCTION is_definer( NAME ) RETURNS TEXT AS $$ SELECT ok( _definer($1), 'Function ' || quote_ident($1) || '() should be security definer' ); $$ LANGUAGE sql; -- isnt_definer( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _definer($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_definer( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_definer( schema, function ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_definer ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _definer($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_definer( function, args[] ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be security definer' ); $$ LANGUAGE sql; -- isnt_definer( function, description ) CREATE OR REPLACE FUNCTION isnt_definer( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _definer($1), $2 ); $$ LANGUAGE sql; -- isnt_definer( function ) CREATE OR REPLACE FUNCTION isnt_definer( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _definer($1), 'Function ' || quote_ident($1) || '() should not be security definer' ); $$ LANGUAGE sql; -- Returns true if the specified function exists and is the specified type, -- false if it exists and is not the specified type, and NULL if it does not -- exist. Types are f for a normal function, p for a procedure, a for an -- aggregate function, or w for a window function -- _type_func(type, schema, function, args[]) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE schema = $2 AND name = $3 AND args = _funkargs($4) $$ LANGUAGE SQL; -- _type_func(type, schema, function) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE schema = $2 AND name = $3 $$ LANGUAGE SQL; -- _type_func(type, function, args[]) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE name = $2 AND args = _funkargs($3) AND is_visible; $$ LANGUAGE SQL; -- _type_func(type, function) CREATE OR REPLACE FUNCTION _type_func ( "char", NAME ) RETURNS BOOLEAN AS $$ SELECT kind = $1 FROM tap_funky WHERE name = $2 AND is_visible; $$ LANGUAGE SQL; -- is_aggregate( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'a', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_aggregate( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('a', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( schema, function, description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_aggregate( schema, function ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( function, args[], description ) CREATE OR REPLACE FUNCTION is_aggregate ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_aggregate( function, args[] ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be an aggregate function' ); $$ LANGUAGE sql; -- is_aggregate( function, description ) CREATE OR REPLACE FUNCTION is_aggregate( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('a', $1), $2 ); $$ LANGUAGE sql; -- is_aggregate( function ) CREATE OR REPLACE FUNCTION is_aggregate( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('a', $1), 'Function ' || quote_ident($1) || '() should be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('a', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('a', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( schema, function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_aggregate ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('a', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_aggregate( function, args[] ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('a', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be an aggregate function' ); $$ LANGUAGE sql; -- isnt_aggregate( function, description ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('a', $1), $2 ); $$ LANGUAGE sql; -- isnt_aggregate( function ) CREATE OR REPLACE FUNCTION isnt_aggregate( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('a', $1), 'Function ' || quote_ident($1) || '() should not be an aggregate function' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _strict ( NAME, NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _strict ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE schema = $1 AND name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _strict ( NAME, NAME[] ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _strict ( NAME ) RETURNS BOOLEAN AS $$ SELECT is_strict FROM tap_funky WHERE name = $1 AND is_visible; $$ LANGUAGE SQL; -- is_strict( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_strict ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _strict($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_strict( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_strict( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _strict($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be strict' ); $$ LANGUAGE sql; -- is_strict( schema, function, description ) CREATE OR REPLACE FUNCTION is_strict ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- is_strict( schema, function ) CREATE OR REPLACE FUNCTION is_strict( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _strict($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be strict' ); $$ LANGUAGE sql; -- is_strict( function, args[], description ) CREATE OR REPLACE FUNCTION is_strict ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- is_strict( function, args[] ) CREATE OR REPLACE FUNCTION is_strict( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( _strict($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be strict' ); $$ LANGUAGE sql; -- is_strict( function, description ) CREATE OR REPLACE FUNCTION is_strict( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _strict($1), $2 ); $$ LANGUAGE sql; -- is_strict( function ) CREATE OR REPLACE FUNCTION is_strict( NAME ) RETURNS TEXT AS $$ SELECT ok( _strict($1), 'Function ' || quote_ident($1) || '() should be strict' ); $$ LANGUAGE sql; -- isnt_strict( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _strict($1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_strict( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_strict( schema, function ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_strict ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _strict($1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_strict( function, args[] ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be strict' ); $$ LANGUAGE sql; -- isnt_strict( function, description ) CREATE OR REPLACE FUNCTION isnt_strict( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _strict($1), $2 ); $$ LANGUAGE sql; -- isnt_strict( function ) CREATE OR REPLACE FUNCTION isnt_strict( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _strict($1), 'Function ' || quote_ident($1) || '() should not be strict' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _expand_vol( char ) RETURNS TEXT AS $$ SELECT CASE $1 WHEN 'i' THEN 'IMMUTABLE' WHEN 's' THEN 'STABLE' WHEN 'v' THEN 'VOLATILE' ELSE 'UNKNOWN' END $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _refine_vol( text ) RETURNS text AS $$ SELECT _expand_vol(substring(LOWER($1) FROM 1 FOR 1)::char); $$ LANGUAGE SQL IMMUTABLE; CREATE OR REPLACE FUNCTION _vol ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.schema = $1 and f.name = $2 AND f.args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _vol ( NAME, NAME ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.schema = $1 and f.name = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _vol ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.name = $1 AND f.args = _funkargs($2) AND f.is_visible; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _vol ( NAME ) RETURNS TEXT AS $$ SELECT _expand_vol(volatility) FROM tap_funky f WHERE f.name = $1 AND f.is_visible; $$ LANGUAGE SQL; -- volatility_is( schema, function, args[], volatility, description ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _vol($1, $2, $3), _refine_vol($4), $5 ); $$ LANGUAGE SQL; -- volatility_is( schema, function, args[], volatility ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT volatility_is( $1, $2, $3, $4, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be ' || _refine_vol($4) ); $$ LANGUAGE SQL; -- volatility_is( schema, function, volatility, description ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _vol($1, $2), _refine_vol($3), $4 ); $$ LANGUAGE SQL; -- volatility_is( schema, function, volatility ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT volatility_is( $1, $2, $3, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be ' || _refine_vol($3) ); $$ LANGUAGE SQL; -- volatility_is( function, args[], volatility, description ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME[], TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _vol($1, $2), _refine_vol($3), $4 ); $$ LANGUAGE SQL; -- volatility_is( function, args[], volatility ) CREATE OR REPLACE FUNCTION volatility_is( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT volatility_is( $1, $2, $3, 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be ' || _refine_vol($3) ); $$ LANGUAGE SQL; -- volatility_is( function, volatility, description ) CREATE OR REPLACE FUNCTION volatility_is( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _vol($1), _refine_vol($2), $3 ); $$ LANGUAGE SQL; -- volatility_is( function, volatility ) CREATE OR REPLACE FUNCTION volatility_is( NAME, TEXT ) RETURNS TEXT AS $$ SELECT volatility_is( $1, $2, 'Function ' || quote_ident($1) || '() should be ' || _refine_vol($2) ); $$ LANGUAGE SQL; -- check_test( test_output, pass, name, description, diag, match_diag ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT, BOOLEAN ) RETURNS SETOF TEXT AS $$ DECLARE tnumb INTEGER; aok BOOLEAN; adescr TEXT; res BOOLEAN; descr TEXT; adiag TEXT; have ALIAS FOR $1; eok ALIAS FOR $2; name ALIAS FOR $3; edescr ALIAS FOR $4; ediag ALIAS FOR $5; matchit ALIAS FOR $6; BEGIN -- What test was it that just ran? tnumb := currval('__tresults___numb_seq'); -- Fetch the results. aok := substring(have, 1, 2) = 'ok'; adescr := COALESCE(substring(have FROM E'(?:not )?ok [[:digit:]]+ - ([^\n]+)'), ''); -- Now delete those results. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb; IF NOT aok THEN PERFORM _set('failed', _get('failed') - 1); END IF; -- Set up the description. descr := coalesce( name || ' ', 'Test ' ) || 'should '; -- So, did the test pass? RETURN NEXT is( aok, eok, descr || CASE eok WHEN true then 'pass' ELSE 'fail' END ); -- Was the description as expected? IF edescr IS NOT NULL THEN RETURN NEXT is( adescr, edescr, descr || 'have the proper description' ); END IF; -- Were the diagnostics as expected? IF ediag IS NOT NULL THEN -- Remove ok and the test number. adiag := substring( have FROM CASE WHEN aok THEN 4 ELSE 9 END + char_length(tnumb::text) ); -- Remove the description, if there is one. IF adescr <> '' THEN adiag := substring( adiag FROM 1 + char_length( ' - ' || substr(diag( adescr ), 3) ) ); END IF; IF NOT aok THEN -- Remove failure message from ok(). adiag := substring(adiag FROM 1 + char_length(diag( 'Failed test ' || tnumb || CASE adescr WHEN '' THEN '' ELSE COALESCE(': "' || adescr || '"', '') END ))); END IF; IF ediag <> '' THEN -- Remove the space before the diagnostics. adiag := substring(adiag FROM 2); END IF; -- Remove the #s. adiag := replace( substring(adiag from 3), E'\n# ', E'\n' ); -- Now compare the diagnostics. IF matchit THEN RETURN NEXT matches( adiag, ediag, descr || 'have the proper diagnostics' ); ELSE RETURN NEXT is( adiag, ediag, descr || 'have the proper diagnostics' ); END IF; END IF; -- And we're done RETURN; END; $$ LANGUAGE plpgsql; -- check_test( test_output, pass, name, description, diag ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT, TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM check_test( $1, $2, $3, $4, $5, FALSE ); $$ LANGUAGE sql; -- check_test( test_output, pass, name, description ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT, TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM check_test( $1, $2, $3, $4, NULL, FALSE ); $$ LANGUAGE sql; -- check_test( test_output, pass, name ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN, TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM check_test( $1, $2, $3, NULL, NULL, FALSE ); $$ LANGUAGE sql; -- check_test( test_output, pass ) CREATE OR REPLACE FUNCTION check_test( TEXT, BOOLEAN ) RETURNS SETOF TEXT AS $$ SELECT * FROM check_test( $1, $2, NULL, NULL, NULL, FALSE ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT, TEXT ) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT DISTINCT (quote_ident(n.nspname) || '.' || quote_ident(p.proname)) COLLATE "C" AS pname FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid WHERE n.nspname = $1 AND p.proname ~ $2 AND ($3 IS NULL OR p.proname !~ $3) ORDER BY pname ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( NAME, TEXT ) RETURNS TEXT[] AS $$ SELECT findfuncs( $1, $2, NULL ) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( TEXT, TEXT ) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT DISTINCT (quote_ident(n.nspname) || '.' || quote_ident(p.proname)) COLLATE "C" AS pname FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON p.pronamespace = n.oid WHERE pg_catalog.pg_function_is_visible(p.oid) AND p.proname ~ $1 AND ($2 IS NULL OR p.proname !~ $2) ORDER BY pname ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION findfuncs( TEXT ) RETURNS TEXT[] AS $$ SELECT findfuncs( $1, NULL ) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _runem( text[], boolean ) RETURNS SETOF TEXT AS $$ DECLARE tap text; lbound int := array_lower($1, 1); BEGIN IF lbound IS NULL THEN RETURN; END IF; FOR i IN lbound..array_upper($1, 1) LOOP -- Send the name of the function to diag if warranted. IF $2 THEN RETURN NEXT diag( $1[i] || '()' ); END IF; -- Execute the tap function and return its results. FOR tap IN EXECUTE 'SELECT * FROM ' || $1[i] || '()' LOOP RETURN NEXT tap; END LOOP; END LOOP; RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _is_verbose() RETURNS BOOLEAN AS $$ SELECT current_setting('client_min_messages') NOT IN ( 'warning', 'error', 'fatal', 'panic' ); $$ LANGUAGE sql STABLE; -- do_tap( schema, pattern ) CREATE OR REPLACE FUNCTION do_tap( name, text ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runem( findfuncs($1, $2), _is_verbose() ); $$ LANGUAGE sql; -- do_tap( schema ) CREATE OR REPLACE FUNCTION do_tap( name ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runem( findfuncs($1, '^test'), _is_verbose() ); $$ LANGUAGE sql; -- do_tap( pattern ) CREATE OR REPLACE FUNCTION do_tap( text ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runem( findfuncs($1), _is_verbose() ); $$ LANGUAGE sql; -- do_tap() CREATE OR REPLACE FUNCTION do_tap( ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runem( findfuncs('^test'), _is_verbose()); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _currtest() RETURNS INTEGER AS $$ BEGIN RETURN currval('__tresults___numb_seq'); EXCEPTION WHEN object_not_in_prerequisite_state THEN RETURN 0; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _cleanup() RETURNS boolean AS $$ DROP SEQUENCE __tresults___numb_seq; DROP TABLE __tcache__; DROP SEQUENCE __tcache___id_seq; SELECT TRUE; $$ LANGUAGE sql; -- diag_test_name ( test_name ) CREATE OR REPLACE FUNCTION diag_test_name(TEXT) RETURNS TEXT AS $$ SELECT diag($1 || '()'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _runner( text[], text[], text[], text[], text[] ) RETURNS SETOF TEXT AS $$ DECLARE startup ALIAS FOR $1; shutdown ALIAS FOR $2; setup ALIAS FOR $3; teardown ALIAS FOR $4; tests ALIAS FOR $5; tap TEXT; tfaild INTEGER := 0; ffaild INTEGER := 0; tnumb INTEGER := 0; fnumb INTEGER := 0; tok BOOLEAN := TRUE; BEGIN BEGIN -- No plan support. PERFORM * FROM no_plan(); FOR tap IN SELECT * FROM _runem(startup, false) LOOP RETURN NEXT tap; END LOOP; EXCEPTION -- Catch all exceptions and simply rethrow custom exceptions. This -- will roll back everything in the above block. WHEN raise_exception THEN RAISE EXCEPTION '%', SQLERRM; END; -- Record how startup tests have failed. tfaild := num_failed(); FOR i IN 1..COALESCE(array_upper(tests, 1), 0) LOOP -- What subtest are we running? RETURN NEXT diag_test_name('Subtest: ' || tests[i]); -- Reset the results. tok := TRUE; tnumb := COALESCE(_get('curr_test'), 0); IF tnumb > 0 THEN EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH 1'; PERFORM _set('curr_test', 0); PERFORM _set('failed', 0); END IF; DECLARE errstate text; errmsg text; detail text; hint text; context text; schname text; tabname text; colname text; chkname text; typname text; BEGIN BEGIN -- Run the setup functions. FOR tap IN SELECT * FROM _runem(setup, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the actual test function. FOR tap IN EXECUTE 'SELECT * FROM ' || tests[i] || '()' LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Run the teardown functions. FOR tap IN SELECT * FROM _runem(teardown, false) LOOP RETURN NEXT regexp_replace(tap, '^', ' ', 'gn'); END LOOP; -- Emit the plan. fnumb := COALESCE(_get('curr_test'), 0); RETURN NEXT ' 1..' || fnumb; -- Emit any error messages. IF fnumb = 0 THEN RETURN NEXT ' # No tests run!'; tok = false; ELSE -- Report failures. ffaild := num_failed(); IF ffaild > 0 THEN tok := FALSE; RETURN NEXT ' ' || diag( 'Looks like you failed ' || ffaild || ' test' || CASE ffaild WHEN 1 THEN '' ELSE 's' END || ' of ' || fnumb ); END IF; END IF; EXCEPTION WHEN OTHERS THEN -- Something went wrong. Record that fact. errstate := SQLSTATE; errmsg := SQLERRM; GET STACKED DIAGNOSTICS detail = PG_EXCEPTION_DETAIL, hint = PG_EXCEPTION_HINT, context = PG_EXCEPTION_CONTEXT, schname = SCHEMA_NAME, tabname = TABLE_NAME, colname = COLUMN_NAME, chkname = CONSTRAINT_NAME, typname = PG_DATATYPE_NAME; END; -- Always raise an exception to rollback any changes. RAISE EXCEPTION '__TAP_ROLLBACK__'; EXCEPTION WHEN raise_exception THEN IF errmsg IS NOT NULL THEN -- Something went wrong. Emit the error message. tok := FALSE; RETURN NEXT regexp_replace( diag('Test died: ' || _error_diag( errstate, errmsg, detail, hint, context, schname, tabname, colname, chkname, typname )), '^', ' ', 'gn'); errmsg := NULL; END IF; END; -- Restore the sequence. EXECUTE 'ALTER SEQUENCE __tresults___numb_seq RESTART WITH ' || tnumb + 1; PERFORM _set('curr_test', tnumb); PERFORM _set('failed', tfaild); -- Record this test. RETURN NEXT ok(tok, tests[i]); IF NOT tok THEN tfaild := tfaild + 1; END IF; END LOOP; -- Run the shutdown functions. FOR tap IN SELECT * FROM _runem(shutdown, false) LOOP RETURN NEXT tap; END LOOP; -- Finish up. FOR tap IN SELECT * FROM _finish( COALESCE(_get('curr_test'), 0), 0, tfaild ) LOOP RETURN NEXT tap; END LOOP; -- Clean up and return. PERFORM _cleanup(); RETURN; END; $$ LANGUAGE plpgsql; -- runtests( schema, match ) CREATE OR REPLACE FUNCTION runtests( NAME, TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runner( findfuncs( $1, '^startup' ), findfuncs( $1, '^shutdown' ), findfuncs( $1, '^setup' ), findfuncs( $1, '^teardown' ), findfuncs( $1, $2, '^(startup|shutdown|setup|teardown)' ) ); $$ LANGUAGE sql; -- runtests( schema ) CREATE OR REPLACE FUNCTION runtests( NAME ) RETURNS SETOF TEXT AS $$ SELECT * FROM runtests( $1, '^test' ); $$ LANGUAGE sql; -- runtests( match ) CREATE OR REPLACE FUNCTION runtests( TEXT ) RETURNS SETOF TEXT AS $$ SELECT * FROM _runner( findfuncs( '^startup' ), findfuncs( '^shutdown' ), findfuncs( '^setup' ), findfuncs( '^teardown' ), findfuncs( $1, '^(startup|shutdown|setup|teardown)' ) ); $$ LANGUAGE sql; -- runtests( ) CREATE OR REPLACE FUNCTION runtests( ) RETURNS SETOF TEXT AS $$ SELECT * FROM runtests( '^test' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _temptable ( TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN EXECUTE 'CREATE TEMP TABLE ' || $2 || ' AS ' || _query($1); return $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _temptable ( anyarray, TEXT ) RETURNS TEXT AS $$ BEGIN CREATE TEMP TABLE _____coltmp___ AS SELECT $1[i] FROM generate_series(array_lower($1, 1), array_upper($1, 1)) s(i); EXECUTE 'ALTER TABLE _____coltmp___ RENAME TO ' || $2; return $2; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _temptypes( TEXT ) RETURNS TEXT AS $$ SELECT array_to_string(ARRAY( SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) FROM pg_catalog.pg_attribute a JOIN pg_catalog.pg_class c ON a.attrelid = c.oid WHERE c.oid = ('pg_temp.' || $1)::pg_catalog.regclass AND attnum > 0 AND NOT attisdropped ORDER BY attnum ), ','); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _docomp( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; extras TEXT[] := '{}'; missing TEXT[] := '{}'; res BOOLEAN := TRUE; msg TEXT := ''; rec RECORD; BEGIN BEGIN -- Find extra records. FOR rec in EXECUTE 'SELECT * FROM ' || have || ' EXCEPT ' || $4 || 'SELECT * FROM ' || want LOOP extras := extras || rec::text; END LOOP; -- Find missing records. FOR rec in EXECUTE 'SELECT * FROM ' || want || ' EXCEPT ' || $4 || 'SELECT * FROM ' || have LOOP missing := missing || rec::text; END LOOP; -- Drop the temporary tables. EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; EXCEPTION WHEN syntax_error OR datatype_mismatch THEN msg := E'\n' || diag( E' Columns differ between queries:\n' || ' have: (' || _temptypes(have) || E')\n' || ' want: (' || _temptypes(want) || ')' ); EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; RETURN ok(FALSE, $3) || msg; END; -- What extra records do we have? IF extras[1] IS NOT NULL THEN res := FALSE; msg := E'\n' || diag( E' Extra records:\n ' || array_to_string( extras, E'\n ' ) ); END IF; -- What missing records do we have? IF missing[1] IS NOT NULL THEN res := FALSE; msg := msg || E'\n' || diag( E' Missing records:\n ' || array_to_string( missing, E'\n ' ) ); END IF; RETURN ok(res, $3) || msg; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _docomp( _temptable( $1, '__taphave__' ), _temptable( $2, '__tapwant__' ), $3, $4 ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _relcomp( TEXT, anyarray, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _docomp( _temptable( $1, '__taphave__' ), _temptable( $2, '__tapwant__' ), $3, $4 ); $$ LANGUAGE sql; -- set_eq( sql, sql, description ) CREATE OR REPLACE FUNCTION set_eq( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, '' ); $$ LANGUAGE sql; -- set_eq( sql, sql ) CREATE OR REPLACE FUNCTION set_eq( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::text, '' ); $$ LANGUAGE sql; -- set_eq( sql, array, description ) CREATE OR REPLACE FUNCTION set_eq( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, '' ); $$ LANGUAGE sql; -- set_eq( sql, array ) CREATE OR REPLACE FUNCTION set_eq( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::text, '' ); $$ LANGUAGE sql; -- bag_eq( sql, sql, description ) CREATE OR REPLACE FUNCTION bag_eq( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'ALL ' ); $$ LANGUAGE sql; -- bag_eq( sql, sql ) CREATE OR REPLACE FUNCTION bag_eq( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::text, 'ALL ' ); $$ LANGUAGE sql; -- bag_eq( sql, array, description ) CREATE OR REPLACE FUNCTION bag_eq( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'ALL ' ); $$ LANGUAGE sql; -- bag_eq( sql, array ) CREATE OR REPLACE FUNCTION bag_eq( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::text, 'ALL ' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _do_ne( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; extras TEXT[] := '{}'; missing TEXT[] := '{}'; res BOOLEAN := TRUE; msg TEXT := ''; BEGIN BEGIN -- Find extra records. EXECUTE 'SELECT EXISTS ( ' || '( SELECT * FROM ' || have || ' EXCEPT ' || $4 || ' SELECT * FROM ' || want || ' ) UNION ( ' || ' SELECT * FROM ' || want || ' EXCEPT ' || $4 || ' SELECT * FROM ' || have || ' ) LIMIT 1 )' INTO res; -- Drop the temporary tables. EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; EXCEPTION WHEN syntax_error OR datatype_mismatch THEN msg := E'\n' || diag( E' Columns differ between queries:\n' || ' have: (' || _temptypes(have) || E')\n' || ' want: (' || _temptypes(want) || ')' ); EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; RETURN ok(FALSE, $3) || msg; END; -- Return the value from the query. RETURN ok(res, $3); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _relne( TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _do_ne( _temptable( $1, '__taphave__' ), _temptable( $2, '__tapwant__' ), $3, $4 ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _relne( TEXT, anyarray, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _do_ne( _temptable( $1, '__taphave__' ), _temptable( $2, '__tapwant__' ), $3, $4 ); $$ LANGUAGE sql; -- set_ne( sql, sql, description ) CREATE OR REPLACE FUNCTION set_ne( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, $3, '' ); $$ LANGUAGE sql; -- set_ne( sql, sql ) CREATE OR REPLACE FUNCTION set_ne( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, NULL::text, '' ); $$ LANGUAGE sql; -- set_ne( sql, array, description ) CREATE OR REPLACE FUNCTION set_ne( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, $3, '' ); $$ LANGUAGE sql; -- set_ne( sql, array ) CREATE OR REPLACE FUNCTION set_ne( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, NULL::text, '' ); $$ LANGUAGE sql; -- bag_ne( sql, sql, description ) CREATE OR REPLACE FUNCTION bag_ne( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, $3, 'ALL ' ); $$ LANGUAGE sql; -- bag_ne( sql, sql ) CREATE OR REPLACE FUNCTION bag_ne( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, NULL::text, 'ALL ' ); $$ LANGUAGE sql; -- bag_ne( sql, array, description ) CREATE OR REPLACE FUNCTION bag_ne( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, $3, 'ALL ' ); $$ LANGUAGE sql; -- bag_ne( sql, array ) CREATE OR REPLACE FUNCTION bag_ne( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT _relne( $1, $2, NULL::text, 'ALL ' ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _relcomp( TEXT, TEXT, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have TEXT := _temptable( $1, '__taphave__' ); want TEXT := _temptable( $2, '__tapwant__' ); results TEXT[] := '{}'; res BOOLEAN := TRUE; msg TEXT := ''; rec RECORD; BEGIN BEGIN -- Find relevant records. FOR rec in EXECUTE 'SELECT * FROM ' || want || ' ' || $4 || ' SELECT * FROM ' || have LOOP results := results || rec::text; END LOOP; -- Drop the temporary tables. EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; EXCEPTION WHEN syntax_error OR datatype_mismatch THEN msg := E'\n' || diag( E' Columns differ between queries:\n' || ' have: (' || _temptypes(have) || E')\n' || ' want: (' || _temptypes(want) || ')' ); EXECUTE 'DROP TABLE ' || have; EXECUTE 'DROP TABLE ' || want; RETURN ok(FALSE, $3) || msg; END; -- What records do we have? IF results[1] IS NOT NULL THEN res := FALSE; msg := msg || E'\n' || diag( ' ' || $5 || E' records:\n ' || array_to_string( results, E'\n ' ) ); END IF; RETURN ok(res, $3) || msg; END; $$ LANGUAGE plpgsql; -- set_has( sql, sql, description ) CREATE OR REPLACE FUNCTION set_has( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'EXCEPT', 'Missing' ); $$ LANGUAGE sql; -- set_has( sql, sql ) CREATE OR REPLACE FUNCTION set_has( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::TEXT, 'EXCEPT', 'Missing' ); $$ LANGUAGE sql; -- bag_has( sql, sql, description ) CREATE OR REPLACE FUNCTION bag_has( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'EXCEPT ALL', 'Missing' ); $$ LANGUAGE sql; -- bag_has( sql, sql ) CREATE OR REPLACE FUNCTION bag_has( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::TEXT, 'EXCEPT ALL', 'Missing' ); $$ LANGUAGE sql; -- set_hasnt( sql, sql, description ) CREATE OR REPLACE FUNCTION set_hasnt( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'INTERSECT', 'Extra' ); $$ LANGUAGE sql; -- set_hasnt( sql, sql ) CREATE OR REPLACE FUNCTION set_hasnt( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::TEXT, 'INTERSECT', 'Extra' ); $$ LANGUAGE sql; -- bag_hasnt( sql, sql, description ) CREATE OR REPLACE FUNCTION bag_hasnt( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, $3, 'INTERSECT ALL', 'Extra' ); $$ LANGUAGE sql; -- bag_hasnt( sql, sql ) CREATE OR REPLACE FUNCTION bag_hasnt( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT _relcomp( $1, $2, NULL::TEXT, 'INTERSECT ALL', 'Extra' ); $$ LANGUAGE sql; -- results_eq( cursor, cursor, description ) CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor, text ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; have_rec RECORD; want_rec RECORD; have_found BOOLEAN; want_found BOOLEAN; rownum INTEGER := 1; err_msg text := 'details not available in pg <= 9.1'; BEGIN FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN RETURN ok( false, $3 ) || E'\n' || diag( ' Results differ beginning at row ' || rownum || E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END ); END IF; rownum = rownum + 1; FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; END LOOP; RETURN ok( true, $3 ); EXCEPTION WHEN datatype_mismatch THEN GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END END || E'\n ERROR: ' || err_msg ); END; $$ LANGUAGE plpgsql; -- results_eq( cursor, cursor ) CREATE OR REPLACE FUNCTION results_eq( refcursor, refcursor ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_eq( sql, sql, description ) CREATE OR REPLACE FUNCTION results_eq( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; want REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); OPEN want FOR EXECUTE _query($2); res := results_eq(have, want, $3); CLOSE have; CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_eq( sql, sql ) CREATE OR REPLACE FUNCTION results_eq( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_eq( sql, array, description ) CREATE OR REPLACE FUNCTION results_eq( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; want REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); OPEN want FOR SELECT $2[i] FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i); res := results_eq(have, want, $3); CLOSE have; CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_eq( sql, array ) CREATE OR REPLACE FUNCTION results_eq( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_eq( sql, cursor, description ) CREATE OR REPLACE FUNCTION results_eq( TEXT, refcursor, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); res := results_eq(have, $2, $3); CLOSE have; RETURN res; END; $$ LANGUAGE plpgsql; -- results_eq( sql, cursor ) CREATE OR REPLACE FUNCTION results_eq( TEXT, refcursor ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_eq( cursor, sql, description ) CREATE OR REPLACE FUNCTION results_eq( refcursor, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE want REFCURSOR; res TEXT; BEGIN OPEN want FOR EXECUTE _query($2); res := results_eq($1, want, $3); CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_eq( cursor, sql ) CREATE OR REPLACE FUNCTION results_eq( refcursor, TEXT ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_eq( cursor, array, description ) CREATE OR REPLACE FUNCTION results_eq( refcursor, anyarray, TEXT ) RETURNS TEXT AS $$ DECLARE want REFCURSOR; res TEXT; BEGIN OPEN want FOR SELECT $2[i] FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i); res := results_eq($1, want, $3); CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_eq( cursor, array ) CREATE OR REPLACE FUNCTION results_eq( refcursor, anyarray ) RETURNS TEXT AS $$ SELECT results_eq( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( cursor, cursor, description ) CREATE OR REPLACE FUNCTION results_ne( refcursor, refcursor, text ) RETURNS TEXT AS $$ DECLARE have ALIAS FOR $1; want ALIAS FOR $2; have_rec RECORD; want_rec RECORD; have_found BOOLEAN; want_found BOOLEAN; err_msg text := 'details not available in pg <= 9.1'; BEGIN FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; WHILE have_found OR want_found LOOP IF have_rec IS DISTINCT FROM want_rec OR have_found <> want_found THEN RETURN ok( true, $3 ); ELSE FETCH have INTO have_rec; have_found := FOUND; FETCH want INTO want_rec; want_found := FOUND; END IF; END LOOP; RETURN ok( false, $3 ); EXCEPTION WHEN datatype_mismatch THEN GET STACKED DIAGNOSTICS err_msg = MESSAGE_TEXT; RETURN ok( false, $3 ) || E'\n' || diag( E' Number of columns or their types differ between the queries' || CASE WHEN have_rec::TEXT = want_rec::text THEN '' ELSE E':\n' || ' have: ' || CASE WHEN have_found THEN have_rec::text ELSE 'NULL' END || E'\n' || ' want: ' || CASE WHEN want_found THEN want_rec::text ELSE 'NULL' END END || E'\n ERROR: ' || err_msg ); END; $$ LANGUAGE plpgsql; -- results_ne( cursor, cursor ) CREATE OR REPLACE FUNCTION results_ne( refcursor, refcursor ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( sql, sql, description ) CREATE OR REPLACE FUNCTION results_ne( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; want REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); OPEN want FOR EXECUTE _query($2); res := results_ne(have, want, $3); CLOSE have; CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_ne( sql, sql ) CREATE OR REPLACE FUNCTION results_ne( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( sql, array, description ) CREATE OR REPLACE FUNCTION results_ne( TEXT, anyarray, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; want REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); OPEN want FOR SELECT $2[i] FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i); res := results_ne(have, want, $3); CLOSE have; CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_ne( sql, array ) CREATE OR REPLACE FUNCTION results_ne( TEXT, anyarray ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( sql, cursor, description ) CREATE OR REPLACE FUNCTION results_ne( TEXT, refcursor, TEXT ) RETURNS TEXT AS $$ DECLARE have REFCURSOR; res TEXT; BEGIN OPEN have FOR EXECUTE _query($1); res := results_ne(have, $2, $3); CLOSE have; RETURN res; END; $$ LANGUAGE plpgsql; -- results_ne( sql, cursor ) CREATE OR REPLACE FUNCTION results_ne( TEXT, refcursor ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( cursor, sql, description ) CREATE OR REPLACE FUNCTION results_ne( refcursor, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE want REFCURSOR; res TEXT; BEGIN OPEN want FOR EXECUTE _query($2); res := results_ne($1, want, $3); CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_ne( cursor, sql ) CREATE OR REPLACE FUNCTION results_ne( refcursor, TEXT ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- results_ne( cursor, array, description ) CREATE OR REPLACE FUNCTION results_ne( refcursor, anyarray, TEXT ) RETURNS TEXT AS $$ DECLARE want REFCURSOR; res TEXT; BEGIN OPEN want FOR SELECT $2[i] FROM generate_series(array_lower($2, 1), array_upper($2, 1)) s(i); res := results_ne($1, want, $3); CLOSE want; RETURN res; END; $$ LANGUAGE plpgsql; -- results_ne( cursor, array ) CREATE OR REPLACE FUNCTION results_ne( refcursor, anyarray ) RETURNS TEXT AS $$ SELECT results_ne( $1, $2, NULL::text ); $$ LANGUAGE sql; -- isa_ok( value, regtype, description ) CREATE OR REPLACE FUNCTION isa_ok( anyelement, regtype, TEXT ) RETURNS TEXT AS $$ DECLARE typeof regtype := pg_typeof($1); BEGIN IF typeof = $2 THEN RETURN ok(true, $3 || ' isa ' || $2 ); END IF; RETURN ok(false, $3 || ' isa ' || $2 ) || E'\n' || diag(' ' || $3 || ' isn''t a "' || $2 || '" it''s a "' || typeof || '"'); END; $$ LANGUAGE plpgsql; -- isa_ok( value, regtype ) CREATE OR REPLACE FUNCTION isa_ok( anyelement, regtype ) RETURNS TEXT AS $$ SELECT isa_ok($1, $2, 'the value'); $$ LANGUAGE sql; -- is_empty( sql, description ) CREATE OR REPLACE FUNCTION is_empty( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE extras TEXT[] := '{}'; res BOOLEAN := TRUE; msg TEXT := ''; rec RECORD; BEGIN -- Find extra records. FOR rec in EXECUTE _query($1) LOOP extras := extras || rec::text; END LOOP; -- What extra records do we have? IF extras[1] IS NOT NULL THEN res := FALSE; msg := E'\n' || diag( E' Unexpected records:\n ' || array_to_string( extras, E'\n ' ) ); END IF; RETURN ok(res, $2) || msg; END; $$ LANGUAGE plpgsql; -- is_empty( sql ) CREATE OR REPLACE FUNCTION is_empty( TEXT ) RETURNS TEXT AS $$ SELECT is_empty( $1, NULL ); $$ LANGUAGE sql; -- isnt_empty( sql, description ) CREATE OR REPLACE FUNCTION isnt_empty( TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE res BOOLEAN := FALSE; rec RECORD; BEGIN -- Find extra records. FOR rec in EXECUTE _query($1) LOOP res := TRUE; EXIT; END LOOP; RETURN ok(res, $2); END; $$ LANGUAGE plpgsql; -- isnt_empty( sql ) CREATE OR REPLACE FUNCTION isnt_empty( TEXT ) RETURNS TEXT AS $$ SELECT isnt_empty( $1, NULL ); $$ LANGUAGE sql; -- collect_tap( tap, tap, tap ) CREATE OR REPLACE FUNCTION collect_tap( VARIADIC text[] ) RETURNS TEXT AS $$ SELECT array_to_string($1, E'\n'); $$ LANGUAGE sql; -- collect_tap( tap[] ) CREATE OR REPLACE FUNCTION collect_tap( VARCHAR[] ) RETURNS TEXT AS $$ SELECT array_to_string($1, E'\n'); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _tlike ( BOOLEAN, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT ok( $1, $4 ) || CASE WHEN $1 THEN '' ELSE E'\n' || diag( ' error message: ' || COALESCE( quote_literal($2), 'NULL' ) || E'\n doesn''t match: ' || COALESCE( quote_literal($3), 'NULL' ) ) END; $$ LANGUAGE sql; -- throws_like ( sql, pattern, description ) CREATE OR REPLACE FUNCTION throws_like ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN EXECUTE _query($1); RETURN ok( FALSE, $3 ) || E'\n' || diag( ' no exception thrown' ); EXCEPTION WHEN OTHERS THEN return _tlike( SQLERRM ~~ $2, SQLERRM, $2, $3 ); END; $$ LANGUAGE plpgsql; -- throws_like ( sql, pattern ) CREATE OR REPLACE FUNCTION throws_like ( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT throws_like($1, $2, 'Should throw exception like ' || quote_literal($2) ); $$ LANGUAGE sql; -- throws_ilike ( sql, pattern, description ) CREATE OR REPLACE FUNCTION throws_ilike ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN EXECUTE _query($1); RETURN ok( FALSE, $3 ) || E'\n' || diag( ' no exception thrown' ); EXCEPTION WHEN OTHERS THEN return _tlike( SQLERRM ~~* $2, SQLERRM, $2, $3 ); END; $$ LANGUAGE plpgsql; -- throws_ilike ( sql, pattern ) CREATE OR REPLACE FUNCTION throws_ilike ( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT throws_ilike($1, $2, 'Should throw exception like ' || quote_literal($2) ); $$ LANGUAGE sql; -- throws_matching ( sql, pattern, description ) CREATE OR REPLACE FUNCTION throws_matching ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN EXECUTE _query($1); RETURN ok( FALSE, $3 ) || E'\n' || diag( ' no exception thrown' ); EXCEPTION WHEN OTHERS THEN return _tlike( SQLERRM ~ $2, SQLERRM, $2, $3 ); END; $$ LANGUAGE plpgsql; -- throws_matching ( sql, pattern ) CREATE OR REPLACE FUNCTION throws_matching ( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT throws_matching($1, $2, 'Should throw exception matching ' || quote_literal($2) ); $$ LANGUAGE sql; -- throws_imatching ( sql, pattern, description ) CREATE OR REPLACE FUNCTION throws_imatching ( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ BEGIN EXECUTE _query($1); RETURN ok( FALSE, $3 ) || E'\n' || diag( ' no exception thrown' ); EXCEPTION WHEN OTHERS THEN return _tlike( SQLERRM ~* $2, SQLERRM, $2, $3 ); END; $$ LANGUAGE plpgsql; -- throws_imatching ( sql, pattern ) CREATE OR REPLACE FUNCTION throws_imatching ( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT throws_imatching($1, $2, 'Should throw exception matching ' || quote_literal($2) ); $$ LANGUAGE sql; -- roles_are( roles[], description ) CREATE OR REPLACE FUNCTION roles_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'roles', ARRAY( SELECT rolname FROM pg_catalog.pg_roles EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT rolname FROM pg_catalog.pg_roles ), $2 ); $$ LANGUAGE SQL; -- roles_are( roles[] ) CREATE OR REPLACE FUNCTION roles_are( NAME[] ) RETURNS TEXT AS $$ SELECT roles_are( $1, 'There should be the correct roles' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _types_are ( NAME, NAME[], TEXT, CHAR[] ) RETURNS TEXT AS $$ SELECT _are( 'types', ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) EXCEPT SELECT _typename($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT _typename($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname = $1 AND t.typtype = ANY( COALESCE($4, ARRAY['b', 'c', 'd', 'p', 'e']) ) ), $3 ); $$ LANGUAGE SQL; -- types_are( schema, types[], description ) CREATE OR REPLACE FUNCTION types_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, $3, NULL ); $$ LANGUAGE SQL; -- types_are( schema, types[] ) CREATE OR REPLACE FUNCTION types_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct types', NULL ); $$ LANGUAGE SQL; -- types_are( types[], description ) CREATE OR REPLACE FUNCTION _types_are ( NAME[], TEXT, CHAR[] ) RETURNS TEXT AS $$ SELECT _are( 'types', ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) EXCEPT SELECT _typename($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT _typename($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = ANY( COALESCE($3, ARRAY['b', 'c', 'd', 'p', 'e']) ) ), $2 ); $$ LANGUAGE SQL; -- types_are( types[], description ) CREATE OR REPLACE FUNCTION types_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, NULL ); $$ LANGUAGE SQL; -- types_are( types[] ) CREATE OR REPLACE FUNCTION types_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct types', NULL ); $$ LANGUAGE SQL; -- domains_are( schema, domains[], description ) CREATE OR REPLACE FUNCTION domains_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, $3, ARRAY['d'] ); $$ LANGUAGE SQL; -- domains_are( schema, domains[] ) CREATE OR REPLACE FUNCTION domains_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct domains', ARRAY['d'] ); $$ LANGUAGE SQL; -- domains_are( domains[], description ) CREATE OR REPLACE FUNCTION domains_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, ARRAY['d'] ); $$ LANGUAGE SQL; -- domains_are( domains[] ) CREATE OR REPLACE FUNCTION domains_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct domains', ARRAY['d'] ); $$ LANGUAGE SQL; -- enums_are( schema, enums[], description ) CREATE OR REPLACE FUNCTION enums_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, $3, ARRAY['e'] ); $$ LANGUAGE SQL; -- enums_are( schema, enums[] ) CREATE OR REPLACE FUNCTION enums_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct enums', ARRAY['e'] ); $$ LANGUAGE SQL; -- enums_are( enums[], description ) CREATE OR REPLACE FUNCTION enums_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _types_are( $1, $2, ARRAY['e'] ); $$ LANGUAGE SQL; -- enums_are( enums[] ) CREATE OR REPLACE FUNCTION enums_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _types_are( $1, 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct enums', ARRAY['e'] ); $$ LANGUAGE SQL; -- _dexists( schema, domain ) CREATE OR REPLACE FUNCTION _dexists ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_type t on n.oid = t.typnamespace WHERE n.nspname = $1 AND t.typname = $2 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _dexists ( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_type t WHERE t.typname = $1 AND pg_catalog.pg_type_is_visible(t.oid) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_dtype( NAME, TEXT, BOOLEAN ) RETURNS TEXT AS $$ SELECT CASE WHEN $3 AND pg_catalog.pg_type_is_visible(t.oid) THEN quote_ident(tn.nspname) || '.' ELSE '' END || pg_catalog.format_type(t.oid, t.typtypmod) FROM pg_catalog.pg_type d JOIN pg_catalog.pg_namespace dn ON d.typnamespace = dn.oid JOIN pg_catalog.pg_type t ON d.typbasetype = t.oid JOIN pg_catalog.pg_namespace tn ON t.typnamespace = tn.oid WHERE d.typisdefined AND dn.nspname = $1 AND d.typname = LOWER($2) AND d.typtype = 'd' $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_dtype( NAME ) RETURNS TEXT AS $$ SELECT pg_catalog.format_type(t.oid, t.typtypmod) FROM pg_catalog.pg_type d JOIN pg_catalog.pg_type t ON d.typbasetype = t.oid WHERE d.typisdefined AND pg_catalog.pg_type_is_visible(d.oid) AND d.typname = LOWER($1) AND d.typtype = 'd' $$ LANGUAGE sql; -- domain_type_is( schema, domain, schema, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, true); BEGIN IF actual_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; IF quote_ident($3) = ANY(current_schemas(true)) THEN RETURN is( actual_type, quote_ident($3) || '.' || _typename($4), $5); END IF; RETURN is( actual_type, _typename(quote_ident($3) || '.' || $4), $5); END; $$ LANGUAGE plpgsql; -- domain_type_is( schema, domain, schema, type ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, NAME, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_is( $1, $2, $3, $4, 'Domain ' || quote_ident($1) || '.' || $2 || ' should extend type ' || quote_ident($3) || '.' || $4 ); $$ LANGUAGE SQL; -- domain_type_is( schema, domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, false); BEGIN IF actual_type IS NULL THEN RETURN fail( $4 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; RETURN is( actual_type, _typename($3), $4 ); END; $$ LANGUAGE plpgsql; -- domain_type_is( schema, domain, type ) CREATE OR REPLACE FUNCTION domain_type_is( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_is( $1, $2, $3, 'Domain ' || quote_ident($1) || '.' || $2 || ' should extend type ' || $3 ); $$ LANGUAGE SQL; -- domain_type_is( domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_is( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1); BEGIN IF actual_type IS NULL THEN RETURN fail( $3 ) || E'\n' || diag ( ' Domain ' || $1 || ' does not exist' ); END IF; RETURN is( actual_type, _typename($2), $3 ); END; $$ LANGUAGE plpgsql; -- domain_type_is( domain, type ) CREATE OR REPLACE FUNCTION domain_type_is( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_is( $1, $2, 'Domain ' || $1 || ' should extend type ' || $2 ); $$ LANGUAGE SQL; -- domain_type_isnt( schema, domain, schema, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, NAME, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, true); BEGIN IF actual_type IS NULL THEN RETURN fail( $5 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; IF quote_ident($3) = ANY(current_schemas(true)) THEN RETURN isnt( actual_type, quote_ident($3) || '.' || _typename($4), $5); END IF; RETURN isnt( actual_type, _typename(quote_ident($3) || '.' || $4), $5); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( schema, domain, schema, type ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, NAME, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_isnt( $1, $2, $3, $4, 'Domain ' || quote_ident($1) || '.' || $2 || ' should not extend type ' || quote_ident($3) || '.' || $4 ); $$ LANGUAGE SQL; -- domain_type_isnt( schema, domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1, $2, false); BEGIN IF actual_type IS NULL THEN RETURN fail( $4 ) || E'\n' || diag ( ' Domain ' || quote_ident($1) || '.' || $2 || ' does not exist' ); END IF; RETURN isnt( actual_type, _typename($3), $4 ); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( schema, domain, type ) CREATE OR REPLACE FUNCTION domain_type_isnt( NAME, TEXT, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_isnt( $1, $2, $3, 'Domain ' || quote_ident($1) || '.' || $2 || ' should not extend type ' || $3 ); $$ LANGUAGE SQL; -- domain_type_isnt( domain, type, description ) CREATE OR REPLACE FUNCTION domain_type_isnt( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$ DECLARE actual_type TEXT := _get_dtype($1); BEGIN IF actual_type IS NULL THEN RETURN fail( $3 ) || E'\n' || diag ( ' Domain ' || $1 || ' does not exist' ); END IF; RETURN isnt( actual_type, _typename($2), $3 ); END; $$ LANGUAGE plpgsql; -- domain_type_isnt( domain, type ) CREATE OR REPLACE FUNCTION domain_type_isnt( TEXT, TEXT ) RETURNS TEXT AS $$ SELECT domain_type_isnt( $1, $2, 'Domain ' || $1 || ' should not extend type ' || $2 ); $$ LANGUAGE SQL; -- row_eq( sql, record, description ) CREATE OR REPLACE FUNCTION row_eq( TEXT, anyelement, TEXT ) RETURNS TEXT AS $$ DECLARE rec RECORD; BEGIN EXECUTE _query($1) INTO rec; IF NOT rec IS DISTINCT FROM $2 THEN RETURN ok(true, $3); END IF; RETURN ok(false, $3 ) || E'\n' || diag( ' have: ' || CASE WHEN rec IS NULL THEN 'NULL' ELSE rec::text END || E'\n want: ' || CASE WHEN $2 IS NULL THEN 'NULL' ELSE $2::text END ); END; $$ LANGUAGE plpgsql; -- row_eq( sql, record ) CREATE OR REPLACE FUNCTION row_eq( TEXT, anyelement ) RETURNS TEXT AS $$ SELECT row_eq($1, $2, NULL ); $$ LANGUAGE sql; -- triggers_are( schema, table, triggers[], description ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'triggers', ARRAY( SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND NOT t.tgisinternal EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 AND NOT t.tgisinternal ), $4 ); $$ LANGUAGE SQL; -- triggers_are( schema, table, triggers[] ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT triggers_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct triggers' ); $$ LANGUAGE SQL; -- triggers_are( table, triggers[], description ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'triggers', ARRAY( SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND NOT t.tgisinternal EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT t.tgname FROM pg_catalog.pg_trigger t JOIN pg_catalog.pg_class c ON c.oid = t.tgrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND NOT t.tgisinternal ), $3 ); $$ LANGUAGE SQL; -- triggers_are( table, triggers[] ) CREATE OR REPLACE FUNCTION triggers_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT triggers_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct triggers' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _areni ( text, text[], text[], TEXT ) RETURNS TEXT AS $$ DECLARE what ALIAS FOR $1; extras ALIAS FOR $2; missing ALIAS FOR $3; descr ALIAS FOR $4; msg TEXT := ''; res BOOLEAN := TRUE; BEGIN IF extras[1] IS NOT NULL THEN res = FALSE; msg := E'\n' || diag( ' Extra ' || what || E':\n ' || _array_to_sorted_string( extras, E'\n ' ) ); END IF; IF missing[1] IS NOT NULL THEN res = FALSE; msg := msg || E'\n' || diag( ' Missing ' || what || E':\n ' || _array_to_sorted_string( missing, E'\n ' ) ); END IF; RETURN ok(res, descr) || msg; END; $$ LANGUAGE plpgsql; -- casts_are( casts[], description ) CREATE OR REPLACE FUNCTION casts_are ( TEXT[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( 'casts', ARRAY( SELECT pg_catalog.format_type(castsource, NULL) || ' AS ' || pg_catalog.format_type(casttarget, NULL) FROM pg_catalog.pg_cast c EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT pg_catalog.format_type(castsource, NULL) || ' AS ' || pg_catalog.format_type(casttarget, NULL) FROM pg_catalog.pg_cast c ), $2 ); $$ LANGUAGE sql; -- casts_are( casts[] ) CREATE OR REPLACE FUNCTION casts_are ( TEXT[] ) RETURNS TEXT AS $$ SELECT casts_are( $1, 'There should be the correct casts'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION display_oper ( NAME, OID ) RETURNS TEXT AS $$ SELECT $1 || substring($2::regoperator::text, '[(][^)]+[)]$') $$ LANGUAGE SQL; -- operators_are( schema, operators[], description ) CREATE OR REPLACE FUNCTION operators_are( NAME, TEXT[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( 'operators', ARRAY( SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $1 EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE n.nspname = $1 ), $3 ); $$ LANGUAGE SQL; -- operators_are( schema, operators[] ) CREATE OR REPLACE FUNCTION operators_are ( NAME, TEXT[] ) RETURNS TEXT AS $$ SELECT operators_are($1, $2, 'Schema ' || quote_ident($1) || ' should have the correct operators' ); $$ LANGUAGE SQL; -- operators_are( operators[], description ) CREATE OR REPLACE FUNCTION operators_are( TEXT[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( 'operators', ARRAY( SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE pg_catalog.pg_operator_is_visible(o.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ), ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) EXCEPT SELECT display_oper(o.oprname, o.oid) || ' RETURNS ' || o.oprresult::regtype FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE pg_catalog.pg_operator_is_visible(o.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') ), $2 ); $$ LANGUAGE SQL; -- operators_are( operators[] ) CREATE OR REPLACE FUNCTION operators_are ( TEXT[] ) RETURNS TEXT AS $$ SELECT operators_are($1, 'There should be the correct operators') $$ LANGUAGE SQL; -- columns_are( schema, table, columns[], description ) CREATE OR REPLACE FUNCTION columns_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'columns', ARRAY( SELECT a.attname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT a.attname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname = $1 AND c.relname = $2 AND a.attnum > 0 AND NOT a.attisdropped ), $4 ); $$ LANGUAGE SQL; -- columns_are( schema, table, columns[] ) CREATE OR REPLACE FUNCTION columns_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT columns_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct columns' ); $$ LANGUAGE SQL; -- columns_are( table, columns[], description ) CREATE OR REPLACE FUNCTION columns_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'columns', ARRAY( SELECT a.attname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT a.attname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_attribute a ON c.oid = a.attrelid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND pg_catalog.pg_table_is_visible(c.oid) AND c.relname = $1 AND a.attnum > 0 AND NOT a.attisdropped ), $3 ); $$ LANGUAGE SQL; -- columns_are( table, columns[] ) CREATE OR REPLACE FUNCTION columns_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT columns_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct columns' ); $$ LANGUAGE SQL; -- _get_db_owner( dbname ) CREATE OR REPLACE FUNCTION _get_db_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = $1; $$ LANGUAGE SQL; -- db_owner_is ( dbname, user, description ) CREATE OR REPLACE FUNCTION db_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE dbowner NAME := _get_db_owner($1); BEGIN -- Make sure the database exists. IF dbowner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Database ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(dbowner, $2, $3); END; $$ LANGUAGE plpgsql; -- db_owner_is ( dbname, user ) CREATE OR REPLACE FUNCTION db_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT db_owner_is( $1, $2, 'Database ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- _get_schema_owner( schema ) CREATE OR REPLACE FUNCTION _get_schema_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(nspowner) FROM pg_catalog.pg_namespace WHERE nspname = $1; $$ LANGUAGE SQL; -- schema_owner_is ( schema, user, description ) CREATE OR REPLACE FUNCTION schema_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_schema_owner($1); BEGIN -- Make sure the schema exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Schema ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- schema_owner_is ( schema, user ) CREATE OR REPLACE FUNCTION schema_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT schema_owner_is( $1, $2, 'Schema ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_rel_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c WHERE c.relname = $1 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- relation_owner_is ( schema, relation, user, description ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner($1, $2); BEGIN -- Make sure the relation exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- relation_owner_is ( schema, relation, user ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT relation_owner_is( $1, $2, $3, 'Relation ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- relation_owner_is ( relation, user, description ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner($1); BEGIN -- Make sure the relation exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Relation ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- relation_owner_is ( relation, user ) CREATE OR REPLACE FUNCTION relation_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT relation_owner_is( $1, $2, 'Relation ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR[], NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = ANY($1) AND n.nspname = $2 AND c.relname = $3 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR[], NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(c.relowner) FROM pg_catalog.pg_class c WHERE c.relkind = ANY($1) AND c.relname = $2 AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME, NAME ) RETURNS NAME AS $$ SELECT _get_rel_owner(ARRAY[$1], $2, $3); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_rel_owner ( CHAR, NAME ) RETURNS NAME AS $$ SELECT _get_rel_owner(ARRAY[$1], $2); $$ LANGUAGE SQL; -- table_owner_is ( schema, table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('{r,p}'::char[], $1, $2); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- table_owner_is ( schema, table, user ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT table_owner_is( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- table_owner_is ( table, user, description ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('{r,p}'::char[], $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- table_owner_is ( table, user ) CREATE OR REPLACE FUNCTION table_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT table_owner_is( $1, $2, 'Table ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- view_owner_is ( schema, view, user, description ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('v'::char, $1, $2); BEGIN -- Make sure the view exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' View ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- view_owner_is ( schema, view, user ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT view_owner_is( $1, $2, $3, 'View ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- view_owner_is ( view, user, description ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('v'::char, $1); BEGIN -- Make sure the view exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' View ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- view_owner_is ( view, user ) CREATE OR REPLACE FUNCTION view_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT view_owner_is( $1, $2, 'View ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- sequence_owner_is ( schema, sequence, user, description ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('S'::char, $1, $2); BEGIN -- Make sure the sequence exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- sequence_owner_is ( schema, sequence, user ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT sequence_owner_is( $1, $2, $3, 'Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- sequence_owner_is ( sequence, user, description ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('S'::char, $1); BEGIN -- Make sure the sequence exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Sequence ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- sequence_owner_is ( sequence, user ) CREATE OR REPLACE FUNCTION sequence_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT sequence_owner_is( $1, $2, 'Sequence ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- composite_owner_is ( schema, composite, user, description ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('c'::char, $1, $2); BEGIN -- Make sure the composite exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Composite type ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- composite_owner_is ( schema, composite, user ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT composite_owner_is( $1, $2, $3, 'Composite type ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- composite_owner_is ( composite, user, description ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('c'::char, $1); BEGIN -- Make sure the composite exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Composite type ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- composite_owner_is ( composite, user ) CREATE OR REPLACE FUNCTION composite_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT composite_owner_is( $1, $2, 'Composite type ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- foreign_table_owner_is ( schema, table, user, description ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('f'::char, $1, $2); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- foreign_table_owner_is ( schema, table, user ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT foreign_table_owner_is( $1, $2, $3, 'Foreign table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- foreign_table_owner_is ( table, user, description ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('f'::char, $1); BEGIN -- Make sure the table exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Foreign table ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- foreign_table_owner_is ( table, user ) CREATE OR REPLACE FUNCTION foreign_table_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT foreign_table_owner_is( $1, $2, 'Foreign table ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE schema = $1 AND name = $2 AND args = _funkargs($3) $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_owner ( NAME, NAME[] ) RETURNS NAME AS $$ SELECT owner FROM tap_funky WHERE name = $1 AND args = _funkargs($2) AND is_visible $$ LANGUAGE SQL; -- function_owner_is( schema, function, args[], user, description ) CREATE OR REPLACE FUNCTION function_owner_is ( NAME, NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_func_owner($1, $2, $3); BEGIN -- Make sure the function exists. IF owner IS NULL THEN RETURN ok(FALSE, $5) || E'\n' || diag( E' Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') does not exist' ); END IF; RETURN is(owner, $4, $5); END; $$ LANGUAGE plpgsql; -- function_owner_is( schema, function, args[], user ) CREATE OR REPLACE FUNCTION function_owner_is( NAME, NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_owner_is( $1, $2, $3, $4, 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be owned by ' || quote_ident($4) ); $$ LANGUAGE sql; -- function_owner_is( function, args[], user, description ) CREATE OR REPLACE FUNCTION function_owner_is ( NAME, NAME[], NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_func_owner($1, $2); BEGIN -- Make sure the function exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- function_owner_is( function, args[], user ) CREATE OR REPLACE FUNCTION function_owner_is( NAME, NAME[], NAME ) RETURNS TEXT AS $$ SELECT function_owner_is( $1, $2, $3, 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- _get_tablespace_owner( tablespace ) CREATE OR REPLACE FUNCTION _get_tablespace_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(spcowner) FROM pg_catalog.pg_tablespace WHERE spcname = $1; $$ LANGUAGE SQL; -- tablespace_owner_is ( tablespace, user, description ) CREATE OR REPLACE FUNCTION tablespace_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_tablespace_owner($1); BEGIN -- Make sure the tablespace exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Tablespace ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- tablespace_owner_is ( tablespace, user ) CREATE OR REPLACE FUNCTION tablespace_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT tablespace_owner_is( $1, $2, 'Tablespace ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_index_owner( NAME, NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(ci.relowner) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid JOIN pg_catalog.pg_namespace n ON n.oid = ct.relnamespace WHERE n.nspname = $1 AND ct.relname = $2 AND ci.relname = $3; $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_index_owner( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(ci.relowner) FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class ct ON ct.oid = x.indrelid JOIN pg_catalog.pg_class ci ON ci.oid = x.indexrelid WHERE ct.relname = $1 AND ci.relname = $2 AND pg_catalog.pg_table_is_visible(ct.oid); $$ LANGUAGE sql; -- index_owner_is ( schema, table, index, user, description ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_index_owner($1, $2, $3); BEGIN -- Make sure the index exists. IF owner IS NULL THEN RETURN ok(FALSE, $5) || E'\n' || diag( E' Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $4, $5); END; $$ LANGUAGE plpgsql; -- index_owner_is ( schema, table, index, user ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_owner_is( $1, $2, $3, $4, 'Index ' || quote_ident($3) || ' ON ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($4) ); $$ LANGUAGE sql; -- index_owner_is ( table, index, user, description ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_index_owner($1, $2); BEGIN -- Make sure the index exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- index_owner_is ( table, index, user ) CREATE OR REPLACE FUNCTION index_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT index_owner_is( $1, $2, $3, 'Index ' || quote_ident($2) || ' ON ' || quote_ident($1) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- _get_language_owner( language ) CREATE OR REPLACE FUNCTION _get_language_owner( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(lanowner) FROM pg_catalog.pg_language WHERE lanname = $1; $$ LANGUAGE SQL; -- language_owner_is ( language, user, description ) CREATE OR REPLACE FUNCTION language_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_language_owner($1); BEGIN -- Make sure the language exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Language ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- language_owner_is ( language, user ) CREATE OR REPLACE FUNCTION language_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT language_owner_is( $1, $2, 'Language ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_opclass_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(opcowner) FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname = $1 AND opcname = $2; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_opclass_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(opcowner) FROM pg_catalog.pg_opclass WHERE opcname = $1 AND pg_catalog.pg_opclass_is_visible(oid); $$ LANGUAGE SQL; -- opclass_owner_is( schema, opclass, user, description ) CREATE OR REPLACE FUNCTION opclass_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_opclass_owner($1, $2); BEGIN -- Make sure the opclass exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- opclass_owner_is( schema, opclass, user ) CREATE OR REPLACE FUNCTION opclass_owner_is( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT opclass_owner_is( $1, $2, $3, 'Operator class ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- opclass_owner_is( opclass, user, description ) CREATE OR REPLACE FUNCTION opclass_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_opclass_owner($1); BEGIN -- Make sure the opclass exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Operator class ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- opclass_owner_is( opclass, user ) CREATE OR REPLACE FUNCTION opclass_owner_is( NAME, NAME ) RETURNS TEXT AS $$ SELECT opclass_owner_is( $1, $2, 'Operator class ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _get_type_owner ( NAME, NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(t.typowner) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE n.nspname = $1 AND t.typname = $2 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_type_owner ( NAME ) RETURNS NAME AS $$ SELECT pg_catalog.pg_get_userbyid(typowner) FROM pg_catalog.pg_type WHERE typname = $1 AND pg_catalog.pg_type_is_visible(oid) $$ LANGUAGE SQL; -- type_owner_is ( schema, type, user, description ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_type_owner($1, $2); BEGIN -- Make sure the type exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Type ' || quote_ident($1) || '.' || quote_ident($2) || ' not found' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- type_owner_is ( schema, type, user ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT type_owner_is( $1, $2, $3, 'Type ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- type_owner_is ( type, user, description ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_type_owner($1); BEGIN -- Make sure the type exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Type ' || quote_ident($1) || ' not found' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- type_owner_is ( type, user ) CREATE OR REPLACE FUNCTION type_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT type_owner_is( $1, $2, 'Type ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION _assets_are ( text, text[], text[], TEXT ) RETURNS TEXT AS $$ SELECT _areni( $1, ARRAY( SELECT UPPER($2[i]) AS thing FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ORDER BY thing ), ARRAY( SELECT $3[i] AS thing FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT UPPER($2[i]) FROM generate_series(1, array_upper($2, 1)) s(i) ORDER BY thing ), $4 ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_table_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := _table_privs(); grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_table_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid table name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _table_privs() RETURNS NAME[] AS $$ DECLARE pgversion INTEGER := pg_version_num(); BEGIN IF pgversion < 80200 THEN RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'RULE', 'SELECT', 'TRIGGER', 'UPDATE' ]; ELSIF pgversion < 80400 THEN RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'SELECT', 'TRIGGER', 'UPDATE' ]; ELSE RETURN ARRAY[ 'DELETE', 'INSERT', 'REFERENCES', 'SELECT', 'TRIGGER', 'TRUNCATE', 'UPDATE' ]; END IF; END; $$ language plpgsql; -- table_privs_are ( schema, table, user, privileges[], description ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_table_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- table_privs_are ( schema, table, user, privileges[] ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT table_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on table ' || quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- table_privs_are ( table, user, privileges[], description ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_table_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- table_privs_are ( table, user, privileges[] ) CREATE OR REPLACE FUNCTION table_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT table_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on table ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _db_privs() RETURNS NAME[] AS $$ DECLARE pgversion INTEGER := pg_version_num(); BEGIN IF pgversion < 80200 THEN RETURN ARRAY['CREATE', 'TEMPORARY']; ELSE RETURN ARRAY['CREATE', 'CONNECT', 'TEMPORARY']; END IF; END; $$ language plpgsql; CREATE OR REPLACE FUNCTION _get_db_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := _db_privs(); grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_database_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN invalid_catalog_name THEN -- Not a valid db name. RETURN '{invalid_catalog_name}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- database_privs_are ( db, user, privileges[], description ) CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_db_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'invalid_catalog_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Database ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- database_privs_are ( db, user, privileges[] ) CREATE OR REPLACE FUNCTION database_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT database_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on database ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_func_privs(TEXT, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_function_privilege($1, $2, 'EXECUTE') THEN RETURN '{EXECUTE}'; ELSE RETURN '{}'; END IF; EXCEPTION -- Not a valid func name. WHEN undefined_function THEN RETURN '{undefined_function}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION _fprivs_are ( TEXT, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_func_privs($2, $1); BEGIN IF grants[1] = 'undefined_function' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Function ' || $1 || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- function_privs_are ( schema, function, args[], user, privileges[], description ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _fprivs_are( quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ')', $4, $5, $6 ); $$ LANGUAGE SQL; -- function_privs_are ( schema, function, args[], user, privileges[] ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME, NAME[], NAME, NAME[] ) RETURNS TEXT AS $$ SELECT function_privs_are( $1, $2, $3, $4, $5, 'Role ' || quote_ident($4) || ' should be granted ' || CASE WHEN $5[1] IS NULL THEN 'no privileges' ELSE array_to_string($5, ', ') END || ' on function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ')' ); $$ LANGUAGE SQL; -- function_privs_are ( function, args[], user, privileges[], description ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME[], NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _fprivs_are( quote_ident($1) || '(' || array_to_string($2, ', ') || ')', $3, $4, $5 ); $$ LANGUAGE SQL; -- function_privs_are ( function, args[], user, privileges[] ) CREATE OR REPLACE FUNCTION function_privs_are ( NAME, NAME[], NAME, NAME[] ) RETURNS TEXT AS $$ SELECT function_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ')' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_lang_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_language_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or language. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_language}' END; END; $$ LANGUAGE plpgsql; -- language_privs_are ( lang, user, privileges[], description ) CREATE OR REPLACE FUNCTION language_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_lang_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_language' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Language ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- language_privs_are ( lang, user, privileges[] ) CREATE OR REPLACE FUNCTION language_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT language_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on language ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_schema_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['CREATE', 'USAGE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP IF pg_catalog.has_schema_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; END LOOP; RETURN grants; EXCEPTION -- Not a valid schema name. WHEN invalid_schema_name THEN RETURN '{invalid_schema_name}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; -- schema_privs_are ( schema, user, privileges[], description ) CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_schema_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'invalid_schema_name' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Schema ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- schema_privs_are ( schema, user, privileges[] ) CREATE OR REPLACE FUNCTION schema_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT schema_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on schema ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_tablespaceprivs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_tablespace_privilege($1, $2, 'CREATE') THEN RETURN '{CREATE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or tablespace. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_tablespace}' END; END; $$ LANGUAGE plpgsql; -- tablespace_privs_are ( tablespace, user, privileges[], description ) CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_tablespaceprivs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_tablespace' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Tablespace ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- tablespace_privs_are ( tablespace, user, privileges[] ) CREATE OR REPLACE FUNCTION tablespace_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT tablespace_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on tablespace ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_sequence_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['SELECT', 'UPDATE', 'USAGE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_sequence_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid sequence name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( schema, sequence, user, privileges[], description ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_sequence_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( schema, sequence, user, privileges[] ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT sequence_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on sequence '|| quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- sequence_privs_are ( sequence, user, privileges[], description ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_sequence_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Sequence ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- sequence_privs_are ( sequence, user, privileges[] ) CREATE OR REPLACE FUNCTION sequence_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT sequence_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on sequence ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_ac_privs(NAME, TEXT) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP BEGIN IF pg_catalog.has_any_column_privilege($1, $2, privs[i]) THEN grants := grants || privs[i]; END IF; EXCEPTION WHEN undefined_table THEN -- Not a valid table name. RETURN '{undefined_table}'; WHEN undefined_object THEN -- Not a valid role. RETURN '{undefined_role}'; WHEN invalid_parameter_value THEN -- Not a valid permission on this version of PostgreSQL; ignore; END; END LOOP; RETURN grants; END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( schema, table, user, privileges[], description ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_ac_privs( $3, quote_ident($1) || '.' || quote_ident($2) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( schema, table, user, privileges[] ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT any_column_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on any column in '|| quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; -- any_column_privs_are ( table, user, privileges[], description ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_ac_privs( $2, quote_ident($1) ); BEGIN IF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- any_column_privs_are ( table, user, privileges[] ) CREATE OR REPLACE FUNCTION any_column_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT any_column_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on any column in ' || quote_ident($1) ); $$ LANGUAGE SQL; -- _get_col_privs(user, table, column) CREATE OR REPLACE FUNCTION _get_col_privs(NAME, TEXT, NAME) RETURNS TEXT[] AS $$ DECLARE privs TEXT[] := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; grants TEXT[] := '{}'; BEGIN FOR i IN 1..array_upper(privs, 1) LOOP IF pg_catalog.has_column_privilege($1, $2, $3, privs[i]) THEN grants := grants || privs[i]; END IF; END LOOP; RETURN grants; EXCEPTION -- Not a valid column name. WHEN undefined_column THEN RETURN '{undefined_column}'; -- Not a valid table name. WHEN undefined_table THEN RETURN '{undefined_table}'; -- Not a valid role. WHEN undefined_object THEN RETURN '{undefined_role}'; END; $$ LANGUAGE plpgsql; -- column_privs_are ( schema, table, column, user, privileges[], description ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_col_privs( $4, quote_ident($1) || '.' || quote_ident($2), $3 ); BEGIN IF grants[1] = 'undefined_column' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' does not exist' ); ELSIF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Table ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $6) || E'\n' || diag( ' Role ' || quote_ident($4) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $5, $6); END; $$ LANGUAGE plpgsql; -- column_privs_are ( schema, table, column, user, privileges[] ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT column_privs_are( $1, $2, $3, $4, $5, 'Role ' || quote_ident($4) || ' should be granted ' || CASE WHEN $5[1] IS NULL THEN 'no privileges' ELSE array_to_string($5, ', ') END || ' on column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) ); $$ LANGUAGE SQL; -- column_privs_are ( table, column, user, privileges[], description ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_col_privs( $3, quote_ident($1), $2 ); BEGIN IF grants[1] = 'undefined_column' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Column ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); ELSIF grants[1] = 'undefined_table' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Table ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $5) || E'\n' || diag( ' Role ' || quote_ident($3) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $4, $5); END; $$ LANGUAGE plpgsql; -- column_privs_are ( table, column, user, privileges[] ) CREATE OR REPLACE FUNCTION column_privs_are ( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT column_privs_are( $1, $2, $3, $4, 'Role ' || quote_ident($3) || ' should be granted ' || CASE WHEN $4[1] IS NULL THEN 'no privileges' ELSE array_to_string($4, ', ') END || ' on column ' || quote_ident($1) || '.' || quote_ident($2) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_fdw_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_foreign_data_wrapper_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or fdw. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_fdw}' END; END; $$ LANGUAGE plpgsql; -- fdw_privs_are ( fdw, user, privileges[], description ) CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_fdw_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_fdw' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' FDW ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- fdw_privs_are ( fdw, user, privileges[] ) CREATE OR REPLACE FUNCTION fdw_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT fdw_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on FDW ' || quote_ident($1) ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _get_server_privs (NAME, TEXT) RETURNS TEXT[] AS $$ BEGIN IF pg_catalog.has_server_privilege($1, $2, 'USAGE') THEN RETURN '{USAGE}'; ELSE RETURN '{}'; END IF; EXCEPTION WHEN undefined_object THEN -- Same error code for unknown user or server. So figure out which. RETURN CASE WHEN SQLERRM LIKE '%' || $1 || '%' THEN '{undefined_role}' ELSE '{undefined_server}' END; END; $$ LANGUAGE plpgsql; -- server_privs_are ( server, user, privileges[], description ) CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ DECLARE grants TEXT[] := _get_server_privs( $2, $1::TEXT ); BEGIN IF grants[1] = 'undefined_server' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Server ' || quote_ident($1) || ' does not exist' ); ELSIF grants[1] = 'undefined_role' THEN RETURN ok(FALSE, $4) || E'\n' || diag( ' Role ' || quote_ident($2) || ' does not exist' ); END IF; RETURN _assets_are('privileges', grants, $3, $4); END; $$ LANGUAGE plpgsql; -- server_privs_are ( server, user, privileges[] ) CREATE OR REPLACE FUNCTION server_privs_are ( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT server_privs_are( $1, $2, $3, 'Role ' || quote_ident($2) || ' should be granted ' || CASE WHEN $3[1] IS NULL THEN 'no privileges' ELSE array_to_string($3, ', ') END || ' on server ' || quote_ident($1) ); $$ LANGUAGE SQL; -- materialized_views_are( schema, materialized_views, description ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2), $3); $$ LANGUAGE SQL; -- materialized_views_are( materialized_views, description ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1), _missing('m', $1), $2); $$ LANGUAGE SQL; -- materialized_views_are( schema, materialized_views ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1, $2), _missing('m', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct materialized views' ); $$ LANGUAGE SQL; -- materialized_views_are( materialized_views ) CREATE OR REPLACE FUNCTION materialized_views_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'Materialized views', _extras('m', $1), _missing('m', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views' ); $$ LANGUAGE SQL; -- materialized_view_owner_is ( schema, materialized_view, user, description ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('m'::char, $1, $2); BEGIN -- Make sure the materialized view exists. IF owner IS NULL THEN RETURN ok(FALSE, $4) || E'\n' || diag( E' Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' does not exist' ); END IF; RETURN is(owner, $3, $4); END; $$ LANGUAGE plpgsql; -- materialized_view_owner_is ( schema, materialized_view, user ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT materialized_view_owner_is( $1, $2, $3, 'Materialized view ' || quote_ident($1) || '.' || quote_ident($2) || ' should be owned by ' || quote_ident($3) ); $$ LANGUAGE sql; -- materialized_view_owner_is ( materialized_view, user, description ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ DECLARE owner NAME := _get_rel_owner('m'::char, $1); BEGIN -- Make sure the materialized view exists. IF owner IS NULL THEN RETURN ok(FALSE, $3) || E'\n' || diag( E' Materialized view ' || quote_ident($1) || ' does not exist' ); END IF; RETURN is(owner, $2, $3); END; $$ LANGUAGE plpgsql; -- materialized_view_owner_is ( materialized_view, user ) CREATE OR REPLACE FUNCTION materialized_view_owner_is ( NAME, NAME ) RETURNS TEXT AS $$ SELECT materialized_view_owner_is( $1, $2, 'Materialized view ' || quote_ident($1) || ' should be owned by ' || quote_ident($2) ); $$ LANGUAGE sql; -- has_materialized_view( schema, materialized_view, description ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'm', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_materialized_view( materialized_view, description ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists( 'm', $1 ), $2 ); $$ LANGUAGE SQL; -- has_materialized_view( materialized_view ) CREATE OR REPLACE FUNCTION has_materialized_view ( NAME ) RETURNS TEXT AS $$ SELECT has_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_materialized_view( schema, materialized_view, description ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'm', $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_materialized_view( materialized_view, description ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists( 'm', $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_materialized_view( materialized_view ) CREATE OR REPLACE FUNCTION hasnt_materialized_view ( NAME ) RETURNS TEXT AS $$ SELECT hasnt_materialized_view( $1, 'Materialized view ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- foreign_tables_are( schema, tables, description ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2), $3); $$ LANGUAGE SQL; -- foreign_tables_are( tables, description ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1), _missing('f', $1), $2); $$ LANGUAGE SQL; -- foreign_tables_are( schema, tables ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1, $2), _missing('f', $1, $2), 'Schema ' || quote_ident($1) || ' should have the correct foreign tables' ); $$ LANGUAGE SQL; -- foreign_tables_are( tables ) CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[] ) RETURNS TEXT AS $$ SELECT _are( 'foreign tables', _extras('f', $1), _missing('f', $1), 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables' ); $$ LANGUAGE SQL; GRANT SELECT ON tap_funky TO PUBLIC; GRANT SELECT ON pg_all_foreign_keys TO PUBLIC; -- Get extensions in a given schema CREATE OR REPLACE FUNCTION _extensions( NAME ) RETURNS SETOF NAME AS $$ SELECT e.extname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_extension e ON n.oid = e.extnamespace WHERE n.nspname = $1 $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _extensions() RETURNS SETOF NAME AS $$ SELECT extname FROM pg_catalog.pg_extension $$ LANGUAGE SQL; -- extensions_are( schema, extensions, description ) CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'extensions', ARRAY(SELECT _extensions($1) EXCEPT SELECT unnest($2)), ARRAY(SELECT unnest($2) EXCEPT SELECT _extensions($1)), $3 ); $$ LANGUAGE SQL; -- extensions_are( schema, extensions) CREATE OR REPLACE FUNCTION extensions_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT extensions_are( $1, $2, 'Schema ' || quote_ident($1) || ' should have the correct extensions' ); $$ LANGUAGE SQL; -- extensions_are( extensions, description ) CREATE OR REPLACE FUNCTION extensions_are( NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'extensions', ARRAY(SELECT _extensions() EXCEPT SELECT unnest($1)), ARRAY(SELECT unnest($1) EXCEPT SELECT _extensions()), $2 ); $$ LANGUAGE SQL; -- extensions_are( schema, extensions) CREATE OR REPLACE FUNCTION extensions_are( NAME[] ) RETURNS TEXT AS $$ SELECT extensions_are($1, 'Should have the correct extensions'); $$ LANGUAGE SQL; -- check extension exists function with schema name CREATE OR REPLACE FUNCTION _ext_exists( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_extension ex JOIN pg_catalog.pg_namespace n ON ex.extnamespace = n.oid WHERE n.nspname = $1 AND ex.extname = $2 ); $$ LANGUAGE SQL; -- check extension exists function without schema name CREATE OR REPLACE FUNCTION _ext_exists( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS ( SELECT TRUE FROM pg_catalog.pg_extension ex WHERE ex.extname = $1 ); $$ LANGUAGE SQL; -- has_extension( schema, name, description ) CREATE OR REPLACE FUNCTION has_extension( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- has_extension( schema, name ) CREATE OR REPLACE FUNCTION has_extension( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1, $2 ), 'Extension ' || quote_ident($2) || ' should exist in schema ' || quote_ident($1) ); $$ LANGUAGE SQL; -- has_extension( name, description ) CREATE OR REPLACE FUNCTION has_extension( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1 ), $2) $$ LANGUAGE SQL; -- has_extension( name ) CREATE OR REPLACE FUNCTION has_extension( NAME ) RETURNS TEXT AS $$ SELECT ok( _ext_exists( $1 ), 'Extension ' || quote_ident($1) || ' should exist' ); $$ LANGUAGE SQL; -- hasnt_extension( schema, name, description ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_extension( schema, name ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1, $2 ), 'Extension ' || quote_ident($2) || ' should not exist in schema ' || quote_ident($1) ); $$ LANGUAGE SQL; -- hasnt_extension( name, description ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1 ), $2) $$ LANGUAGE SQL; -- hasnt_extension( name ) CREATE OR REPLACE FUNCTION hasnt_extension( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ext_exists( $1 ), 'Extension ' || quote_ident($1) || ' should not exist' ); $$ LANGUAGE SQL; -- is_partitioned( schema, table, description ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1, $2), $3); $$ LANGUAGE sql; -- is_partitioned( schema, table ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1, $2), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be partitioned' ); $$ LANGUAGE sql; -- is_partitioned( table, description ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1), $2); $$ LANGUAGE sql; -- is_partitioned( table ) CREATE OR REPLACE FUNCTION is_partitioned ( NAME ) RETURNS TEXT AS $$ SELECT ok( _rexists('p', $1), 'Table ' || quote_ident($1) || ' should be partitioned' ); $$ LANGUAGE sql; -- isnt_partitioned( schema, table, description ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1, $2), $3); $$ LANGUAGE sql; -- isnt_partitioned( schema, table ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1, $2), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should not be partitioned' ); $$ LANGUAGE sql; -- isnt_partitioned( table, description ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1), $2); $$ LANGUAGE sql; -- isnt_partitioned( table ) CREATE OR REPLACE FUNCTION isnt_partitioned ( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _rexists('p', $1), 'Table ' || quote_ident($1) || ' should not be partitioned' ); $$ LANGUAGE sql; -- _partof( child_schema, child_table, parent_schema, parent_table ) CREATE OR REPLACE FUNCTION _partof ( NAME, NAME, NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace cn JOIN pg_catalog.pg_class cc ON cn.oid = cc.relnamespace JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid JOIN pg_catalog.pg_namespace pn ON pc.relnamespace = pn.oid WHERE cn.nspname = $1 AND cc.relname = $2 AND cc.relispartition AND pn.nspname = $3 AND pc.relname = $4 AND pc.relkind = 'p' ) $$ LANGUAGE sql; -- _partof( child_table, parent_table ) CREATE OR REPLACE FUNCTION _partof ( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class cc JOIN pg_catalog.pg_inherits i ON cc.oid = i.inhrelid JOIN pg_catalog.pg_class pc ON i.inhparent = pc.oid WHERE cc.relname = $1 AND cc.relispartition AND pc.relname = $2 AND pc.relkind = 'p' AND pg_catalog.pg_table_is_visible(cc.oid) AND pg_catalog.pg_table_is_visible(pc.oid) ) $$ LANGUAGE sql; -- is_partition_of( child_schema, child_table, parent_schema, parent_table, description ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2, $3, $4), $5); $$ LANGUAGE sql; -- is_partition_of( child_schema, child_table, parent_schema, parent_table ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2, $3, $4), 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should be a partition of ' || quote_ident($3) || '.' || quote_ident($4) ); $$ LANGUAGE sql; -- is_partition_of( child_table, parent_table, description ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2), $3); $$ LANGUAGE sql; -- is_partition_of( child_table, parent_table ) CREATE OR REPLACE FUNCTION is_partition_of ( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _partof($1, $2), 'Table ' || quote_ident($1) || ' should be a partition of ' || quote_ident($2) ); $$ LANGUAGE sql; -- _parts(schema, table) CREATE OR REPLACE FUNCTION _parts( NAME, NAME ) RETURNS SETOF NAME AS $$ SELECT i.inhrelid::regclass::name FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent WHERE n.nspname = $1 AND c.relname = $2 AND c.relkind = 'p' $$ LANGUAGE SQL; -- _parts(table) CREATE OR REPLACE FUNCTION _parts( NAME ) RETURNS SETOF NAME AS $$ SELECT i.inhrelid::regclass::name FROM pg_catalog.pg_class c JOIN pg_catalog.pg_inherits i ON c.oid = i.inhparent WHERE c.relname = $1 AND c.relkind = 'p' AND pg_catalog.pg_table_is_visible(c.oid) $$ LANGUAGE SQL; -- partitions_are( schema, table, partitions, description ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'partitions', ARRAY(SELECT _parts($1, $2) EXCEPT SELECT unnest($3)), ARRAY(SELECT unnest($3) EXCEPT SELECT _parts($1, $2)), $4 ); $$ LANGUAGE SQL; -- partitions_are( schema, table, partitions ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT partitions_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct partitions' ); $$ LANGUAGE SQL; -- partitions_are( table, partitions, description ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'partitions', ARRAY(SELECT _parts($1) EXCEPT SELECT unnest($2)), ARRAY(SELECT unnest($2) EXCEPT SELECT _parts($1)), $3 ); $$ LANGUAGE SQL; -- partitions_are( table, partitions ) CREATE OR REPLACE FUNCTION partitions_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT partitions_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct partitions' ); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION _ident_array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT quote_ident($1[i]) FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY $1[i] ), $2); $$ LANGUAGE SQL immutable; CREATE OR REPLACE FUNCTION _array_to_sorted_string( name[], text ) RETURNS text AS $$ SELECT array_to_string(ARRAY( SELECT $1[i] FROM generate_series(1, array_upper($1, 1)) s(i) ORDER BY $1[i] ), $2); $$ LANGUAGE SQL immutable; -- policies_are( schema, table, policies[], description ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policies', ARRAY( SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = $1 AND c.relname = $2 ), $4 ); $$ LANGUAGE SQL; -- policies_are( schema, table, policies[] ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policies_are( $1, $2, $3, 'Table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct policies' ); $$ LANGUAGE SQL; -- policies_are( table, policies[], description ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policies', ARRAY( SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) ), ARRAY( SELECT $2[i] FROM generate_series(1, array_upper($2, 1)) s(i) EXCEPT SELECT p.polname FROM pg_catalog.pg_policy p JOIN pg_catalog.pg_class c ON c.oid = p.polrelid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace AND n.nspname NOT IN ('pg_catalog', 'information_schema') ), $3 ); $$ LANGUAGE SQL; -- policies_are( table, policies[] ) CREATE OR REPLACE FUNCTION policies_are( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policies_are( $1, $2, 'Table ' || quote_ident($1) || ' should have the correct policies' ); $$ LANGUAGE SQL; -- policy_roles_are( schema, table, policy, roles[], description ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policy roles', ARRAY( SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 EXCEPT SELECT $4[i] FROM generate_series(1, array_upper($4, 1)) s(i) ), ARRAY( SELECT $4[i] FROM generate_series(1, array_upper($4, 1)) s(i) EXCEPT SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 ), $5 ); $$ LANGUAGE SQL; -- policy_roles_are( schema, table, policy, roles[] ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policy_roles_are( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should have the correct roles' ); $$ LANGUAGE SQL; -- policy_roles_are( table, policy, roles[], description ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _are( 'policy roles', ARRAY( SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') EXCEPT SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) ), ARRAY( SELECT $3[i] FROM generate_series(1, array_upper($3, 1)) s(i) EXCEPT SELECT pr.rolname FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_roles AS pr ON pr.oid = ANY (pp.polroles) JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') ), $4 ); $$ LANGUAGE SQL; -- policy_roles_are( table, policy, roles[] ) CREATE OR REPLACE FUNCTION policy_roles_are( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT policy_roles_are( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should have the correct roles' ); $$ LANGUAGE SQL; -- policy_cmd_is( schema, table, policy, command, description ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text, text ) RETURNS TEXT AS $$ DECLARE cmd text; BEGIN SELECT CASE pp.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' ELSE 'ALL' END FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pn.nspname = $1 AND pc.relname = $2 AND pp.polname = $3 INTO cmd; RETURN is( cmd, upper($4), $5 ); END; $$ LANGUAGE plpgsql; -- policy_cmd_is( schema, table, policy, command ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, NAME, text ) RETURNS TEXT AS $$ SELECT policy_cmd_is( $1, $2, $3, $4, 'Policy ' || quote_ident($3) || ' for table ' || quote_ident($1) || '.' || quote_ident($2) || ' should apply to ' || upper($4) || ' command' ); $$ LANGUAGE sql; -- policy_cmd_is( table, policy, command, description ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text, text ) RETURNS TEXT AS $$ DECLARE cmd text; BEGIN SELECT CASE pp.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'w' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' ELSE 'ALL' END FROM pg_catalog.pg_policy AS pp JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace WHERE pc.relname = $1 AND pp.polname = $2 AND pn.nspname NOT IN ('pg_catalog', 'information_schema') INTO cmd; RETURN is( cmd, upper($3), $4 ); END; $$ LANGUAGE plpgsql; -- policy_cmd_is( table, policy, command ) CREATE OR REPLACE FUNCTION policy_cmd_is( NAME, NAME, text ) RETURNS TEXT AS $$ SELECT policy_cmd_is( $1, $2, $3, 'Policy ' || quote_ident($2) || ' for table ' || quote_ident($1) || ' should apply to ' || upper($3) || ' command' ); $$ LANGUAGE sql; /******************** INHERITANCE ***********************************************/ /* * Internal function to test whether the specified table in the specified schema * has an inheritance chain. Returns true or false. */ CREATE OR REPLACE FUNCTION _inherited( NAME, NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_class c ON n.oid = c.relnamespace WHERE c.relkind = 'r' AND n.nspname = $1 AND c.relname = $2 AND c.relhassubclass = true ); $$ LANGUAGE SQL; /* * Internal function to test whether a specific table in the search_path has an * inheritance chain. Returns true or false. */ CREATE OR REPLACE FUNCTION _inherited( NAME ) RETURNS BOOLEAN AS $$ SELECT EXISTS( SELECT true FROM pg_catalog.pg_class c WHERE c.relkind = 'r' AND pg_catalog.pg_table_is_visible( c.oid ) AND c.relname = $1 AND c.relhassubclass = true ); $$ LANGUAGE SQL; -- has_inherited_tables( schema, table, description ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1, $2 ), $3); $$ LANGUAGE SQL; -- has_inherited_tables( schema, table ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1, $2 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should have descendents' ); $$ LANGUAGE SQL; -- has_inherited_tables( table, description ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1 ), $2 ); $$ LANGUAGE SQL; -- has_inherited_tables( table ) CREATE OR REPLACE FUNCTION has_inherited_tables( NAME ) RETURNS TEXT AS $$ SELECT ok( _inherited( $1 ), 'Table ' || quote_ident( $1 ) || ' should have descendents' ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( schema, table, description ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1, $2 ), $3 ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( schema, table ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1, $2 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not have descendents' ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( table, description ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1 ), $2 ); $$ LANGUAGE SQL; -- hasnt_inherited_tables( table ) CREATE OR REPLACE FUNCTION hasnt_inherited_tables( NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _inherited( $1 ), 'Table ' || quote_ident( $1 ) || ' should not have descendents' ); $$ LANGUAGE SQL; /* * Internal function to test whether the schema-qualified table is an ancestor of * the other schema-qualified table. The integer value is the length of the * inheritance chain: a direct ancestor has has a chain length of 1. */ CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS BOOLEAN AS $$ WITH RECURSIVE inheritance_chain AS ( -- select the ancestor tuple SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level FROM pg_catalog.pg_inherits i WHERE i.inhparent = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND n1.nspname = $1 ) UNION -- select the descendents SELECT i.inhrelid AS descendent_id, p.inheritance_level + 1 AS inheritance_level FROM pg_catalog.pg_inherits i JOIN inheritance_chain p ON p.descendent_id = i.inhparent WHERE i.inhrelid = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $4 AND n1.nspname = $3 ) ) SELECT EXISTS( SELECT true FROM inheritance_chain WHERE inheritance_level = COALESCE($5, inheritance_level) AND descendent_id = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $4 AND n1.nspname = $3 ) ); $$ LANGUAGE SQL; /* * Internal function to check if not-qualified tables * within the search_path are connected by an inheritance chain. */ CREATE OR REPLACE FUNCTION _ancestor_of( NAME, NAME, INT ) RETURNS BOOLEAN AS $$ WITH RECURSIVE inheritance_chain AS ( -- select the ancestor tuple SELECT i.inhrelid AS descendent_id, 1 AS inheritance_level FROM pg_catalog.pg_inherits i WHERE i.inhparent = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $1 AND pg_catalog.pg_table_is_visible( c1.oid ) ) UNION -- select the descendents SELECT i.inhrelid AS descendent_id, p.inheritance_level + 1 AS inheritance_level FROM pg_catalog.pg_inherits i JOIN inheritance_chain p ON p.descendent_id = i.inhparent WHERE i.inhrelid = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND pg_catalog.pg_table_is_visible( c1.oid ) ) ) SELECT EXISTS( SELECT true FROM inheritance_chain WHERE inheritance_level = COALESCE($3, inheritance_level) AND descendent_id = ( SELECT c1.oid FROM pg_catalog.pg_class c1 JOIN pg_catalog.pg_namespace n1 ON c1.relnamespace = n1.oid WHERE c1.relname = $2 AND pg_catalog.pg_table_is_visible( c1.oid ) ) ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be ancestor ' || $5 || ' for ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, NULL ), $5 ); $$ LANGUAGE SQL; -- is_ancestor_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3, $4, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be an ancestor of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, depth ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, $3 ), 'Table ' || quote_ident( $1 ) || ' should be ancestor ' || $3 || ' of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table, description ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, NULL ), $3 ); $$ LANGUAGE SQL; -- is_ancestor_of( table, table ) CREATE OR REPLACE FUNCTION is_ancestor_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || ' should be an ancestor of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, $5 ), $6 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be ancestor ' || $5 || ' for ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, NULL ), $5 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3, $4, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be an ancestor of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3 ), $4 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, depth ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, $3 ), 'Table ' || quote_ident( $1 ) || ' should not be ancestor ' || $3 || ' of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table, description ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, NULL ), $3 ); $$ LANGUAGE SQL; -- isnt_ancestor_of( table, table ) CREATE OR REPLACE FUNCTION isnt_ancestor_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || ' should not be an ancestor of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, $5 ), $6 ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be descendent ' || $5 || ' from ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, NULL ), $5 ); $$ LANGUAGE SQL; -- is_descendent_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $3, $4, $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should be a descendent of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, $3 ), $4 ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, depth ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, $3 ), 'Table ' || quote_ident( $1 ) || ' should be descendent ' || $3 || ' from ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_descendent_of( table, table, description ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, NULL ), $3 ); $$ LANGUAGE SQL; -- is_descendent_of( table, table ) CREATE OR REPLACE FUNCTION is_descendent_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( _ancestor_of( $2, $1, NULL ), 'Table ' || quote_ident( $1 ) || ' should be a descendent of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, $5 ), $6 ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, depth ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $3, $4, $1, $2, $5 ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be descendent ' || $5 || ' from ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $3, $4, $1, $2, NULL ), $5 ); $$ LANGUAGE SQL; -- isnt_descendent_of( schema, table, schema, table ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $3, $4, $1, $2, NULL ), 'Table ' || quote_ident( $1 ) || '.' || quote_ident( $2 ) || ' should not be a descendent of ' || quote_ident( $3 ) || '.' || quote_ident( $4 ) ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, depth, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $2, $1, $3 ), $4 ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, depth ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, INT ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $2, $1, $3 ), 'Table ' || quote_ident( $1 ) || ' should not be descendent ' || $3 || ' from ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table, description ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT ok(NOT _ancestor_of( $2, $1, NULL ), $3 ); $$ LANGUAGE SQL; -- isnt_descendent_of( table, table ) CREATE OR REPLACE FUNCTION isnt_descendent_of( NAME, NAME ) RETURNS TEXT AS $$ SELECT ok( NOT _ancestor_of( $2, $1, NULL ), 'Table ' || quote_ident( $1 ) || ' should not be a descendent of ' || quote_ident( $2) ); $$ LANGUAGE SQL; -- is_normal_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func('f', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_normal_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('f', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( schema, function, description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_normal_function( schema, function ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( function, args[], description ) CREATE OR REPLACE FUNCTION is_normal_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_normal_function( function, args[] ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a normal function' ); $$ LANGUAGE sql; -- is_normal_function( function, description ) CREATE OR REPLACE FUNCTION is_normal_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('f', $1), $2 ); $$ LANGUAGE sql; -- is_normal_function( function ) CREATE OR REPLACE FUNCTION is_normal_function( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('f', $1), 'Function ' || quote_ident($1) || '() should be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('f', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_normal_function( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('f', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_normal_function( schema, function ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_normal_function ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('f', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_normal_function( function, args[] ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('f', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a normal function' ); $$ LANGUAGE sql; -- isnt_normal_function( function, description ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('f', $1), $2 ); $$ LANGUAGE sql; -- isnt_normal_function( function ) CREATE OR REPLACE FUNCTION isnt_normal_function( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('f', $1), 'Function ' || quote_ident($1) || '() should not be a normal function' ); $$ LANGUAGE sql; -- is_window( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'w', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_window( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('w', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a window function' ); $$ LANGUAGE sql; -- is_window( schema, function, description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_window( schema, function ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a window function' ); $$ LANGUAGE sql; -- is_window( function, args[], description ) CREATE OR REPLACE FUNCTION is_window ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_window( function, args[] ) CREATE OR REPLACE FUNCTION is_window( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a window function' ); $$ LANGUAGE sql; -- is_window( function, description ) CREATE OR REPLACE FUNCTION is_window( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('w', $1), $2 ); $$ LANGUAGE sql; -- is_window( function ) CREATE OR REPLACE FUNCTION is_window( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('w', $1), 'Function ' || quote_ident($1) || '() should be a window function' ); $$ LANGUAGE sql; -- isnt_window( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('w', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_window( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('w', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_window( schema, function ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_window ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('w', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_window( function, args[] ) CREATE OR REPLACE FUNCTION isnt_window( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('w', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a window function' ); $$ LANGUAGE sql; -- isnt_window( function, description ) CREATE OR REPLACE FUNCTION isnt_window( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('w', $1), $2 ); $$ LANGUAGE sql; -- isnt_window( function ) CREATE OR REPLACE FUNCTION isnt_window( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('w', $1), 'Function ' || quote_ident($1) || '() should not be a window function' ); $$ LANGUAGE sql; -- is_procedure( schema, function, args[], description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, _type_func( 'p', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- is_procedure( schema, function, args[] ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, _type_func('p', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( schema, function, description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_procedure( schema, function ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( function, args[], description ) CREATE OR REPLACE FUNCTION is_procedure ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- is_procedure( function, args[] ) CREATE OR REPLACE FUNCTION is_procedure( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should be a procedure' ); $$ LANGUAGE sql; -- is_procedure( function, description ) CREATE OR REPLACE FUNCTION is_procedure( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, _type_func('p', $1), $2 ); $$ LANGUAGE sql; -- is_procedure( function ) CREATE OR REPLACE FUNCTION is_procedure( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, _type_func('p', $1), 'Function ' || quote_ident($1) || '() should be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( schema, function, args[], description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, $3, NOT _type_func('p', $1, $2, $3), $4 ); $$ LANGUAGE SQL; -- isnt_procedure( schema, function, args[] ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, $3, NOT _type_func('p', $1, $2, $3), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '(' || array_to_string($3, ', ') || ') should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( schema, function, description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare($1, $2, NOT _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_procedure( schema, function ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME ) RETURNS TEXT AS $$ SELECT _func_compare( $1, $2, NOT _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '.' || quote_ident($2) || '() should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( function, args[], description ) CREATE OR REPLACE FUNCTION isnt_procedure ( NAME, NAME[], TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, $2, NOT _type_func('p', $1, $2), $3 ); $$ LANGUAGE SQL; -- isnt_procedure( function, args[] ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, NAME[] ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, $2, NOT _type_func('p', $1, $2), 'Function ' || quote_ident($1) || '(' || array_to_string($2, ', ') || ') should not be a procedure' ); $$ LANGUAGE sql; -- isnt_procedure( function, description ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME, TEXT ) RETURNS TEXT AS $$ SELECT _func_compare(NULL, $1, NOT _type_func('p', $1), $2 ); $$ LANGUAGE sql; -- isnt_procedure( function ) CREATE OR REPLACE FUNCTION isnt_procedure( NAME ) RETURNS TEXT AS $$ SELECT _func_compare( NULL, $1, NOT _type_func('p', $1), 'Function ' || quote_ident($1) || '() should not be a procedure' ); $$ LANGUAGE sql; pgtap-1.3.2/test/000077500000000000000000000000001455775703000136245ustar00rootroot00000000000000pgtap-1.3.2/test/Dockerfile000066400000000000000000000003501455775703000156140ustar00rootroot00000000000000ARG pgtag FROM postgres:${pgtag:-alpine} ENV POSTGRES_HOST_AUTH_METHOD trust RUN apk --no-cache add make perl-dev patch \ && cpan -T TAP::Parser::SourceHandler::pgTAP ENV PGUSER postgres WORKDIR /pgtap ENV PATH /pgtap/test:$PATH pgtap-1.3.2/test/docker-compose.yml000066400000000000000000000003501455775703000172570ustar00rootroot00000000000000version: "3" services: test: build: context: . args: [pgtag] volumes: - ../:/pgtap - postgres:/var/lib/postgresql/data volumes: postgres: driver_opts: type: tmpfs device: tmpfs pgtap-1.3.2/test/expected/000077500000000000000000000000001455775703000154255ustar00rootroot00000000000000pgtap-1.3.2/test/expected/aretap.out000066400000000000000000001011541455775703000174340ustar00rootroot00000000000000\unset ECHO 1..459 ok 1 - tablespaces_are(tablespaces, desc) should pass ok 2 - tablespaces_are(tablespaces, desc) should have the proper description ok 3 - tablespaces_are(tablespaces, desc) should have the proper diagnostics ok 4 - tablespaces_are(tablespaces) should pass ok 5 - tablespaces_are(tablespaces) should have the proper description ok 6 - tablespaces_are(tablespaces) should have the proper diagnostics ok 7 - tablespaces_are(tablespaces, desc) missing should fail ok 8 - tablespaces_are(tablespaces, desc) missing should have the proper description ok 9 - tablespaces_are(tablespaces, desc) missing should have the proper diagnostics ok 10 - tablespaces_are(tablespaces, desc) extra should fail ok 11 - tablespaces_are(tablespaces, desc) extra should have the proper description ok 12 - tablespaces_are(tablespaces, desc) extra should have the proper diagnostics ok 13 - tablespaces_are(tablespaces, desc) extras and missing should fail ok 14 - tablespaces_are(tablespaces, desc) extras and missing should have the proper description ok 15 - tablespaces_are(tablespaces, desc) extras and missing should have the proper diagnostics ok 16 - schemas_are(schemas, desc) should pass ok 17 - schemas_are(schemas, desc) should have the proper description ok 18 - schemas_are(schemas, desc) should have the proper diagnostics ok 19 - schemas_are(schemas) should pass ok 20 - schemas_are(schemas) should have the proper description ok 21 - schemas_are(schemas) should have the proper diagnostics ok 22 - schemas_are(schemas, desc) missing should fail ok 23 - schemas_are(schemas, desc) missing should have the proper description ok 24 - schemas_are(schemas, desc) missing should have the proper diagnostics ok 25 - schemas_are(schemas, desc) extras should fail ok 26 - schemas_are(schemas, desc) extras should have the proper description ok 27 - schemas_are(schemas, desc) extras should have the proper diagnostics ok 28 - schemas_are(schemas, desc) missing and extras should fail ok 29 - schemas_are(schemas, desc) missing and extras should have the proper description ok 30 - schemas_are(schemas, desc) missing and extras should have the proper diagnostics ok 31 - tables_are(schema, tables, desc) should pass ok 32 - tables_are(schema, tables, desc) should have the proper description ok 33 - tables_are(schema, tables, desc) should have the proper diagnostics ok 34 - tables_are(schema, tables) should pass ok 35 - tables_are(schema, tables) should have the proper description ok 36 - tables_are(schema, tables) should have the proper diagnostics ok 37 - tables_are(tables) should pass ok 38 - tables_are(tables) should have the proper description ok 39 - tables_are(tables) should have the proper diagnostics ok 40 - tables_are(tables, desc) should pass ok 41 - tables_are(tables, desc) should have the proper description ok 42 - tables_are(tables, desc) should have the proper diagnostics ok 43 - tables_are(schema, tables) missing should fail ok 44 - tables_are(schema, tables) missing should have the proper description ok 45 - tables_are(schema, tables) missing should have the proper diagnostics ok 46 - tables_are(tables) missing should fail ok 47 - tables_are(tables) missing should have the proper description ok 48 - tables_are(tables) missing should have the proper diagnostics ok 49 - tables_are(schema, tables) extra should fail ok 50 - tables_are(schema, tables) extra should have the proper description ok 51 - tables_are(schema, tables) extra should have the proper diagnostics ok 52 - tables_are(tables) extra should fail ok 53 - tables_are(tables) extra should have the proper description ok 54 - tables_are(tables) extra should have the proper diagnostics ok 55 - tables_are(schema, tables) extra and missing should fail ok 56 - tables_are(schema, tables) extra and missing should have the proper description ok 57 - tables_are(schema, tables) extra and missing should have the proper diagnostics ok 58 - tables_are(tables) extra and missing should fail ok 59 - tables_are(tables) extra and missing should have the proper description ok 60 - tables_are(tables) extra and missing should have the proper diagnostics ok 61 - views_are(schema, views, desc) should pass ok 62 - views_are(schema, views, desc) should have the proper description ok 63 - views_are(schema, views, desc) should have the proper diagnostics ok 64 - views_are(schema, views) should pass ok 65 - views_are(schema, views) should have the proper description ok 66 - views_are(schema, views) should have the proper diagnostics ok 67 - views_are(views) should pass ok 68 - views_are(views) should have the proper description ok 69 - views_are(views) should have the proper diagnostics ok 70 - views_are(views, desc) should pass ok 71 - views_are(views, desc) should have the proper description ok 72 - views_are(views, desc) should have the proper diagnostics ok 73 - views_are(schema, views) missing should fail ok 74 - views_are(schema, views) missing should have the proper description ok 75 - views_are(schema, views) missing should have the proper diagnostics ok 76 - views_are(views) missing should fail ok 77 - views_are(views) missing should have the proper description ok 78 - views_are(views) missing should have the proper diagnostics ok 79 - views_are(schema, views) extra should fail ok 80 - views_are(schema, views) extra should have the proper description ok 81 - views_are(schema, views) extra should have the proper diagnostics ok 82 - views_are(views) extra should fail ok 83 - views_are(views) extra should have the proper description ok 84 - views_are(views) extra should have the proper diagnostics ok 85 - views_are(schema, views) extra and missing should fail ok 86 - views_are(schema, views) extra and missing should have the proper description ok 87 - views_are(schema, views) extra and missing should have the proper diagnostics ok 88 - views_are(views) extra and missing should fail ok 89 - views_are(views) extra and missing should have the proper description ok 90 - views_are(views) extra and missing should have the proper diagnostics ok 91 - sequences_are(schema, sequences, desc) should pass ok 92 - sequences_are(schema, sequences, desc) should have the proper description ok 93 - sequences_are(schema, sequences, desc) should have the proper diagnostics ok 94 - sequences_are(schema, sequences) should pass ok 95 - sequences_are(schema, sequences) should have the proper description ok 96 - sequences_are(schema, sequences) should have the proper diagnostics ok 97 - sequences_are(sequences) should pass ok 98 - sequences_are(sequences) should have the proper description ok 99 - sequences_are(sequences) should have the proper diagnostics ok 100 - sequences_are(sequences, desc) should pass ok 101 - sequences_are(sequences, desc) should have the proper description ok 102 - sequences_are(sequences, desc) should have the proper diagnostics ok 103 - sequences_are(schema, sequences) missing should fail ok 104 - sequences_are(schema, sequences) missing should have the proper description ok 105 - sequences_are(schema, sequences) missing should have the proper diagnostics ok 106 - sequences_are(sequences) missing should fail ok 107 - sequences_are(sequences) missing should have the proper description ok 108 - sequences_are(sequences) missing should have the proper diagnostics ok 109 - sequences_are(schema, sequences) extra should fail ok 110 - sequences_are(schema, sequences) extra should have the proper description ok 111 - sequences_are(schema, sequences) extra should have the proper diagnostics ok 112 - sequences_are(sequences) extra should fail ok 113 - sequences_are(sequences) extra should have the proper description ok 114 - sequences_are(sequences) extra should have the proper diagnostics ok 115 - sequences_are(schema, sequences) extra and missing should fail ok 116 - sequences_are(schema, sequences) extra and missing should have the proper description ok 117 - sequences_are(schema, sequences) extra and missing should have the proper diagnostics ok 118 - sequences_are(sequences) extra and missing should fail ok 119 - sequences_are(sequences) extra and missing should have the proper description ok 120 - sequences_are(sequences) extra and missing should have the proper diagnostics ok 121 - functions_are(schema, functions, desc) should pass ok 122 - functions_are(schema, functions, desc) should have the proper description ok 123 - functions_are(schema, functions, desc) should have the proper diagnostics ok 124 - functions_are(schema, functions) should pass ok 125 - functions_are(schema, functions) should have the proper description ok 126 - functions_are(schema, functions, desc) + missing should fail ok 127 - functions_are(schema, functions, desc) + missing should have the proper description ok 128 - functions_are(schema, functions, desc) + missing should have the proper diagnostics ok 129 - functions_are(schema, functions, desc) + extra should fail ok 130 - functions_are(schema, functions, desc) + extra should have the proper description ok 131 - functions_are(schema, functions, desc) + extra should have the proper diagnostics ok 132 - functions_are(schema, functions, desc) + extra & missing should fail ok 133 - functions_are(schema, functions, desc) + extra & missing should have the proper description ok 134 - functions_are(schema, functions, desc) + extra & missing should have the proper diagnostics ok 135 - functions_are(functions, desc) should pass ok 136 - functions_are(functions, desc) should have the proper description ok 137 - functions_are(functions, desc) should have the proper diagnostics ok 138 - functions_are(functions) should pass ok 139 - functions_are(functions) should have the proper description ok 140 - functions_are(functions) should have the proper diagnostics ok 141 - functions_are(functions, desc) + missing should fail ok 142 - functions_are(functions, desc) + missing should have the proper description ok 143 - functions_are(functions, desc) + missing should have the proper diagnostics ok 144 - functions_are(functions, desc) + extra should fail ok 145 - functions_are(functions, desc) + extra should have the proper description ok 146 - functions_are(functions, desc) + extra should have the proper diagnostics ok 147 - functions_are(functions, desc) + extra & missing should fail ok 148 - functions_are(functions, desc) + extra & missing should have the proper description ok 149 - functions_are(functions, desc) + extra & missing should have the proper diagnostics ok 150 - indexes_are(schema, table, indexes, desc) should pass ok 151 - indexes_are(schema, table, indexes, desc) should have the proper description ok 152 - indexes_are(schema, table, indexes, desc) should have the proper diagnostics ok 153 - indexes_are(schema, table, indexes) should pass ok 154 - indexes_are(schema, table, indexes) should have the proper description ok 155 - indexes_are(schema, table, indexes) should have the proper diagnostics ok 156 - indexes_are(schema, table, indexes) + extra should fail ok 157 - indexes_are(schema, table, indexes) + extra should have the proper description ok 158 - indexes_are(schema, table, indexes) + extra should have the proper diagnostics ok 159 - indexes_are(schema, table, indexes) + missing should fail ok 160 - indexes_are(schema, table, indexes) + missing should have the proper description ok 161 - indexes_are(schema, table, indexes) + missing should have the proper diagnostics ok 162 - indexes_are(schema, table, indexes) + extra & missing should fail ok 163 - indexes_are(schema, table, indexes) + extra & missing should have the proper description ok 164 - indexes_are(schema, table, indexes) + extra & missing should have the proper diagnostics ok 165 - indexes_are(table, indexes, desc) should pass ok 166 - indexes_are(table, indexes, desc) should have the proper description ok 167 - indexes_are(table, indexes, desc) should have the proper diagnostics ok 168 - indexes_are(table, indexes) should pass ok 169 - indexes_are(table, indexes) should have the proper description ok 170 - indexes_are(table, indexes) should have the proper diagnostics ok 171 - indexes_are(table, indexes) + extra should fail ok 172 - indexes_are(table, indexes) + extra should have the proper description ok 173 - indexes_are(table, indexes) + extra should have the proper diagnostics ok 174 - indexes_are(table, indexes) + missing should fail ok 175 - indexes_are(table, indexes) + missing should have the proper description ok 176 - indexes_are(table, indexes) + missing should have the proper diagnostics ok 177 - indexes_are(table, indexes) + extra & missing should fail ok 178 - indexes_are(table, indexes) + extra & missing should have the proper description ok 179 - indexes_are(table, indexes) + extra & missing should have the proper diagnostics ok 180 - users_are(users, desc) should pass ok 181 - users_are(users, desc) should have the proper description ok 182 - users_are(users, desc) should have the proper diagnostics ok 183 - users_are(users) should pass ok 184 - users_are(users) should have the proper description ok 185 - users_are(users) should have the proper diagnostics ok 186 - users_are(users, desc) missing should fail ok 187 - users_are(users, desc) missing should have the proper description ok 188 - users_are(users, desc) missing should have the proper diagnostics ok 189 - users_are(users, desc) extras should fail ok 190 - users_are(users, desc) extras should have the proper description ok 191 - users_are(users, desc) extras should have the proper diagnostics ok 192 - users_are(users, desc) missing and extras should fail ok 193 - users_are(users, desc) missing and extras should have the proper description ok 194 - users_are(users, desc) missing and extras should have the proper diagnostics ok 195 - groups_are(groups, desc) should pass ok 196 - groups_are(groups, desc) should have the proper description ok 197 - groups_are(groups, desc) should have the proper diagnostics ok 198 - groups_are(groups) should pass ok 199 - groups_are(groups) should have the proper description ok 200 - groups_are(groups) should have the proper diagnostics ok 201 - groups_are(groups, desc) missing should fail ok 202 - groups_are(groups, desc) missing should have the proper description ok 203 - groups_are(groups, desc) missing should have the proper diagnostics ok 204 - groups_are(groups, desc) extras should fail ok 205 - groups_are(groups, desc) extras should have the proper description ok 206 - groups_are(groups, desc) extras should have the proper diagnostics ok 207 - groups_are(groups, desc) missing and extras should fail ok 208 - groups_are(groups, desc) missing and extras should have the proper description ok 209 - groups_are(groups, desc) missing and extras should have the proper diagnostics ok 210 - languages_are(languages, desc) should pass ok 211 - languages_are(languages, desc) should have the proper description ok 212 - languages_are(languages, desc) should have the proper diagnostics ok 213 - languages_are(languages) should pass ok 214 - languages_are(languages) should have the proper description ok 215 - languages_are(languages) should have the proper diagnostics ok 216 - languages_are(languages, desc) missing should fail ok 217 - languages_are(languages, desc) missing should have the proper description ok 218 - languages_are(languages, desc) missing should have the proper diagnostics ok 219 - languages_are(languages, desc) extras should fail ok 220 - languages_are(languages, desc) extras should have the proper description ok 221 - languages_are(languages, desc) extras should have the proper diagnostics ok 222 - languages_are(languages, desc) missing and extras should fail ok 223 - languages_are(languages, desc) missing and extras should have the proper description ok 224 - languages_are(languages, desc) missing and extras should have the proper diagnostics ok 225 - opclasses_are(schema, opclasses, desc) should pass ok 226 - opclasses_are(schema, opclasses, desc) should have the proper description ok 227 - opclasses_are(schema, opclasses, desc) should have the proper diagnostics ok 228 - opclasses_are(schema, opclasses) should pass ok 229 - opclasses_are(schema, opclasses) should have the proper description ok 230 - opclasses_are(schema, opclasses, desc) + missing should fail ok 231 - opclasses_are(schema, opclasses, desc) + missing should have the proper description ok 232 - opclasses_are(schema, opclasses, desc) + missing should have the proper diagnostics ok 233 - opclasses_are(schema, opclasses, desc) + extra should fail ok 234 - opclasses_are(schema, opclasses, desc) + extra should have the proper description ok 235 - opclasses_are(schema, opclasses, desc) + extra should have the proper diagnostics ok 236 - opclasses_are(schema, opclasses, desc) + extra & missing should fail ok 237 - opclasses_are(schema, opclasses, desc) + extra & missing should have the proper description ok 238 - opclasses_are(schema, opclasses, desc) + extra & missing should have the proper diagnostics ok 239 - opclasses_are(opclasses) should pass ok 240 - opclasses_are(opclasses) should have the proper description ok 241 - opclasses_are(opclasses) should have the proper diagnostics ok 242 - opclasses_are(opclasses, desc) + missing should fail ok 243 - opclasses_are(opclasses, desc) + missing should have the proper description ok 244 - opclasses_are(opclasses, desc) + missing should have the proper diagnostics ok 245 - opclasses_are(opclasses, desc) + extra should fail ok 246 - opclasses_are(opclasses, desc) + extra should have the proper description ok 247 - opclasses_are(opclasses, desc) + extra should have the proper diagnostics ok 248 - opclasses_are(opclasses, desc) + extra & missing should fail ok 249 - opclasses_are(opclasses, desc) + extra & missing should have the proper description ok 250 - opclasses_are(opclasses, desc) + extra & missing should have the proper diagnostics ok 251 - rules_are(schema, table, rules, desc) should pass ok 252 - rules_are(schema, table, rules, desc) should have the proper description ok 253 - rules_are(schema, table, rules, desc) should have the proper diagnostics ok 254 - rules_are(schema, table, rules) should pass ok 255 - rules_are(schema, table, rules) should have the proper description ok 256 - rules_are(schema, table, rules) should have the proper diagnostics ok 257 - rules_are(schema, table, rules) + extra should fail ok 258 - rules_are(schema, table, rules) + extra should have the proper description ok 259 - rules_are(schema, table, rules) + extra should have the proper diagnostics ok 260 - rules_are(schema, table, rules) + missing should fail ok 261 - rules_are(schema, table, rules) + missing should have the proper description ok 262 - rules_are(schema, table, rules) + missing should have the proper diagnostics ok 263 - rules_are(schema, table, rules) + extra & missing should fail ok 264 - rules_are(schema, table, rules) + extra & missing should have the proper description ok 265 - rules_are(schema, table, rules) + extra & missing should have the proper diagnostics ok 266 - rules_are(table, rules, desc) should pass ok 267 - rules_are(table, rules, desc) should have the proper description ok 268 - rules_are(table, rules, desc) should have the proper diagnostics ok 269 - rules_are(table, rules) should pass ok 270 - rules_are(table, rules) should have the proper description ok 271 - rules_are(table, rules) should have the proper diagnostics ok 272 - rules_are(table, rules) + extra should fail ok 273 - rules_are(table, rules) + extra should have the proper description ok 274 - rules_are(table, rules) + extra should have the proper diagnostics ok 275 - rules_are(table, rules) + missing should fail ok 276 - rules_are(table, rules) + missing should have the proper description ok 277 - rules_are(table, rules) + missing should have the proper diagnostics ok 278 - rules_are(table, rules) + extra & missing should fail ok 279 - rules_are(table, rules) + extra & missing should have the proper description ok 280 - rules_are(table, rules) + extra & missing should have the proper diagnostics ok 281 - types_are(schema, types, desc) should pass ok 282 - types_are(schema, types, desc) should have the proper description ok 283 - types_are(schema, types, desc) should have the proper diagnostics ok 284 - types_are(schema, types) should pass ok 285 - types_are(schema, types) should have the proper description ok 286 - types_are(schema, types, desc) + missing should fail ok 287 - types_are(schema, types, desc) + missing should have the proper description ok 288 - types_are(schema, types, desc) + missing should have the proper diagnostics ok 289 - types_are(schema, types, desc) + extra should fail ok 290 - types_are(schema, types, desc) + extra should have the proper description ok 291 - types_are(schema, types, desc) + extra should have the proper diagnostics ok 292 - types_are(schema, types, desc) + extra & missing should fail ok 293 - types_are(schema, types, desc) + extra & missing should have the proper description ok 294 - types_are(schema, types, desc) + extra & missing should have the proper diagnostics ok 295 - types_are(types) should pass ok 296 - types_are(types) should have the proper description ok 297 - types_are(types) should have the proper diagnostics ok 298 - types_are(types, desc) + missing should fail ok 299 - types_are(types, desc) + missing should have the proper description ok 300 - types_are(types, desc) + missing should have the proper diagnostics ok 301 - types_are(types, desc) + extra should fail ok 302 - types_are(types, desc) + extra should have the proper description ok 303 - types_are(types, desc) + extra should have the proper diagnostics ok 304 - types_are(types, desc) + extra & missing should fail ok 305 - types_are(types, desc) + extra & missing should have the proper description ok 306 - types_are(types, desc) + extra & missing should have the proper diagnostics ok 307 - domains_are(schema, domains, desc) should pass ok 308 - domains_are(schema, domains, desc) should have the proper description ok 309 - domains_are(schema, domains, desc) should have the proper diagnostics ok 310 - domains_are(schema, domains) should pass ok 311 - domains_are(schema, domains) should have the proper description ok 312 - domains_are(schema, domains) should have the proper diagnostics ok 313 - domains_are(schema, domains, desc) fail should fail ok 314 - domains_are(schema, domains, desc) fail should have the proper description ok 315 - domains_are(schema, domains, desc) fail should have the proper diagnostics ok 316 - domains_are(schema, domains) fail should fail ok 317 - domains_are(schema, domains) fail should have the proper description ok 318 - domains_are(schema, domains) fail should have the proper diagnostics ok 319 - domains_are(domains, desc) should pass ok 320 - domains_are(domains, desc) should have the proper description ok 321 - domains_are(domains, desc) should have the proper diagnostics ok 322 - domains_are(domains) should pass ok 323 - domains_are(domains) should have the proper description ok 324 - domains_are(domains) should have the proper diagnostics ok 325 - domains_are(domains, desc) fail should fail ok 326 - domains_are(domains, desc) fail should have the proper description ok 327 - domains_are(domains, desc) fail should have the proper diagnostics ok 328 - domains_are(domains) fail should fail ok 329 - domains_are(domains) fail should have the proper description ok 330 - domains_are(domains) fail should have the proper diagnostics ok 331 - casts_are(casts, desc) should pass ok 332 - casts_are(casts, desc) should have the proper description ok 333 - casts_are(casts, desc) should have the proper diagnostics ok 334 - casts_are(casts) should pass ok 335 - casts_are(casts) should have the proper description ok 336 - casts_are(casts) should have the proper diagnostics ok 337 - casts_are(casts, desc) missing should fail ok 338 - casts_are(casts, desc) missing should have the proper description ok 339 - casts_are(casts, desc) missing should have the proper diagnostics ok 340 - casts_are(casts, desc) extra should fail ok 341 - casts_are(casts, desc) extra should have the proper description ok 342 - casts_are(casts, desc) extra should have the proper diagnostics ok 343 - casts_are(casts, desc) extras and missing should fail ok 344 - casts_are(casts, desc) extras and missing should have the proper description ok 345 - casts_are(casts, desc) extras and missing should have the proper diagnostics ok 346 - operators_are(schema, operators, desc) should pass ok 347 - operators_are(schema, operators, desc) should have the proper description ok 348 - operators_are(schema, operators, desc) should have the proper diagnostics ok 349 - operators_are(schema, operators) should pass ok 350 - operators_are(schema, operators) should have the proper description ok 351 - operators_are(schema, operators) should have the proper diagnostics ok 352 - operators_are(schema, operators, desc) fail should fail ok 353 - operators_are(schema, operators, desc) fail should have the proper description ok 354 - operators_are(schema, operators, desc) fail should have the proper diagnostics ok 355 - operators_are(schema, operators) fail should fail ok 356 - operators_are(schema, operators) fail should have the proper description ok 357 - operators_are(schema, operators) fail should have the proper diagnostics ok 358 - operators_are(operators, desc) should pass ok 359 - operators_are(operators, desc) should have the proper description ok 360 - operators_are(operators, desc) should have the proper diagnostics ok 361 - operators_are(operators) should pass ok 362 - operators_are(operators) should have the proper description ok 363 - operators_are(operators) should have the proper diagnostics ok 364 - operators_are(operators, desc) fail should fail ok 365 - operators_are(operators, desc) fail should have the proper description ok 366 - operators_are(operators, desc) fail should have the proper diagnostics ok 367 - operators_are(operators) fail should fail ok 368 - operators_are(operators) fail should have the proper description ok 369 - operators_are(operators) fail should have the proper diagnostics ok 370 - columns_are(schema, table, columns, desc) should pass ok 371 - columns_are(schema, table, columns, desc) should have the proper description ok 372 - columns_are(schema, table, columns, desc) should have the proper diagnostics ok 373 - columns_are(schema, table, columns) should pass ok 374 - columns_are(schema, table, columns) should have the proper description ok 375 - columns_are(schema, table, columns) should have the proper diagnostics ok 376 - columns_are(schema, table, columns) + extra should fail ok 377 - columns_are(schema, table, columns) + extra should have the proper description ok 378 - columns_are(schema, table, columns) + extra should have the proper diagnostics ok 379 - columns_are(schema, table, columns) + missing should fail ok 380 - columns_are(schema, table, columns) + missing should have the proper description ok 381 - columns_are(schema, table, columns) + missing should have the proper diagnostics ok 382 - columns_are(schema, table, columns) + extra & missing should fail ok 383 - columns_are(schema, table, columns) + extra & missing should have the proper description ok 384 - columns_are(schema, table, columns) + extra & missing should have the proper diagnostics ok 385 - columns_are(table, columns, desc) should pass ok 386 - columns_are(table, columns, desc) should have the proper description ok 387 - columns_are(table, columns, desc) should have the proper diagnostics ok 388 - columns_are(table, columns) should pass ok 389 - columns_are(table, columns) should have the proper description ok 390 - columns_are(table, columns) should have the proper diagnostics ok 391 - columns_are(table, columns) + extra should fail ok 392 - columns_are(table, columns) + extra should have the proper description ok 393 - columns_are(table, columns) + extra should have the proper diagnostics ok 394 - columns_are(table, columns) + missing should fail ok 395 - columns_are(table, columns) + missing should have the proper description ok 396 - columns_are(table, columns) + missing should have the proper diagnostics ok 397 - columns_are(table, columns) + extra & missing should fail ok 398 - columns_are(table, columns) + extra & missing should have the proper description ok 399 - columns_are(table, columns) + extra & missing should have the proper diagnostics ok 400 - materialized_views_are(schema, materialized_views, desc) should pass ok 401 - materialized_views_are(schema, materialized_views, desc) should have the proper description ok 402 - materialized_views_are(schema, materialized_views, desc) should have the proper diagnostics ok 403 - materialized_views_are(schema, materialized_views) should pass ok 404 - materialized_views_are(schema, materialized_views) should have the proper description ok 405 - materialized_views_are(schema, materialized_views) should have the proper diagnostics ok 406 - materialized_views_are(views) should pass ok 407 - materialized_views_are(views) should have the proper description ok 408 - materialized_views_are(views) should have the proper diagnostics ok 409 - materialized_views_are(views, desc) should pass ok 410 - materialized_views_are(views, desc) should have the proper description ok 411 - materialized_views_are(views, desc) should have the proper diagnostics ok 412 - materialized_views_are(schema, materialized_views) missing should fail ok 413 - materialized_views_are(schema, materialized_views) missing should have the proper description ok 414 - materialized_views_are(schema, materialized_views) missing should have the proper diagnostics ok 415 - materialized_views_are(materialized_views) missing should fail ok 416 - materialized_views_are(materialized_views) missing should have the proper description ok 417 - materialized_views_are(materialized_views) missing should have the proper diagnostics ok 418 - materialized_views_are(schema, materialized_views) extra should fail ok 419 - materialized_views_are(schema, materialized_views) extra should have the proper description ok 420 - materialized_views_are(schema, materialized_views) extra should have the proper diagnostics ok 421 - materialized_views_are(materialized_views) extra should fail ok 422 - materialized_views_are(materialized_views) extra should have the proper description ok 423 - materialized_views_are(materialized_views) extra should have the proper diagnostics ok 424 - materialized_views_are(schema, materialized_views) extra and missing should fail ok 425 - materialized_views_are(schema, materialized_views) extra and missing should have the proper description ok 426 - materialized_views_are(schema, materialized_views) extra and missing should have the proper diagnostics ok 427 - materialized_views_are(materialized_views) extra and missing should fail ok 428 - materialized_views_are(materialized_views) extra and missing should have the proper description ok 429 - materialized_views_are(materialized_views) extra and missing should have the proper diagnostics ok 430 - foreign_tables_are(schema, tables, desc) should pass ok 431 - foreign_tables_are(schema, tables, desc) should have the proper description ok 432 - foreign_tables_are(schema, tables, desc) should have the proper diagnostics ok 433 - foreign_tables_are(tables, desc) should pass ok 434 - foreign_tables_are(tables, desc) should have the proper description ok 435 - foreign_tables_are(tables, desc) should have the proper diagnostics ok 436 - foreign_tables_are(schema, tables) should pass ok 437 - foreign_tables_are(schema, tables) should have the proper description ok 438 - foreign_tables_are(schema, tables) should have the proper diagnostics ok 439 - foreign_tables_are(tables) should pass ok 440 - foreign_tables_are(tables) should have the proper description ok 441 - foreign_tables_are(tables) should have the proper diagnostics ok 442 - foreign_tables_are(schema, tables) missing should fail ok 443 - foreign_tables_are(schema, tables) missing should have the proper description ok 444 - foreign_tables_are(schema, tables) missing should have the proper diagnostics ok 445 - foreign_tables_are(tables) missing should fail ok 446 - foreign_tables_are(tables) missing should have the proper description ok 447 - foreign_tables_are(tables) missing should have the proper diagnostics ok 448 - foreign_tables_are(schema, tables) extra should fail ok 449 - foreign_tables_are(schema, tables) extra should have the proper description ok 450 - foreign_tables_are(schema, tables) extra should have the proper diagnostics ok 451 - foreign_tables_are(tables) extra should fail ok 452 - foreign_tables_are(tables) extra should have the proper description ok 453 - foreign_tables_are(tables) extra should have the proper diagnostics ok 454 - foreign_tables_are(schema, tables) extra and missing should fail ok 455 - foreign_tables_are(schema, tables) extra and missing should have the proper description ok 456 - foreign_tables_are(schema, tables) extra and missing should have the proper diagnostics ok 457 - foreign_tables_are(tables) extra and missing should fail ok 458 - foreign_tables_are(tables) extra and missing should have the proper description ok 459 - foreign_tables_are(tables) extra and missing should have the proper diagnostics pgtap-1.3.2/test/expected/build.out000066400000000000000000000000141455775703000172500ustar00rootroot00000000000000\unset ECHO pgtap-1.3.2/test/expected/check.out000066400000000000000000000063341455775703000172410ustar00rootroot00000000000000\unset ECHO 1..48 ok 1 - has_check( schema, table, desc ) should pass ok 2 - has_check( schema, table, desc ) should have the proper description ok 3 - has_check( schema, table, desc ) should have the proper diagnostics ok 4 - has_check( table, desc ) should pass ok 5 - has_check( table, desc ) should have the proper description ok 6 - has_check( table, desc ) should have the proper diagnostics ok 7 - has_check( table ) should pass ok 8 - has_check( table ) should have the proper description ok 9 - has_check( table ) should have the proper diagnostics ok 10 - has_check( schema, table, descr ) fail should fail ok 11 - has_check( schema, table, descr ) fail should have the proper description ok 12 - has_check( schema, table, descr ) fail should have the proper diagnostics ok 13 - has_check( table, desc ) fail should fail ok 14 - has_check( table, desc ) fail should have the proper description ok 15 - has_check( table, desc ) fail should have the proper diagnostics ok 16 - col_has_check( sch, tab, col, desc ) should pass ok 17 - col_has_check( sch, tab, col, desc ) should have the proper description ok 18 - col_has_check( sch, tab, col, desc ) should have the proper diagnostics ok 19 - col_has_check( sch, tab, cols, desc ) should pass ok 20 - col_has_check( sch, tab, cols, desc ) should have the proper description ok 21 - col_has_check( sch, tab, cols, desc ) should have the proper diagnostics ok 22 - col_has_check( tab, col, desc ) should pass ok 23 - col_has_check( tab, col, desc ) should have the proper description ok 24 - col_has_check( tab, col, desc ) should have the proper diagnostics ok 25 - col_has_check( tab, cols, desc ) should pass ok 26 - col_has_check( tab, cols, desc ) should have the proper description ok 27 - col_has_check( tab, cols, desc ) should have the proper diagnostics ok 28 - col_has_check( table, column ) should pass ok 29 - col_has_check( table, column ) should have the proper description ok 30 - col_has_check( table, column ) should have the proper diagnostics ok 31 - col_has_check( table, columns ) should pass ok 32 - col_has_check( table, columns ) should have the proper description ok 33 - col_has_check( table, columns ) should have the proper diagnostics ok 34 - col_has_check( sch, tab, col, desc ) fail should fail ok 35 - col_has_check( sch, tab, col, desc ) fail should have the proper description ok 36 - col_has_check( sch, tab, col, desc ) fail should have the proper diagnostics ok 37 - col_has_check( tab, col, desc ) fail should fail ok 38 - col_has_check( tab, col, desc ) fail should have the proper description ok 39 - col_has_check( tab, col, desc ) fail should have the proper diagnostics ok 40 - col_has_check( sch, tab, col[], desc ) should pass ok 41 - col_has_check( sch, tab, col[], desc ) should have the proper description ok 42 - col_has_check( sch, tab, col[], desc ) should have the proper diagnostics ok 43 - col_has_check( tab, col[], desc ) should pass ok 44 - col_has_check( tab, col[], desc ) should have the proper description ok 45 - col_has_check( tab, col[], desc ) should have the proper diagnostics ok 46 - col_has_check( tab, col[] ) should pass ok 47 - col_has_check( tab, col[] ) should have the proper description ok 48 - col_has_check( tab, col[] ) should have the proper diagnostics pgtap-1.3.2/test/expected/cmpok.out000066400000000000000000000042421455775703000172710ustar00rootroot00000000000000\unset ECHO 1..38 ok 1 - cmp_ok( int, =, int ) should pass ok 2 - cmp_ok( int, =, int ) should have the proper description ok 3 - cmp_ok( int, =, int ) should have the proper diagnostics ok 4 - cmp_ok( int, <>, int ) should pass ok 5 - cmp_ok( int, <>, int ) should have the proper description ok 6 - cmp_ok( int, <>, int ) should have the proper diagnostics ok 7 - cmp_ok( polygon, ~=, polygon ) should pass ok 8 - cmp_ok( polygon, ~=, polygon ) should have the proper description ok 9 - cmp_ok( int[], =, int[] ) should pass ok 10 - cmp_ok( int[], =, int[] ) should have the proper description ok 11 - cmp_ok( int[], =, int[] ) should have the proper diagnostics ok 12 - cmp_ok( inet[], =, inet[] ) should pass ok 13 - cmp_ok( inet[], =, inet[] ) should have the proper description ok 14 - cmp_ok( inet[], =, inet[] ) should have the proper diagnostics ok 15 - cmp_ok() fail should fail ok 16 - cmp_ok() fail should have the proper description ok 17 - cmp_ok() fail should have the proper diagnostics ok 18 - cmp_ok() NULL fail should fail ok 19 - cmp_ok() NULL fail should have the proper description ok 20 - cmp_ok() NULL fail should have the proper diagnostics ok 21 - isa_ok("", text, desc) should pass ok 22 - isa_ok("", text, desc) should have the proper description ok 23 - isa_ok("", text, desc) should have the proper diagnostics ok 24 - isa_ok("", text, desc) should pass ok 25 - isa_ok("", text, desc) should have the proper description ok 26 - isa_ok("", text, desc) should have the proper diagnostics ok 27 - isa_ok(false, boolean) should pass ok 28 - isa_ok(false, boolean) should have the proper description ok 29 - isa_ok(false, boolean) should have the proper diagnostics ok 30 - isa_ok(NULL, boolean) should pass ok 31 - isa_ok(NULL, boolean) should have the proper description ok 32 - isa_ok(NULL, boolean) should have the proper diagnostics ok 33 - isa_ok(ARRAY, boolean[]) should pass ok 34 - isa_ok(ARRAY, boolean[]) should have the proper description ok 35 - isa_ok(ARRAY, boolean[]) should have the proper diagnostics ok 36 - isa_ok(bool, int[]) should fail ok 37 - isa_ok(bool, int[]) should have the proper description ok 38 - isa_ok(bool, int[]) should have the proper diagnostics pgtap-1.3.2/test/expected/coltap.out000066400000000000000000000504551455775703000174510ustar00rootroot00000000000000\unset ECHO 1..276 ok 1 - col_not_null( sch, tab, col, desc ) should pass ok 2 - col_not_null( sch, tab, col, desc ) should have the proper description ok 3 - col_not_null( sch, tab, col, desc ) should have the proper diagnostics ok 4 - col_not_null( sch, tab, col::name ) should pass ok 5 - col_not_null( sch, tab, col::name ) should have the proper description ok 6 - col_not_null( sch, tab, col::name ) should have the proper diagnostics ok 7 - col_not_null( tab, col, desc ) should pass ok 8 - col_not_null( tab, col, desc ) should have the proper description ok 9 - col_not_null( tab, col, desc ) should have the proper diagnostics ok 10 - col_not_null( table, column ) should pass ok 11 - col_not_null( table, column ) should have the proper description ok 12 - col_not_null( table, column ) should have the proper diagnostics ok 13 - col_not_null( table, column ) fail should fail ok 14 - col_not_null( table, column ) fail should have the proper description ok 15 - col_not_null( table, column ) fail should have the proper diagnostics ok 16 - col_not_null( sch, tab, noncol, desc ) should fail ok 17 - col_not_null( sch, tab, noncol, desc ) should have the proper description ok 18 - col_not_null( sch, tab, noncol, desc ) should have the proper diagnostics ok 19 - col_not_null( table, noncolumn ) fail should fail ok 20 - col_not_null( table, noncolumn ) fail should have the proper description ok 21 - col_not_null( table, noncolumn ) fail should have the proper diagnostics ok 22 - col_is_null( sch, tab, col, desc ) should pass ok 23 - col_is_null( sch, tab, col, desc ) should have the proper description ok 24 - col_is_null( sch, tab, col, desc ) should have the proper diagnostics ok 25 - col_is_null( sch, tab, col::name ) should pass ok 26 - col_is_null( sch, tab, col::name ) should have the proper description ok 27 - col_is_null( sch, tab, col::name ) should have the proper diagnostics ok 28 - col_is_null( tab, col, desc ) should pass ok 29 - col_is_null( tab, col, desc ) should have the proper description ok 30 - col_is_null( tab, col, desc ) should have the proper diagnostics ok 31 - col_is_null( tab, col ) should pass ok 32 - col_is_null( tab, col ) should have the proper description ok 33 - col_is_null( tab, col ) should have the proper diagnostics ok 34 - col_is_null( tab, col ) fail should fail ok 35 - col_is_null( tab, col ) fail should have the proper description ok 36 - col_is_null( tab, col ) fail should have the proper diagnostics ok 37 - col_is_null( sch, tab, noncol, desc ) should fail ok 38 - col_is_null( sch, tab, noncol, desc ) should have the proper description ok 39 - col_is_null( sch, tab, noncol, desc ) should have the proper diagnostics ok 40 - col_is_null( table, noncolumn ) fail should fail ok 41 - col_is_null( table, noncolumn ) fail should have the proper description ok 42 - col_is_null( table, noncolumn ) fail should have the proper diagnostics ok 43 - col_type_is( sch, tab, col, sch, type, desc ) should pass ok 44 - col_type_is( sch, tab, col, sch, type, desc ) should have the proper description ok 45 - col_type_is( sch, tab, col, sch, type, desc ) should have the proper diagnostics ok 46 - col_type_is( sch, tab, col, sch, type, desc ) should pass ok 47 - col_type_is( sch, tab, col, sch, type, desc ) should have the proper description ok 48 - col_type_is( sch, tab, col, sch, type, desc ) should have the proper diagnostics ok 49 - col_type_is( sch, tab, myNum, sch, type, desc ) should pass ok 50 - col_type_is( sch, tab, myNum, sch, type, desc ) should have the proper description ok 51 - col_type_is( sch, tab, myNum, sch, type, desc ) should have the proper diagnostics ok 52 - col_type_is( sch, tab, myNum, sch, type, desc ) should pass ok 53 - col_type_is( sch, tab, myNum, sch, type, desc ) should have the proper description ok 54 - col_type_is( sch, tab, myNum, sch, type, desc ) should have the proper diagnostics ok 55 - col_type_is( sch, tab, camel, sch, type, desc ) should pass ok 56 - col_type_is( sch, tab, camel, sch, type, desc ) should have the proper description ok 57 - col_type_is( sch, tab, camel, sch, type, desc ) should have the proper diagnostics ok 58 - col_type_is( sch, tab, camel, sch, type ) should pass ok 59 - col_type_is( sch, tab, camel, sch, type ) should have the proper description ok 60 - col_type_is( sch, tab, camel, sch, type ) should have the proper diagnostics ok 61 - col_type_is( sch, tab, camel, type, desc ) should pass ok 62 - col_type_is( sch, tab, camel, type, desc ) should have the proper description ok 63 - col_type_is( sch, tab, camel, type, desc ) should have the proper diagnostics ok 64 - col_type_is( sch, tab, interval, sch, type, desc ) should pass ok 65 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper description ok 66 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper diagnostics ok 67 - col_type_is( sch, tab, interval, sch, type, desc ) should pass ok 68 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper description ok 69 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper diagnostics ok 70 - col_type_is( sch, tab, inval, type, desc ) should pass ok 71 - col_type_is( sch, tab, inval, type, desc ) should have the proper description ok 72 - col_type_is( sch, tab, inval, type, desc ) should have the proper diagnostics ok 73 - col_type_is( sch, tab, intsec, sch, type, desc ) should pass ok 74 - col_type_is( sch, tab, intsec, sch, type, desc ) should have the proper description ok 75 - col_type_is( sch, tab, intsec, sch, type, desc ) should have the proper diagnostics ok 76 - col_type_is( sch, tab, interval, sch, type, desc ) should pass ok 77 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper description ok 78 - col_type_is( sch, tab, interval, sch, type, desc ) should have the proper diagnostics ok 79 - col_type_is( sch, tab, inval, type, desc ) should pass ok 80 - col_type_is( sch, tab, inval, type, desc ) should have the proper description ok 81 - col_type_is( sch, tab, inval, type, desc ) should have the proper diagnostics ok 82 - col_type_is( sch, tab, stuff, sch, type, desc ) should pass ok 83 - col_type_is( sch, tab, stuff, sch, type, desc ) should have the proper description ok 84 - col_type_is( sch, tab, stuff, sch, type, desc ) should have the proper diagnostics ok 85 - col_type_is( sch, tab, stuff, sch, type, desc ) should pass ok 86 - col_type_is( sch, tab, stuff, sch, type, desc ) should have the proper description ok 87 - col_type_is( sch, tab, stuff, sch, type, desc ) should have the proper diagnostics ok 88 - col_type_is( sch, tab, col, sch, type, desc ) fail should fail ok 89 - col_type_is( sch, tab, col, sch, type, desc ) fail should have the proper description ok 90 - col_type_is( sch, tab, col, sch, type, desc ) fail should have the proper diagnostics ok 91 - col_type_is( sch, tab, col, sch, non-type, desc ) should fail ok 92 - col_type_is( sch, tab, col, sch, non-type, desc ) should have the proper description ok 93 - col_type_is( sch, tab, col, sch, non-type, desc ) should have the proper diagnostics ok 94 - col_type_is( sch, tab, col, non-sch, type, desc ) should fail ok 95 - col_type_is( sch, tab, col, non-sch, type, desc ) should have the proper description ok 96 - col_type_is( sch, tab, col, non-sch, type, desc ) should have the proper diagnostics ok 97 - col_type_is( sch, tab, col, non-sch, type, desc ) should fail ok 98 - col_type_is( sch, tab, col, non-sch, type, desc ) should have the proper description ok 99 - col_type_is( sch, tab, col, non-sch, type, desc ) should have the proper diagnostics ok 100 - col_type_is( sch, tab, col, non-type, desc ) should fail ok 101 - col_type_is( sch, tab, col, non-type, desc ) should have the proper description ok 102 - col_type_is( sch, tab, col, non-type, desc ) should have the proper diagnostics ok 103 - col_type_is( tab, col, non-type, desc ) should fail ok 104 - col_type_is( tab, col, non-type, desc ) should have the proper description ok 105 - col_type_is( tab, col, non-type, desc ) should have the proper diagnostics ok 106 - col_type_is( sch, tab, non-col, sch, type, desc ) should fail ok 107 - col_type_is( sch, tab, non-col, sch, type, desc ) should have the proper description ok 108 - col_type_is( sch, tab, non-col, sch, type, desc ) should have the proper diagnostics ok 109 - col_type_is( sch, tab, col, type, desc ) should pass ok 110 - col_type_is( sch, tab, col, type, desc ) should have the proper description ok 111 - col_type_is( sch, tab, col, type, desc ) should have the proper diagnostics ok 112 - col_type_is( sch, tab, col, type ) should pass ok 113 - col_type_is( sch, tab, col, type ) should have the proper description ok 114 - col_type_is( sch, tab, col, type ) should have the proper diagnostics ok 115 - col_type_is( tab, col, type, desc ) should pass ok 116 - col_type_is( tab, col, type, desc ) should have the proper description ok 117 - col_type_is( tab, col, type, desc ) should have the proper diagnostics ok 118 - col_type_is( tab, col, type ) should pass ok 119 - col_type_is( tab, col, type ) should have the proper description ok 120 - col_type_is( tab, col, type ) should have the proper diagnostics ok 121 - col_type_is( tab, col, type ) fail should fail ok 122 - col_type_is( tab, col, type ) fail should have the proper description ok 123 - col_type_is( tab, col, type ) fail should have the proper diagnostics ok 124 - col_type_is( tab, noncol, type ) fail should fail ok 125 - col_type_is( tab, noncol, type ) fail should have the proper description ok 126 - col_type_is( tab, noncol, type ) fail should have the proper diagnostics ok 127 - col_type_is( sch, tab, noncol, type, desc ) fail should fail ok 128 - col_type_is( sch, tab, noncol, type, desc ) fail should have the proper description ok 129 - col_type_is( sch, tab, noncol, type, desc ) fail should have the proper diagnostics ok 130 - col_type_is with precision should pass ok 131 - col_type_is with precision should have the proper description ok 132 - col_type_is with precision should have the proper diagnostics ok 133 - col_type_is precision fail should fail ok 134 - col_type_is precision fail should have the proper description ok 135 - col_type_is precision fail should have the proper diagnostics ok 136 - col_has_default( sch, tab, col, desc ) should pass ok 137 - col_has_default( sch, tab, col, desc ) should have the proper description ok 138 - col_has_default( sch, tab, col, desc ) should have the proper diagnostics ok 139 - col_has_default( tab, col, desc ) should pass ok 140 - col_has_default( tab, col, desc ) should have the proper description ok 141 - col_has_default( tab, col, desc ) should have the proper diagnostics ok 142 - col_has_default( tab, col ) should pass ok 143 - col_has_default( tab, col ) should have the proper description ok 144 - col_has_default( tab, col ) should have the proper diagnostics ok 145 - col_has_default( sch, tab, col, desc ) should fail ok 146 - col_has_default( sch, tab, col, desc ) should have the proper description ok 147 - col_has_default( sch, tab, col, desc ) should have the proper diagnostics ok 148 - col_has_default( tab, col, desc ) should fail ok 149 - col_has_default( tab, col, desc ) should have the proper description ok 150 - col_has_default( tab, col, desc ) should have the proper diagnostics ok 151 - col_has_default( tab, col ) should fail ok 152 - col_has_default( tab, col ) should have the proper description ok 153 - col_has_default( tab, col ) should have the proper diagnostics ok 154 - col_has_default( sch, tab, col, desc ) should fail ok 155 - col_has_default( sch, tab, col, desc ) should have the proper description ok 156 - col_has_default( sch, tab, col, desc ) should have the proper diagnostics ok 157 - col_has_default( tab, col, desc ) should fail ok 158 - col_has_default( tab, col, desc ) should have the proper description ok 159 - col_has_default( tab, col, desc ) should have the proper diagnostics ok 160 - col_has_default( tab, col ) should fail ok 161 - col_has_default( tab, col ) should have the proper description ok 162 - col_has_default( tab, col ) should have the proper diagnostics ok 163 - col_hasnt_default( sch, tab, col, desc ) should fail ok 164 - col_hasnt_default( sch, tab, col, desc ) should have the proper description ok 165 - col_hasnt_default( sch, tab, col, desc ) should have the proper diagnostics ok 166 - col_hasnt_default( tab, col, desc ) should fail ok 167 - col_hasnt_default( tab, col, desc ) should have the proper description ok 168 - col_hasnt_default( tab, col, desc ) should have the proper diagnostics ok 169 - col_hasnt_default( tab, col ) should fail ok 170 - col_hasnt_default( tab, col ) should have the proper description ok 171 - col_hasnt_default( tab, col ) should have the proper diagnostics ok 172 - col_hasnt_default( sch, tab, col, desc ) should pass ok 173 - col_hasnt_default( sch, tab, col, desc ) should have the proper description ok 174 - col_hasnt_default( sch, tab, col, desc ) should have the proper diagnostics ok 175 - col_hasnt_default( tab, col, desc ) should pass ok 176 - col_hasnt_default( tab, col, desc ) should have the proper description ok 177 - col_hasnt_default( tab, col, desc ) should have the proper diagnostics ok 178 - col_hasnt_default( tab, col ) should pass ok 179 - col_hasnt_default( tab, col ) should have the proper description ok 180 - col_hasnt_default( tab, col ) should have the proper diagnostics ok 181 - col_hasnt_default( sch, tab, col, desc ) should fail ok 182 - col_hasnt_default( sch, tab, col, desc ) should have the proper description ok 183 - col_hasnt_default( sch, tab, col, desc ) should have the proper diagnostics ok 184 - col_hasnt_default( tab, col, desc ) should fail ok 185 - col_hasnt_default( tab, col, desc ) should have the proper description ok 186 - col_hasnt_default( tab, col, desc ) should have the proper diagnostics ok 187 - col_hasnt_default( tab, col ) should fail ok 188 - col_hasnt_default( tab, col ) should have the proper description ok 189 - col_hasnt_default( tab, col ) should have the proper diagnostics ok 190 - col_default_is( sch, tab, col, def, desc ) should pass ok 191 - col_default_is( sch, tab, col, def, desc ) should have the proper description ok 192 - col_default_is( sch, tab, col, def, desc ) should have the proper diagnostics ok 193 - col_default_is() fail should fail ok 194 - col_default_is() fail should have the proper description ok 195 - col_default_is() fail should have the proper diagnostics ok 196 - col_default_is( tab, col, def, desc ) should pass ok 197 - col_default_is( tab, col, def, desc ) should have the proper description ok 198 - col_default_is( tab, col, def, desc ) should have the proper diagnostics ok 199 - col_default_is( tab, col, def ) should pass ok 200 - col_default_is( tab, col, def ) should have the proper description ok 201 - col_default_is( tab, col, def ) should have the proper diagnostics ok 202 - col_default_is( tab, col, int ) should pass ok 203 - col_default_is( tab, col, int ) should have the proper description ok 204 - col_default_is( tab, col, int ) should have the proper diagnostics ok 205 - col_default_is( tab, col, NULL, desc ) should pass ok 206 - col_default_is( tab, col, NULL, desc ) should have the proper description ok 207 - col_default_is( tab, col, NULL, desc ) should have the proper diagnostics ok 208 - col_default_is( tab, col, NULL ) should pass ok 209 - col_default_is( tab, col, NULL ) should have the proper description ok 210 - col_default_is( tab, col, NULL ) should have the proper diagnostics ok 211 - col_default_is( tab, col, bogus, desc ) should fail ok 212 - col_default_is( tab, col, bogus, desc ) should have the proper description ok 213 - col_default_is( tab, col, bogus, desc ) should have the proper diagnostics ok 214 - col_default_is( tab, col, bogus ) should fail ok 215 - col_default_is( tab, col, bogus ) should have the proper description ok 216 - col_default_is( tab, col, bogus ) should have the proper diagnostics ok 217 - col_default_is( tab, col, expression ) should pass ok 218 - col_default_is( tab, col, expression ) should have the proper description ok 219 - col_default_is( tab, col, expression ) should have the proper diagnostics ok 220 - col_default_is( tab, col, expression::text ) should pass ok 221 - col_default_is( tab, col, expression::text ) should have the proper description ok 222 - col_default_is( tab, col, expression::text ) should have the proper diagnostics ok 223 - col_default_is( tab, col, expression, desc ) should pass ok 224 - col_default_is( tab, col, expression, desc ) should have the proper description ok 225 - col_default_is( tab, col, expression, desc ) should have the proper diagnostics ok 226 - col_default_is( tab, col, expression, desc ) should pass ok 227 - col_default_is( tab, col, expression, desc ) should have the proper description ok 228 - col_default_is( tab, col, expression, desc ) should have the proper diagnostics ok 229 - col_default_is( schema, tab, col, expression, desc ) should pass ok 230 - col_default_is( schema, tab, col, expression, desc ) should have the proper description ok 231 - col_default_is( schema, tab, col, expression, desc ) should have the proper diagnostics ok 232 - col_default_is( schema, tab, col, expression, desc ) should pass ok 233 - col_default_is( schema, tab, col, expression, desc ) should have the proper description ok 234 - col_default_is( schema, tab, col, expression, desc ) should have the proper diagnostics ok 235 - col_default_is( sch, tab, col, def, desc ) should fail ok 236 - col_default_is( sch, tab, col, def, desc ) should have the proper description ok 237 - col_default_is( sch, tab, col, def, desc ) should have the proper diagnostics ok 238 - col_default_is( tab, col, def, desc ) should fail ok 239 - col_default_is( tab, col, def, desc ) should have the proper description ok 240 - col_default_is( tab, col, def, desc ) should have the proper diagnostics ok 241 - col_default_is( tab, col, def ) should fail ok 242 - col_default_is( tab, col, def ) should have the proper description ok 243 - col_default_is( tab, col, def ) should have the proper diagnostics ok 244 - col_default_is( tab, col, CURRENT_CATALOG ) should pass ok 245 - col_default_is( tab, col, CURRENT_CATALOG ) should have the proper description ok 246 - col_default_is( tab, col, CURRENT_CATALOG ) should have the proper diagnostics ok 247 - col_default_is( tab, col, CURRENT_ROLE ) should pass ok 248 - col_default_is( tab, col, CURRENT_ROLE ) should have the proper description ok 249 - col_default_is( tab, col, CURRENT_ROLE ) should have the proper diagnostics ok 250 - col_default_is( tab, col, CURRENT_SCHEMA ) should pass ok 251 - col_default_is( tab, col, CURRENT_SCHEMA ) should have the proper description ok 252 - col_default_is( tab, col, CURRENT_SCHEMA ) should have the proper diagnostics ok 253 - col_default_is( tab, col, CURRENT_USER ) should pass ok 254 - col_default_is( tab, col, CURRENT_USER ) should have the proper description ok 255 - col_default_is( tab, col, CURRENT_USER ) should have the proper diagnostics ok 256 - col_default_is( tab, col, SESSION_USER ) should pass ok 257 - col_default_is( tab, col, SESSION_USER ) should have the proper description ok 258 - col_default_is( tab, col, SESSION_USER ) should have the proper diagnostics ok 259 - col_default_is( tab, col, USER ) should pass ok 260 - col_default_is( tab, col, USER ) should have the proper description ok 261 - col_default_is( tab, col, USER ) should have the proper diagnostics ok 262 - col_default_is( tab, col, CURRENT_DATE ) should pass ok 263 - col_default_is( tab, col, CURRENT_DATE ) should have the proper description ok 264 - col_default_is( tab, col, CURRENT_DATE ) should have the proper diagnostics ok 265 - col_default_is( tab, col, CURRENT_TIME ) should pass ok 266 - col_default_is( tab, col, CURRENT_TIME ) should have the proper description ok 267 - col_default_is( tab, col, CURRENT_TIME ) should have the proper diagnostics ok 268 - col_default_is( tab, col, CURRENT_TIMESTAMP ) should pass ok 269 - col_default_is( tab, col, CURRENT_TIMESTAMP ) should have the proper description ok 270 - col_default_is( tab, col, CURRENT_TIMESTAMP ) should have the proper diagnostics ok 271 - col_default_is( tab, col, LOCALTIME ) should pass ok 272 - col_default_is( tab, col, LOCALTIME ) should have the proper description ok 273 - col_default_is( tab, col, LOCALTIME ) should have the proper diagnostics ok 274 - col_default_is( tab, col, LOCALTIMESTAMP ) should pass ok 275 - col_default_is( tab, col, LOCALTIMESTAMP ) should have the proper description ok 276 - col_default_is( tab, col, LOCALTIMESTAMP ) should have the proper diagnostics pgtap-1.3.2/test/expected/create.out000066400000000000000000000000141455775703000174140ustar00rootroot00000000000000\unset ECHO pgtap-1.3.2/test/expected/do_tap.out000066400000000000000000000017551455775703000174340ustar00rootroot00000000000000\unset ECHO 1..29 ok 1 - findfuncs(public, ^test, this) should work ok 2 - findfuncs(public, ^test) should work ok 3 - findfuncs(^test, this) should work ok 4 - findfuncs(^test) should work ok 5 - findfuncs(unknown) should find no tests # public."test ident"() ok 6 - ident ok 7 - ident 2 # public.testplpgsql() ok 8 - plpgsql simple ok 9 - plpgsql simple 2 # public.testthis() ok 10 - simple pass ok 11 - another simple pass # public."test ident"() ok 12 - ident ok 13 - ident 2 # public.testplpgsql() ok 14 - plpgsql simple ok 15 - plpgsql simple 2 # public.testthis() ok 16 - simple pass ok 17 - another simple pass # public."test ident"() ok 18 - ident ok 19 - ident 2 # public.testplpgsql() ok 20 - plpgsql simple ok 21 - plpgsql simple 2 # public.testthis() ok 22 - simple pass ok 23 - another simple pass # public."test ident"() ok 24 - ident ok 25 - ident 2 # public.testplpgsql() ok 26 - plpgsql simple ok 27 - plpgsql simple 2 # public.testthis() ok 28 - simple pass ok 29 - another simple pass pgtap-1.3.2/test/expected/enumtap.out000066400000000000000000000155551455775703000176420ustar00rootroot00000000000000\unset ECHO 1..108 ok 1 - has_type(enum) should pass ok 2 - has_type(enum) should have the proper description ok 3 - has_type(enum) should have the proper diagnostics ok 4 - has_enum(enum) should pass ok 5 - has_enum(enum) should have the proper description ok 6 - has_enum(enum) should have the proper diagnostics ok 7 - has_enum(enum, desc) should pass ok 8 - has_enum(enum, desc) should have the proper description ok 9 - has_enum(enum, desc) should have the proper diagnostics ok 10 - has_enum(scheam, enum) should pass ok 11 - has_enum(scheam, enum) should have the proper description ok 12 - has_enum(scheam, enum) should have the proper diagnostics ok 13 - has_enum(schema, enum, desc) should pass ok 14 - has_enum(schema, enum, desc) should have the proper description ok 15 - has_enum(schema, enum, desc) should have the proper diagnostics ok 16 - has_enum(enum) should fail ok 17 - has_enum(enum) should have the proper description ok 18 - has_enum(enum) should have the proper diagnostics ok 19 - has_enum(enum, desc) should fail ok 20 - has_enum(enum, desc) should have the proper description ok 21 - has_enum(enum, desc) should have the proper diagnostics ok 22 - has_enum(scheam, enum) should fail ok 23 - has_enum(scheam, enum) should have the proper description ok 24 - has_enum(scheam, enum) should have the proper diagnostics ok 25 - has_enum(schema, enum, desc) should fail ok 26 - has_enum(schema, enum, desc) should have the proper description ok 27 - has_enum(schema, enum, desc) should have the proper diagnostics ok 28 - hasnt_enum(enum) should pass ok 29 - hasnt_enum(enum) should have the proper description ok 30 - hasnt_enum(enum) should have the proper diagnostics ok 31 - hasnt_enum(enum, desc) should pass ok 32 - hasnt_enum(enum, desc) should have the proper description ok 33 - hasnt_enum(enum, desc) should have the proper diagnostics ok 34 - hasnt_enum(scheam, enum) should pass ok 35 - hasnt_enum(scheam, enum) should have the proper description ok 36 - hasnt_enum(scheam, enum) should have the proper diagnostics ok 37 - hasnt_enum(schema, enum, desc) should pass ok 38 - hasnt_enum(schema, enum, desc) should have the proper description ok 39 - hasnt_enum(schema, enum, desc) should have the proper diagnostics ok 40 - hasnt_enum(enum) should fail ok 41 - hasnt_enum(enum) should have the proper description ok 42 - hasnt_enum(enum) should have the proper diagnostics ok 43 - hasnt_enum(enum, desc) should fail ok 44 - hasnt_enum(enum, desc) should have the proper description ok 45 - hasnt_enum(enum, desc) should have the proper diagnostics ok 46 - hasnt_enum(scheam, enum) should fail ok 47 - hasnt_enum(scheam, enum) should have the proper description ok 48 - hasnt_enum(scheam, enum) should have the proper diagnostics ok 49 - hasnt_enum(schema, enum, desc) should fail ok 50 - hasnt_enum(schema, enum, desc) should have the proper description ok 51 - hasnt_enum(schema, enum, desc) should have the proper diagnostics ok 52 - enum_has_labels(schema, enum, labels, desc) should pass ok 53 - enum_has_labels(schema, enum, labels, desc) should have the proper description ok 54 - enum_has_labels(schema, enum, labels, desc) should have the proper diagnostics ok 55 - enum_has_labels(schema, enum, labels) should pass ok 56 - enum_has_labels(schema, enum, labels) should have the proper description ok 57 - enum_has_labels(schema, enum, labels) should have the proper diagnostics ok 58 - enum_has_labels(enum, labels, desc) should pass ok 59 - enum_has_labels(enum, labels, desc) should have the proper description ok 60 - enum_has_labels(enum, labels, desc) should have the proper diagnostics ok 61 - enum_has_labels(enum, labels) should pass ok 62 - enum_has_labels(enum, labels) should have the proper description ok 63 - enum_has_labels(enum, labels) should have the proper diagnostics ok 64 - enum_has_labels(schema, enum, labels, desc) fail should fail ok 65 - enum_has_labels(schema, enum, labels, desc) fail should have the proper description ok 66 - enum_has_labels(schema, enum, labels, desc) fail should have the proper diagnostics ok 67 - enum_has_labels(schema, enum, labels, desc) fail should fail ok 68 - enum_has_labels(schema, enum, labels, desc) fail should have the proper description ok 69 - enum_has_labels(schema, enum, labels, desc) fail should have the proper diagnostics ok 70 - enum_has_labels(enum, labels, desc) fail should fail ok 71 - enum_has_labels(enum, labels, desc) fail should have the proper description ok 72 - enum_has_labels(enum, labels, desc) fail should have the proper diagnostics ok 73 - enums_are(schema, enums, desc) should pass ok 74 - enums_are(schema, enums, desc) should have the proper description ok 75 - enums_are(schema, enums, desc) should have the proper diagnostics ok 76 - enums_are(schema, enums) should pass ok 77 - enums_are(schema, enums) should have the proper description ok 78 - enums_are(schema, enums) should have the proper diagnostics ok 79 - enums_are(schema, enums, desc) fail should fail ok 80 - enums_are(schema, enums, desc) fail should have the proper description ok 81 - enums_are(schema, enums, desc) fail should have the proper diagnostics ok 82 - enums_are(schema, enums) fail should fail ok 83 - enums_are(schema, enums) fail should have the proper description ok 84 - enums_are(schema, enums) fail should have the proper diagnostics ok 85 - enums_are(enums, desc) should pass ok 86 - enums_are(enums, desc) should have the proper description ok 87 - enums_are(enums, desc) should have the proper diagnostics ok 88 - enums_are(enums) should pass ok 89 - enums_are(enums) should have the proper description ok 90 - enums_are(enums) should have the proper diagnostics ok 91 - enums_are(enums, desc) fail should fail ok 92 - enums_are(enums, desc) fail should have the proper description ok 93 - enums_are(enums, desc) fail should have the proper diagnostics ok 94 - enums_are(enums) fail should fail ok 95 - enums_are(enums) fail should have the proper description ok 96 - enums_are(enums) fail should have the proper diagnostics ok 97 - enum_has_labels(schema, altered_enum, labels, desc) should pass ok 98 - enum_has_labels(schema, altered_enum, labels, desc) should have the proper description ok 99 - enum_has_labels(schema, altered_enum, labels, desc) should have the proper diagnostics ok 100 - enum_has_labels(schema, altered_enum, labels) should pass ok 101 - enum_has_labels(schema, altered_enum, labels) should have the proper description ok 102 - enum_has_labels(schema, altered_enum, labels) should have the proper diagnostics ok 103 - enum_has_labels(altered_enum, labels, desc) should pass ok 104 - enum_has_labels(altered_enum, labels, desc) should have the proper description ok 105 - enum_has_labels(altered_enum, labels, desc) should have the proper diagnostics ok 106 - enum_has_labels(altered_enum, labels) should pass ok 107 - enum_has_labels(altered_enum, labels) should have the proper description ok 108 - enum_has_labels(altered_enum, labels) should have the proper diagnostics pgtap-1.3.2/test/expected/extension.out000066400000000000000000000112261455775703000201740ustar00rootroot00000000000000\unset ECHO 1..72 ok 1 - extensions_are(sch, exts, desc) should pass ok 2 - extensions_are(sch, exts, desc) should have the proper description ok 3 - extensions_are(sch, exts, desc) should have the proper diagnostics ok 4 - extensions_are(sch, exts) should pass ok 5 - extensions_are(sch, exts) should have the proper description ok 6 - extensions_are(sch, exts) should have the proper diagnostics ok 7 - extensions_are(exts, desc) should pass ok 8 - extensions_are(exts, desc) should have the proper description ok 9 - extensions_are(exts, desc) should have the proper diagnostics ok 10 - extensions_are(exts) should pass ok 11 - extensions_are(exts) should have the proper description ok 12 - extensions_are(exts) should have the proper diagnostics ok 13 - extensions_are(ci_schema, exts, desc) should pass ok 14 - extensions_are(ci_schema, exts, desc) should have the proper description ok 15 - extensions_are(ci_schema, exts, desc) should have the proper diagnostics ok 16 - extensions_are(non-sch, exts) should pass ok 17 - extensions_are(non-sch, exts) should have the proper description ok 18 - extensions_are(non-sch, exts) should have the proper diagnostics ok 19 - extensions_are(sch, good/bad, desc) should fail ok 20 - extensions_are(sch, good/bad, desc) should have the proper description ok 21 - extensions_are(sch, good/bad, desc) should have the proper diagnostics ok 22 - extensions_are(someexts) should fail ok 23 - extensions_are(someexts) should have the proper description ok 24 - extensions_are(someexts) should have the proper diagnostics ok 25 - has_extension( schema, name, desc ) should pass ok 26 - has_extension( schema, name, desc ) should have the proper description ok 27 - has_extension( schema, name, desc ) should have the proper diagnostics ok 28 - has_extension( schema, name ) should pass ok 29 - has_extension( schema, name ) should have the proper description ok 30 - has_extension( schema, name ) should have the proper diagnostics ok 31 - has_extension( name, desc ) should pass ok 32 - has_extension( name, desc ) should have the proper description ok 33 - has_extension( name, desc ) should have the proper diagnostics ok 34 - has_extension( name ) should pass ok 35 - has_extension( name ) should have the proper description ok 36 - has_extension( name ) should have the proper diagnostics ok 37 - has_extension( schema, name, desc ) fail should fail ok 38 - has_extension( schema, name, desc ) fail should have the proper description ok 39 - has_extension( schema, name, desc ) fail should have the proper diagnostics ok 40 - has_extension( schema, name ) fail should fail ok 41 - has_extension( schema, name ) fail should have the proper description ok 42 - has_extension( schema, name ) fail should have the proper diagnostics ok 43 - has_extension( name, desc ) fail should fail ok 44 - has_extension( name, desc ) fail should have the proper description ok 45 - has_extension( name, desc ) fail should have the proper diagnostics ok 46 - has_extension( name ) fail should fail ok 47 - has_extension( name ) fail should have the proper description ok 48 - has_extension( name ) fail should have the proper diagnostics ok 49 - hasnt_extension( schema, name, desc ) should pass ok 50 - hasnt_extension( schema, name, desc ) should have the proper description ok 51 - hasnt_extension( schema, name, desc ) should have the proper diagnostics ok 52 - hasnt_extension( schema, name ) should pass ok 53 - hasnt_extension( schema, name ) should have the proper description ok 54 - hasnt_extension( schema, name ) should have the proper diagnostics ok 55 - hasnt_extension( name, desc ) should pass ok 56 - hasnt_extension( name, desc ) should have the proper description ok 57 - hasnt_extension( name, desc ) should have the proper diagnostics ok 58 - hasnt_extension( name ) should pass ok 59 - hasnt_extension( name ) should have the proper description ok 60 - hasnt_extension( name ) should have the proper diagnostics ok 61 - hasnt_extension( schema, name, desc ) should fail ok 62 - hasnt_extension( schema, name, desc ) should have the proper description ok 63 - hasnt_extension( schema, name, desc ) should have the proper diagnostics ok 64 - hasnt_extension( schema, name ) should fail ok 65 - hasnt_extension( schema, name ) should have the proper description ok 66 - hasnt_extension( schema, name ) should have the proper diagnostics ok 67 - hasnt_extension( name, desc ) should fail ok 68 - hasnt_extension( name, desc ) should have the proper description ok 69 - hasnt_extension( name, desc ) should have the proper diagnostics ok 70 - hasnt_extension( name ) should fail ok 71 - hasnt_extension( name ) should have the proper description ok 72 - hasnt_extension( name ) should have the proper diagnostics pgtap-1.3.2/test/expected/fktap.out000066400000000000000000000203371455775703000172700ustar00rootroot00000000000000\unset ECHO 1..134 ok 1 - has_fk( schema, table, description ) should pass ok 2 - has_fk( schema, table, description ) should have the proper description ok 3 - has_fk( table, description ) should pass ok 4 - has_fk( table, description ) should have the proper description ok 5 - has_fk( table4, description ) should pass ok 6 - has_fk( table4, description ) should have the proper description ok 7 - has_fk( schema, table4, description ) should pass ok 8 - has_fk( schema, table4, description ) should have the proper description ok 9 - has_fk( table ) should pass ok 10 - has_fk( table ) should have the proper description ok 11 - has_fk( schema, table, description ) fail should fail ok 12 - has_fk( schema, table, description ) fail should have the proper description ok 13 - has_fk( table, description ) fail should fail ok 14 - has_fk( table, description ) fail should have the proper description ok 15 - hasnt_fk( schema, table, description ) should fail ok 16 - hasnt_fk( schema, table, description ) should have the proper description ok 17 - hasnt_fk( table, description ) should fail ok 18 - hasnt_fk( table, description ) should have the proper description ok 19 - hasnt_fk( table ) should fail ok 20 - hasnt_fk( table ) should have the proper description ok 21 - hasnt_fk( schema, table, description ) pass should pass ok 22 - hasnt_fk( schema, table, description ) pass should have the proper description ok 23 - hasnt_fk( table, description ) pass should pass ok 24 - hasnt_fk( table, description ) pass should have the proper description ok 25 - col_is_fk( schema, table, column, description ) should pass ok 26 - col_is_fk( schema, table, column, description ) should have the proper description ok 27 - col_is_fk( table, column, description ) should pass ok 28 - col_is_fk( table, column, description ) should have the proper description ok 29 - col_is_fk( table, column ) should pass ok 30 - col_is_fk( table, column ) should have the proper description ok 31 - col_is_fk( schema, table, column, description ) should fail ok 32 - col_is_fk( schema, table, column, description ) should have the proper description ok 33 - col_is_fk( schema, table, column, description ) should have the proper diagnostics ok 34 - col_is_fk( table, column, description ) should fail ok 35 - col_is_fk( table, column, description ) should have the proper description ok 36 - col_is_fk( table, column, description ) should have the proper diagnostics ok 37 - multi-fk col_is_fk test should pass ok 38 - multi-fk col_is_fk test should have the proper description ok 39 - col_is_fk with no FKs should fail ok 40 - col_is_fk with no FKs should have the proper description ok 41 - col_is_fk with no FKs should have the proper diagnostics ok 42 - col_is_fk with no FKs should fail ok 43 - col_is_fk with no FKs should have the proper description ok 44 - col_is_fk with no FKs should have the proper diagnostics ok 45 - col_is_fk( schema, table, column[], description ) should pass ok 46 - col_is_fk( schema, table, column[], description ) should have the proper description ok 47 - col_is_fk( table, column[], description ) should pass ok 48 - col_is_fk( table, column[], description ) should have the proper description ok 49 - col_is_fk( table, column[] ) should pass ok 50 - col_is_fk( table, column[] ) should have the proper description ok 51 - col_isnt_fk( schema, table, column, description ) should fail ok 52 - col_isnt_fk( schema, table, column, description ) should have the proper description ok 53 - col_isnt_fk( schema, table, column, description ) should have the proper diagnostics ok 54 - col_isnt_fk( table, column, description ) should fail ok 55 - col_isnt_fk( table, column, description ) should have the proper description ok 56 - col_isnt_fk( table, column, description ) should have the proper diagnostics ok 57 - col_isnt_fk( table, column ) should fail ok 58 - col_isnt_fk( table, column ) should have the proper description ok 59 - col_isnt_fk( table, column ) should have the proper diagnostics ok 60 - col_isnt_fk( schema, table, column, description ) should pass ok 61 - col_isnt_fk( schema, table, column, description ) should have the proper description ok 62 - col_isnt_fk( schema, table, column, description ) should have the proper diagnostics ok 63 - col_isnt_fk( table, column, description ) should pass ok 64 - col_isnt_fk( table, column, description ) should have the proper description ok 65 - col_isnt_fk( table, column, description ) should have the proper diagnostics ok 66 - multi-fk col_isnt_fk test should fail ok 67 - multi-fk col_isnt_fk test should have the proper description ok 68 - multi-fk col_isnt_fk test should have the proper diagnostics ok 69 - col_isnt_fk with no FKs should pass ok 70 - col_isnt_fk with no FKs should have the proper description ok 71 - col_isnt_fk with no FKs should have the proper diagnostics ok 72 - col_isnt_fk with no FKs should pass ok 73 - col_isnt_fk with no FKs should have the proper description ok 74 - col_isnt_fk with no FKs should have the proper diagnostics ok 75 - col_isnt_fk( schema, table, column[], description ) should fail ok 76 - col_isnt_fk( schema, table, column[], description ) should have the proper description ok 77 - col_isnt_fk( table, column[], description ) should fail ok 78 - col_isnt_fk( table, column[], description ) should have the proper description ok 79 - col_isnt_fk( table, column[] ) should fail ok 80 - col_isnt_fk( table, column[] ) should have the proper description ok 81 - full fk_ok array should pass ok 82 - full fk_ok array should have the proper description ok 83 - pg_my_temp_schema() should pass ok 84 - pg_my_temp_schema() should have the proper description ok 85 - multiple fk fk_ok desc should pass ok 86 - multiple fk fk_ok desc should have the proper description ok 87 - fk_ok array desc should pass ok 88 - fk_ok array desc should have the proper description ok 89 - fk_ok array noschema desc should pass ok 90 - fk_ok array noschema desc should have the proper description ok 91 - multiple fk fk_ok noschema desc should pass ok 92 - multiple fk fk_ok noschema desc should have the proper description ok 93 - fk_ok array noschema should pass ok 94 - fk_ok array noschema should have the proper description ok 95 - basic fk_ok should pass ok 96 - basic fk_ok should have the proper description ok 97 - basic fk_ok desc should pass ok 98 - basic fk_ok desc should have the proper description ok 99 - basic fk_ok noschema should pass ok 100 - basic fk_ok noschema should have the proper description ok 101 - basic fk_ok noschema desc should pass ok 102 - basic fk_ok noschema desc should have the proper description ok 103 - basic fk_ok noschema desc should have the proper diagnostics ok 104 - Test should pass ok 105 - fk_ok fail should fail ok 106 - fk_ok fail should have the proper description ok 107 - fk_ok fail should have the proper diagnostics ok 108 - fk_ok fail desc should fail ok 109 - fk_ok fail desc should have the proper description ok 110 - fk_ok fail desc should have the proper diagnostics ok 111 - fk_ok fail no schema should fail ok 112 - fk_ok fail no schema should have the proper description ok 113 - fk_ok fail no schema should have the proper diagnostics ok 114 - fk_ok fail no schema desc should fail ok 115 - fk_ok fail no schema desc should have the proper description ok 116 - fk_ok fail no schema desc should have the proper diagnostics ok 117 - fk_ok bad PK test should fail ok 118 - fk_ok bad PK test should have the proper description ok 119 - fk_ok bad PK test should have the proper diagnostics ok 120 - double fk schema test should pass ok 121 - double fk schema test should have the proper description ok 122 - double fk schema test should have the proper diagnostics ok 123 - double fk test should pass ok 124 - double fk test should have the proper description ok 125 - double fk test should have the proper diagnostics ok 126 - double fk and col schema test should pass ok 127 - double fk and col schema test should have the proper description ok 128 - double fk and col schema test should have the proper diagnostics ok 129 - missing fk test should fail ok 130 - missing fk test should have the proper description ok 131 - missing fk test should have the proper diagnostics ok 132 - bad FK column test should fail ok 133 - bad FK column test should have the proper description ok 134 - bad FK column test should have the proper diagnostics pgtap-1.3.2/test/expected/functap.out000066400000000000000000002251651455775703000176310ustar00rootroot00000000000000\unset ECHO 1..1105 ok 1 - simple function should pass ok 2 - simple function should have the proper description ok 3 - simple function should have the proper diagnostics ok 4 - simple schema.function should pass ok 5 - simple schema.function should have the proper description ok 6 - simple schema.function should have the proper diagnostics ok 7 - simple function desc should pass ok 8 - simple function desc should have the proper description ok 9 - simple function desc should have the proper diagnostics ok 10 - simple with 0 args should pass ok 11 - simple with 0 args should have the proper description ok 12 - simple with 0 args should have the proper diagnostics ok 13 - simple with 0 args desc should pass ok 14 - simple with 0 args desc should have the proper description ok 15 - simple with 0 args desc should have the proper diagnostics ok 16 - simple schema.func with 0 args should pass ok 17 - simple schema.func with 0 args should have the proper description ok 18 - simple schema.func with 0 args should have the proper diagnostics ok 19 - simple schema.func with desc should pass ok 20 - simple schema.func with desc should have the proper description ok 21 - simple schema.func with desc should have the proper diagnostics ok 22 - simple schema.func with 0 args, desc should pass ok 23 - simple schema.func with 0 args, desc should have the proper description ok 24 - simple schema.func with 0 args, desc should have the proper diagnostics ok 25 - simple function with 1 arg should pass ok 26 - simple function with 1 arg should have the proper description ok 27 - simple function with 1 arg should have the proper diagnostics ok 28 - simple function with 2 args should pass ok 29 - simple function with 2 args should have the proper description ok 30 - simple function with 2 args should have the proper diagnostics ok 31 - simple array function should pass ok 32 - simple array function should have the proper description ok 33 - simple array function should have the proper diagnostics ok 34 - custom array function should pass ok 35 - custom array function should have the proper description ok 36 - custom array function should have the proper diagnostics ok 37 - custom numeric function should pass ok 38 - custom numeric function should have the proper description ok 39 - custom numeric function should have the proper diagnostics ok 40 - custom unqualified function with intword unqualified argument should pass ok 41 - custom unqualified function with intword unqualified argument should have the proper description ok 42 - custom unqualified function with intword unqualified argument should have the proper diagnostics ok 43 - custom unqualified function with intword qualified argument should pass ok 44 - custom unqualified function with intword qualified argument should have the proper description ok 45 - custom unqualified function with intword qualified argument should have the proper diagnostics ok 46 - custom qualified function with intword unqualified argument should pass ok 47 - custom qualified function with intword unqualified argument should have the proper description ok 48 - custom qualified function with intword unqualified argument should have the proper diagnostics ok 49 - custom qualified function with intword qualified argument should pass ok 50 - custom qualified function with intword qualified argument should have the proper description ok 51 - custom qualified function with intword qualified argument should have the proper diagnostics ok 52 - failure output should fail ok 53 - failure output should have the proper description ok 54 - failure output should have the proper diagnostics ok 55 - public procedure should pass ok 56 - public procedure should have the proper description ok 57 - public procedure should have the proper diagnostics ok 58 - public procedure should pass ok 59 - public procedure should have the proper description ok 60 - public procedure should have the proper diagnostics ok 61 - simple function should fail ok 62 - simple function should have the proper description ok 63 - simple function should have the proper diagnostics ok 64 - simple schema.function should fail ok 65 - simple schema.function should have the proper description ok 66 - simple schema.function should have the proper diagnostics ok 67 - simple function desc should fail ok 68 - simple function desc should have the proper description ok 69 - simple function desc should have the proper diagnostics ok 70 - simple with 0 args should fail ok 71 - simple with 0 args should have the proper description ok 72 - simple with 0 args should have the proper diagnostics ok 73 - simple with 0 args desc should fail ok 74 - simple with 0 args desc should have the proper description ok 75 - simple with 0 args desc should have the proper diagnostics ok 76 - simple schema.func with 0 args should fail ok 77 - simple schema.func with 0 args should have the proper description ok 78 - simple schema.func with 0 args should have the proper diagnostics ok 79 - simple schema.func with desc should fail ok 80 - simple schema.func with desc should have the proper description ok 81 - simple schema.func with desc should have the proper diagnostics ok 82 - simple schema.func with 0 args, desc should fail ok 83 - simple schema.func with 0 args, desc should have the proper description ok 84 - simple schema.func with 0 args, desc should have the proper diagnostics ok 85 - simple function with 1 arg should fail ok 86 - simple function with 1 arg should have the proper description ok 87 - simple function with 1 arg should have the proper diagnostics ok 88 - simple function with 2 args should fail ok 89 - simple function with 2 args should have the proper description ok 90 - simple function with 2 args should have the proper diagnostics ok 91 - simple array function should fail ok 92 - simple array function should have the proper description ok 93 - simple array function should have the proper diagnostics ok 94 - custom array function should fail ok 95 - custom array function should have the proper description ok 96 - custom array function should have the proper diagnostics ok 97 - custom numeric function should fail ok 98 - custom numeric function should have the proper description ok 99 - custom numeric function should have the proper diagnostics ok 100 - public procedure should fail ok 101 - public procedure should have the proper description ok 102 - public procedure should have the proper diagnostics ok 103 - public procedure should fail ok 104 - public procedure should have the proper description ok 105 - public procedure should have the proper diagnostics ok 106 - can(schema) with desc should pass ok 107 - can(schema) with desc should have the proper description ok 108 - can(schema) with desc should have the proper diagnostics ok 109 - can(schema) should pass ok 110 - can(schema) should have the proper description ok 111 - can(schema) should have the proper diagnostics ok 112 - fail can(schema) with desc should fail ok 113 - fail can(schema) with desc should have the proper description ok 114 - fail can(schema) with desc should have the proper diagnostics ok 115 - fail can(someschema) with desc should fail ok 116 - fail can(someschema) with desc should have the proper description ok 117 - fail can(someschema) with desc should have the proper diagnostics ok 118 - can() with desc should pass ok 119 - can() with desc should have the proper description ok 120 - can() with desc should have the proper diagnostics ok 121 - can(schema) should pass ok 122 - can(schema) should have the proper description ok 123 - can(schema) should have the proper diagnostics ok 124 - fail can() with desc should fail ok 125 - fail can() with desc should have the proper description ok 126 - fail can() with desc should have the proper diagnostics ok 127 - can(sch, proc) with desc should pass ok 128 - can(sch, proc) with desc should have the proper description ok 129 - can(sch, proc) with desc should have the proper diagnostics ok 130 - can(proc) with desc should pass ok 131 - can(proc) with desc should have the proper description ok 132 - can(proc) with desc should have the proper diagnostics ok 133 - function_lang_is(schema, func, 0 args, sql, desc) should pass ok 134 - function_lang_is(schema, func, 0 args, sql, desc) should have the proper description ok 135 - function_lang_is(schema, func, 0 args, sql, desc) should have the proper diagnostics ok 136 - function_lang_is(schema, func, 0 args, sql) should pass ok 137 - function_lang_is(schema, func, 0 args, sql) should have the proper description ok 138 - function_lang_is(schema, func, 0 args, sql) should have the proper diagnostics ok 139 - function_lang_is(schema, func, args, plpgsql, desc) should pass ok 140 - function_lang_is(schema, func, args, plpgsql, desc) should have the proper description ok 141 - function_lang_is(schema, func, args, plpgsql, desc) should have the proper diagnostics ok 142 - function_lang_is(schema, func, args, plpgsql) should pass ok 143 - function_lang_is(schema, func, args, plpgsql) should have the proper description ok 144 - function_lang_is(schema, func, args, plpgsql) should have the proper diagnostics ok 145 - function_lang_is(schema, func, 0 args, perl, desc) should fail ok 146 - function_lang_is(schema, func, 0 args, perl, desc) should have the proper description ok 147 - function_lang_is(schema, func, 0 args, perl, desc) should have the proper diagnostics ok 148 - function_lang_is(schema, non-func, 0 args, sql, desc) should fail ok 149 - function_lang_is(schema, non-func, 0 args, sql, desc) should have the proper description ok 150 - function_lang_is(schema, non-func, 0 args, sql, desc) should have the proper diagnostics ok 151 - function_lang_is(schema, func, args, plpgsql) should fail ok 152 - function_lang_is(schema, func, args, plpgsql) should have the proper description ok 153 - function_lang_is(schema, func, args, plpgsql) should have the proper diagnostics ok 154 - function_lang_is(schema, func, sql, desc) should pass ok 155 - function_lang_is(schema, func, sql, desc) should have the proper description ok 156 - function_lang_is(schema, func, sql, desc) should have the proper diagnostics ok 157 - function_lang_is(schema, func, sql) should pass ok 158 - function_lang_is(schema, func, sql) should have the proper description ok 159 - function_lang_is(schema, func, sql) should have the proper diagnostics ok 160 - function_lang_is(schema, func, perl, desc) should fail ok 161 - function_lang_is(schema, func, perl, desc) should have the proper description ok 162 - function_lang_is(schema, func, perl, desc) should have the proper diagnostics ok 163 - function_lang_is(schema, non-func, sql, desc) should fail ok 164 - function_lang_is(schema, non-func, sql, desc) should have the proper description ok 165 - function_lang_is(schema, non-func, sql, desc) should have the proper diagnostics ok 166 - function_lang_is(func, 0 args, sql, desc) should pass ok 167 - function_lang_is(func, 0 args, sql, desc) should have the proper description ok 168 - function_lang_is(func, 0 args, sql, desc) should have the proper diagnostics ok 169 - function_lang_is(func, 0 args, sql) should pass ok 170 - function_lang_is(func, 0 args, sql) should have the proper description ok 171 - function_lang_is(func, 0 args, sql) should have the proper diagnostics ok 172 - function_lang_is(func, args, plpgsql, desc) should pass ok 173 - function_lang_is(func, args, plpgsql, desc) should have the proper description ok 174 - function_lang_is(func, args, plpgsql, desc) should have the proper diagnostics ok 175 - function_lang_is(func, args, plpgsql) should pass ok 176 - function_lang_is(func, args, plpgsql) should have the proper description ok 177 - function_lang_is(func, args, plpgsql) should have the proper diagnostics ok 178 - function_lang_is(func, 0 args, perl, desc) should fail ok 179 - function_lang_is(func, 0 args, perl, desc) should have the proper description ok 180 - function_lang_is(func, 0 args, perl, desc) should have the proper diagnostics ok 181 - function_lang_is(non-func, 0 args, sql, desc) should fail ok 182 - function_lang_is(non-func, 0 args, sql, desc) should have the proper description ok 183 - function_lang_is(non-func, 0 args, sql, desc) should have the proper diagnostics ok 184 - function_lang_is(func, args, plpgsql) should fail ok 185 - function_lang_is(func, args, plpgsql) should have the proper description ok 186 - function_lang_is(func, args, plpgsql) should have the proper diagnostics ok 187 - function_lang_is(func, sql, desc) should pass ok 188 - function_lang_is(func, sql, desc) should have the proper description ok 189 - function_lang_is(func, sql, desc) should have the proper diagnostics ok 190 - function_lang_is(func, sql) should pass ok 191 - function_lang_is(func, sql) should have the proper description ok 192 - function_lang_is(func, sql) should have the proper diagnostics ok 193 - function_lang_is(func, perl, desc) should fail ok 194 - function_lang_is(func, perl, desc) should have the proper description ok 195 - function_lang_is(func, perl, desc) should have the proper diagnostics ok 196 - function_lang_is(non-func, sql, desc) should fail ok 197 - function_lang_is(non-func, sql, desc) should have the proper description ok 198 - function_lang_is(non-func, sql, desc) should have the proper diagnostics ok 199 - function_lang_is(schema, proc, desc) should pass ok 200 - function_lang_is(schema, proc, desc) should have the proper description ok 201 - function_lang_is(schema, proc, desc) should have the proper diagnostics ok 202 - function_lang_is(schema, proc, desc) should pass ok 203 - function_lang_is(schema, proc, desc) should have the proper description ok 204 - function_lang_is(schema, proc, desc) should have the proper diagnostics ok 205 - function_returns(schema, func, 0 args, bool, desc) should pass ok 206 - function_returns(schema, func, 0 args, bool, desc) should have the proper description ok 207 - function_returns(schema, func, 0 args, bool, desc) should have the proper diagnostics ok 208 - function_returns(schema, func, 0 args, bool) should pass ok 209 - function_returns(schema, func, 0 args, bool) should have the proper description ok 210 - function_returns(schema, func, 0 args, bool) should have the proper diagnostics ok 211 - function_returns(schema, func, args, bool, false) should pass ok 212 - function_returns(schema, func, args, bool, false) should have the proper description ok 213 - function_returns(schema, func, args, bool, false) should have the proper diagnostics ok 214 - function_returns(schema, func, args, bool) should pass ok 215 - function_returns(schema, func, args, bool) should have the proper description ok 216 - function_returns(schema, func, args, bool) should have the proper diagnostics ok 217 - function_returns(schema, func, 0 args, setof bool, desc) should pass ok 218 - function_returns(schema, func, 0 args, setof bool, desc) should have the proper description ok 219 - function_returns(schema, func, 0 args, setof bool, desc) should have the proper diagnostics ok 220 - function_returns(schema, func, 0 args, setof bool) should pass ok 221 - function_returns(schema, func, 0 args, setof bool) should have the proper description ok 222 - function_returns(schema, func, 0 args, setof bool) should have the proper diagnostics ok 223 - function_returns(schema, func, bool, desc) should pass ok 224 - function_returns(schema, func, bool, desc) should have the proper description ok 225 - function_returns(schema, func, bool, desc) should have the proper diagnostics ok 226 - function_returns(schema, func, bool) should pass ok 227 - function_returns(schema, func, bool) should have the proper description ok 228 - function_returns(schema, func, bool) should have the proper diagnostics ok 229 - function_returns(schema, other func, bool, false) should pass ok 230 - function_returns(schema, other func, bool, false) should have the proper description ok 231 - function_returns(schema, other func, bool, false) should have the proper diagnostics ok 232 - function_returns(schema, other func, bool) should pass ok 233 - function_returns(schema, other func, bool) should have the proper description ok 234 - function_returns(schema, other func, bool) should have the proper diagnostics ok 235 - function_returns(schema, func, setof bool, desc) should pass ok 236 - function_returns(schema, func, setof bool, desc) should have the proper description ok 237 - function_returns(schema, func, setof bool, desc) should have the proper diagnostics ok 238 - function_returns(schema, func, setof bool) should pass ok 239 - function_returns(schema, func, setof bool) should have the proper description ok 240 - function_returns(schema, func, setof bool) should have the proper diagnostics ok 241 - function_returns(func, 0 args, bool, desc) should pass ok 242 - function_returns(func, 0 args, bool, desc) should have the proper description ok 243 - function_returns(func, 0 args, bool, desc) should have the proper diagnostics ok 244 - function_returns(func, 0 args, bool) should pass ok 245 - function_returns(func, 0 args, bool) should have the proper description ok 246 - function_returns(func, 0 args, bool) should have the proper diagnostics ok 247 - function_returns(func, args, bool, false) should pass ok 248 - function_returns(func, args, bool, false) should have the proper description ok 249 - function_returns(func, args, bool, false) should have the proper diagnostics ok 250 - function_returns(func, args, bool) should pass ok 251 - function_returns(func, args, bool) should have the proper description ok 252 - function_returns(func, args, bool) should have the proper diagnostics ok 253 - function_returns(func, 0 args, setof bool, desc) should pass ok 254 - function_returns(func, 0 args, setof bool, desc) should have the proper description ok 255 - function_returns(func, 0 args, setof bool, desc) should have the proper diagnostics ok 256 - function_returns(func, 0 args, setof bool) should pass ok 257 - function_returns(func, 0 args, setof bool) should have the proper description ok 258 - function_returns(func, 0 args, setof bool) should have the proper diagnostics ok 259 - function_returns(func, bool, desc) should pass ok 260 - function_returns(func, bool, desc) should have the proper description ok 261 - function_returns(func, bool, desc) should have the proper diagnostics ok 262 - function_returns(func, bool) should pass ok 263 - function_returns(func, bool) should have the proper description ok 264 - function_returns(func, bool) should have the proper diagnostics ok 265 - function_returns(other func, bool, false) should pass ok 266 - function_returns(other func, bool, false) should have the proper description ok 267 - function_returns(other func, bool, false) should have the proper diagnostics ok 268 - function_returns(other func, bool) should pass ok 269 - function_returns(other func, bool) should have the proper description ok 270 - function_returns(other func, bool) should have the proper diagnostics ok 271 - function_returns(func, setof bool, desc) should pass ok 272 - function_returns(func, setof bool, desc) should have the proper description ok 273 - function_returns(func, setof bool, desc) should have the proper diagnostics ok 274 - function_returns(func, setof bool) should pass ok 275 - function_returns(func, setof bool) should have the proper description ok 276 - function_returns(func, setof bool) should have the proper diagnostics ok 277 - function_returns(sch, proc, void) should pass ok 278 - function_returns(sch, proc, void) should have the proper description ok 279 - function_returns(sch, proc, void) should have the proper diagnostics ok 280 - function_returns(sch, proc, void) should pass ok 281 - function_returns(sch, proc, void) should have the proper description ok 282 - function_returns(sch, proc, void) should have the proper diagnostics ok 283 - is_definer(schema, func, 0 args, desc) should pass ok 284 - is_definer(schema, func, 0 args, desc) should have the proper description ok 285 - is_definer(schema, func, 0 args, desc) should have the proper diagnostics ok 286 - isnt_definer(schema, func, 0 args, desc) should fail ok 287 - isnt_definer(schema, func, 0 args, desc) should have the proper description ok 288 - isnt_definer(schema, func, 0 args, desc) should have the proper diagnostics ok 289 - is_definer(schema, func, 0 args) should pass ok 290 - is_definer(schema, func, 0 args) should have the proper description ok 291 - is_definer(schema, func, 0 args) should have the proper diagnostics ok 292 - isnt_definer(schema, func, 0 args) should fail ok 293 - isnt_definer(schema, func, 0 args) should have the proper description ok 294 - isnt_definer(schema, func, 0 args) should have the proper diagnostics ok 295 - is_definer(schema, func, args, desc) should fail ok 296 - is_definer(schema, func, args, desc) should have the proper description ok 297 - is_definer(schema, func, args, desc) should have the proper diagnostics ok 298 - isnt_definer(schema, func, args, desc) should pass ok 299 - isnt_definer(schema, func, args, desc) should have the proper description ok 300 - isnt_definer(schema, func, args, desc) should have the proper diagnostics ok 301 - is_definer(schema, func, args) should fail ok 302 - is_definer(schema, func, args) should have the proper description ok 303 - is_definer(schema, func, args) should have the proper diagnostics ok 304 - isnt_definer(schema, func, args) should pass ok 305 - isnt_definer(schema, func, args) should have the proper description ok 306 - isnt_definer(schema, func, args) should have the proper diagnostics ok 307 - is_definer(schema, func, desc) should pass ok 308 - is_definer(schema, func, desc) should have the proper description ok 309 - is_definer(schema, func, desc) should have the proper diagnostics ok 310 - isnt_definer(schema, func, desc) should fail ok 311 - isnt_definer(schema, func, desc) should have the proper description ok 312 - isnt_definer(schema, func, desc) should have the proper diagnostics ok 313 - is_definer(schema, func) should pass ok 314 - is_definer(schema, func) should have the proper description ok 315 - is_definer(schema, func) should have the proper diagnostics ok 316 - isnt_definer(schema, func) should fail ok 317 - isnt_definer(schema, func) should have the proper description ok 318 - isnt_definer(schema, func) should have the proper diagnostics ok 319 - is_definer(schema, func, 0 args, desc) should pass ok 320 - is_definer(schema, func, 0 args, desc) should have the proper description ok 321 - is_definer(schema, func, 0 args, desc) should have the proper diagnostics ok 322 - isnt_definer(schema, func, 0 args, desc) should fail ok 323 - isnt_definer(schema, func, 0 args, desc) should have the proper description ok 324 - isnt_definer(schema, func, 0 args, desc) should have the proper diagnostics ok 325 - is_definer(schema, func, 0 args) should pass ok 326 - is_definer(schema, func, 0 args) should have the proper description ok 327 - is_definer(schema, func, 0 args) should have the proper diagnostics ok 328 - isnt_definer(schema, func, 0 args) should fail ok 329 - isnt_definer(schema, func, 0 args) should have the proper description ok 330 - isnt_definer(schema, func, 0 args) should have the proper diagnostics ok 331 - is_definer(schema, func, args, desc) should fail ok 332 - is_definer(schema, func, args, desc) should have the proper description ok 333 - is_definer(schema, func, args, desc) should have the proper diagnostics ok 334 - isnt_definer(schema, func, args, desc) should pass ok 335 - isnt_definer(schema, func, args, desc) should have the proper description ok 336 - isnt_definer(schema, func, args, desc) should have the proper diagnostics ok 337 - is_definer(schema, func, args) should fail ok 338 - is_definer(schema, func, args) should have the proper description ok 339 - is_definer(schema, func, args) should have the proper diagnostics ok 340 - isnt_definer(schema, func, args) should pass ok 341 - isnt_definer(schema, func, args) should have the proper description ok 342 - isnt_definer(schema, func, args) should have the proper diagnostics ok 343 - is_definer(schema, func, desc) should pass ok 344 - is_definer(schema, func, desc) should have the proper description ok 345 - is_definer(schema, func, desc) should have the proper diagnostics ok 346 - isnt_definer(schema, func, desc) should fail ok 347 - isnt_definer(schema, func, desc) should have the proper description ok 348 - isnt_definer(schema, func, desc) should have the proper diagnostics ok 349 - is_definer(schema, func) should pass ok 350 - is_definer(schema, func) should have the proper description ok 351 - is_definer(schema, func) should have the proper diagnostics ok 352 - isnt_definer(schema, func) should fail ok 353 - isnt_definer(schema, func) should have the proper description ok 354 - isnt_definer(schema, func) should have the proper diagnostics ok 355 - is_definer(func, 0 args, desc) should pass ok 356 - is_definer(func, 0 args, desc) should have the proper description ok 357 - is_definer(func, 0 args, desc) should have the proper diagnostics ok 358 - isnt_definer(func, 0 args, desc) should fail ok 359 - isnt_definer(func, 0 args, desc) should have the proper description ok 360 - isnt_definer(func, 0 args, desc) should have the proper diagnostics ok 361 - is_definer(func, 0 args) should pass ok 362 - is_definer(func, 0 args) should have the proper description ok 363 - is_definer(func, 0 args) should have the proper diagnostics ok 364 - isnt_definer(func, 0 args) should fail ok 365 - isnt_definer(func, 0 args) should have the proper description ok 366 - isnt_definer(func, 0 args) should have the proper diagnostics ok 367 - is_definer(func, args, desc) should fail ok 368 - is_definer(func, args, desc) should have the proper description ok 369 - is_definer(func, args, desc) should have the proper diagnostics ok 370 - isnt_definer(func, args, desc) should pass ok 371 - isnt_definer(func, args, desc) should have the proper description ok 372 - isnt_definer(func, args, desc) should have the proper diagnostics ok 373 - is_definer(func, args) should fail ok 374 - is_definer(func, args) should have the proper description ok 375 - is_definer(func, args) should have the proper diagnostics ok 376 - isnt_definer(func, args) should pass ok 377 - isnt_definer(func, args) should have the proper description ok 378 - isnt_definer(func, args) should have the proper diagnostics ok 379 - is_definer(func, desc) should pass ok 380 - is_definer(func, desc) should have the proper description ok 381 - is_definer(func, desc) should have the proper diagnostics ok 382 - isnt_definer(func, desc) should fail ok 383 - isnt_definer(func, desc) should have the proper description ok 384 - isnt_definer(func, desc) should have the proper diagnostics ok 385 - is_definer(func) should pass ok 386 - is_definer(func) should have the proper description ok 387 - is_definer(func) should have the proper diagnostics ok 388 - isnt_definer(func) should fail ok 389 - isnt_definer(func) should have the proper description ok 390 - isnt_definer(func) should have the proper diagnostics ok 391 - is_definer(sch, proc) should fail ok 392 - is_definer(sch, proc) should have the proper description ok 393 - is_definer(sch, proc) should have the proper diagnostics ok 394 - isnt_definer(sch, proc) should pass ok 395 - isnt_definer(sch, proc) should have the proper description ok 396 - isnt_definer(sch, proc) should have the proper diagnostics ok 397 - is_definer(proc) should fail ok 398 - is_definer(proc) should have the proper description ok 399 - is_definer(proc) should have the proper diagnostics ok 400 - isnt_definer(proc) should pass ok 401 - isnt_definer(proc) should have the proper description ok 402 - isnt_definer(proc) should have the proper diagnostics ok 403 - is_normal_function(schema, func, noargs, desc) should pass ok 404 - is_normal_function(schema, func, noargs, desc) should have the proper description ok 405 - is_normal_function(schema, func, noargs, desc) should have the proper diagnostics ok 406 - is_normal_function(schema, agg, arg, desc) should fail ok 407 - is_normal_function(schema, agg, arg, desc) should have the proper description ok 408 - is_normal_function(schema, agg, arg, desc) should have the proper diagnostics ok 409 - isnt_normal_function(schema, func, noargs, desc) should fail ok 410 - isnt_normal_function(schema, func, noargs, desc) should have the proper description ok 411 - isnt_normal_function(schema, func, noargs, desc) should have the proper diagnostics ok 412 - isnt_normal_function(schema, agg, noargs, desc) should pass ok 413 - isnt_normal_function(schema, agg, noargs, desc) should have the proper description ok 414 - isnt_normal_function(schema, agg, noargs, desc) should have the proper diagnostics ok 415 - is_normal_function(schema, func, args, desc) should pass ok 416 - is_normal_function(schema, func, args, desc) should have the proper description ok 417 - is_normal_function(schema, func, args, desc) should have the proper diagnostics ok 418 - is_normal_function(schema, agg, args, desc) should fail ok 419 - is_normal_function(schema, agg, args, desc) should have the proper description ok 420 - is_normal_function(schema, agg, args, desc) should have the proper diagnostics ok 421 - is_normal_function(schema, func, args, desc) should fail ok 422 - is_normal_function(schema, func, args, desc) should have the proper description ok 423 - is_normal_function(schema, func, args, desc) should have the proper diagnostics ok 424 - isnt_normal_function(schema, agg, args, desc) should pass ok 425 - isnt_normal_function(schema, agg, args, desc) should have the proper description ok 426 - isnt_normal_function(schema, agg, args, desc) should have the proper diagnostics ok 427 - is_normal_function(schema, nofunc, noargs, desc) should fail ok 428 - is_normal_function(schema, nofunc, noargs, desc) should have the proper description ok 429 - is_normal_function(schema, nofunc, noargs, desc) should have the proper diagnostics ok 430 - isnt_normal_function(schema, noagg, args, desc) should fail ok 431 - isnt_normal_function(schema, noagg, args, desc) should have the proper description ok 432 - isnt_normal_function(schema, noagg, args, desc) should have the proper diagnostics ok 433 - is_normal_function(schema, func, noargs) should pass ok 434 - is_normal_function(schema, func, noargs) should have the proper description ok 435 - is_normal_function(schema, func, noargs) should have the proper diagnostics ok 436 - is_normal_function(schema, agg, noargs) should fail ok 437 - is_normal_function(schema, agg, noargs) should have the proper description ok 438 - is_normal_function(schema, agg, noargs) should have the proper diagnostics ok 439 - isnt_normal_function(schema, func, noargs) should fail ok 440 - isnt_normal_function(schema, func, noargs) should have the proper description ok 441 - isnt_normal_function(schema, func, noargs) should have the proper diagnostics ok 442 - isnt_normal_function(schema, agg, noargs) should pass ok 443 - isnt_normal_function(schema, agg, noargs) should have the proper description ok 444 - isnt_normal_function(schema, agg, noargs) should have the proper diagnostics ok 445 - is_normal_function(schema, func2, args) should pass ok 446 - is_normal_function(schema, func2, args) should have the proper description ok 447 - is_normal_function(schema, func2, args) should have the proper diagnostics ok 448 - isnt_normal_function(schema, func2, args) should fail ok 449 - isnt_normal_function(schema, func2, args) should have the proper description ok 450 - isnt_normal_function(schema, func2, args) should have the proper diagnostics ok 451 - is_normal_function(schema, func, noargs) should fail ok 452 - is_normal_function(schema, func, noargs) should have the proper description ok 453 - is_normal_function(schema, func, noargs) should have the proper diagnostics ok 454 - is_normal_function(schema, nofunc, noargs) should fail ok 455 - is_normal_function(schema, nofunc, noargs) should have the proper description ok 456 - is_normal_function(schema, nofunc, noargs) should have the proper diagnostics ok 457 - is_normal_function(schema, func, desc) should pass ok 458 - is_normal_function(schema, func, desc) should have the proper description ok 459 - is_normal_function(schema, func, desc) should have the proper diagnostics ok 460 - is_normal_function(schema, agg, desc) should fail ok 461 - is_normal_function(schema, agg, desc) should have the proper description ok 462 - is_normal_function(schema, agg, desc) should have the proper diagnostics ok 463 - isnt_normal_function(schema, func, desc) should fail ok 464 - isnt_normal_function(schema, func, desc) should have the proper description ok 465 - isnt_normal_function(schema, func, desc) should have the proper diagnostics ok 466 - isnt_normal_function(schema, agg, desc) should pass ok 467 - isnt_normal_function(schema, agg, desc) should have the proper description ok 468 - isnt_normal_function(schema, agg, desc) should have the proper diagnostics ok 469 - is_normal_function(schema, func2, desc) should pass ok 470 - is_normal_function(schema, func2, desc) should have the proper description ok 471 - is_normal_function(schema, func2, desc) should have the proper diagnostics ok 472 - isnt_normal_function(schema, func2, desc) should fail ok 473 - isnt_normal_function(schema, func2, desc) should have the proper description ok 474 - isnt_normal_function(schema, func2, desc) should have the proper diagnostics ok 475 - is_normal_function(schema, nofunc, desc) should fail ok 476 - is_normal_function(schema, nofunc, desc) should have the proper description ok 477 - is_normal_function(schema, nofunc, desc) should have the proper diagnostics ok 478 - is_normal_function(schema, noagg, desc) should fail ok 479 - is_normal_function(schema, noagg, desc) should have the proper description ok 480 - is_normal_function(schema, noagg, desc) should have the proper diagnostics ok 481 - is_normal_function(schema, func) should pass ok 482 - is_normal_function(schema, func) should have the proper description ok 483 - is_normal_function(schema, func) should have the proper diagnostics ok 484 - is_normal_function(schema, agg) should fail ok 485 - is_normal_function(schema, agg) should have the proper description ok 486 - is_normal_function(schema, agg) should have the proper diagnostics ok 487 - isnt_normal_function(schema, func) should fail ok 488 - isnt_normal_function(schema, func) should have the proper description ok 489 - isnt_normal_function(schema, func) should have the proper diagnostics ok 490 - isnt_normal_function(schema, agg) should pass ok 491 - isnt_normal_function(schema, agg) should have the proper description ok 492 - isnt_normal_function(schema, agg) should have the proper diagnostics ok 493 - is_normal_function(schema, func2, args) should pass ok 494 - is_normal_function(schema, func2, args) should have the proper description ok 495 - is_normal_function(schema, func2, args) should have the proper diagnostics ok 496 - isnt_normal_function(schema, func2) should fail ok 497 - isnt_normal_function(schema, func2) should have the proper description ok 498 - isnt_normal_function(schema, func2) should have the proper diagnostics ok 499 - is_normal_function(schema, nofunc) should fail ok 500 - is_normal_function(schema, nofunc) should have the proper description ok 501 - is_normal_function(schema, nofunc) should have the proper diagnostics ok 502 - is_normal_function(schema, nogg) should fail ok 503 - is_normal_function(schema, nogg) should have the proper description ok 504 - is_normal_function(schema, nogg) should have the proper diagnostics ok 505 - is_normal_function(func, noargs, desc) should pass ok 506 - is_normal_function(func, noargs, desc) should have the proper description ok 507 - is_normal_function(func, noargs, desc) should have the proper diagnostics ok 508 - is_normal_function(func, agg, desc) should fail ok 509 - is_normal_function(func, agg, desc) should have the proper description ok 510 - is_normal_function(func, agg, desc) should have the proper diagnostics ok 511 - isnt_normal_function(func, noargs, desc) should fail ok 512 - isnt_normal_function(func, noargs, desc) should have the proper description ok 513 - isnt_normal_function(func, noargs, desc) should have the proper diagnostics ok 514 - isnt_normal_function(func, agg, desc) should pass ok 515 - isnt_normal_function(func, agg, desc) should have the proper description ok 516 - isnt_normal_function(func, agg, desc) should have the proper diagnostics ok 517 - is_normal_function(func, args, desc) should pass ok 518 - is_normal_function(func, args, desc) should have the proper description ok 519 - is_normal_function(func, args, desc) should have the proper diagnostics ok 520 - isnt_normal_function(func, args, desc) should fail ok 521 - isnt_normal_function(func, args, desc) should have the proper description ok 522 - isnt_normal_function(func, args, desc) should have the proper diagnostics ok 523 - is_normal_function(nofunc, noargs, desc) should fail ok 524 - is_normal_function(nofunc, noargs, desc) should have the proper description ok 525 - is_normal_function(nofunc, noargs, desc) should have the proper diagnostics ok 526 - is_normal_function(func, noagg, desc) should fail ok 527 - is_normal_function(func, noagg, desc) should have the proper description ok 528 - is_normal_function(func, noagg, desc) should have the proper diagnostics ok 529 - is_normal_function(func, noargs) should pass ok 530 - is_normal_function(func, noargs) should have the proper description ok 531 - is_normal_function(func, noargs) should have the proper diagnostics ok 532 - isnt_normal_function(func, noargs) should fail ok 533 - isnt_normal_function(func, noargs) should have the proper description ok 534 - isnt_normal_function(func, noargs) should have the proper diagnostics ok 535 - is_normal_function(func, noargs) should pass ok 536 - is_normal_function(func, noargs) should have the proper description ok 537 - is_normal_function(func, noargs) should have the proper diagnostics ok 538 - isnt_normal_function(func, noargs) should fail ok 539 - isnt_normal_function(func, noargs) should have the proper description ok 540 - isnt_normal_function(func, noargs) should have the proper diagnostics ok 541 - is_normal_function(nofunc, noargs) should fail ok 542 - is_normal_function(nofunc, noargs) should have the proper description ok 543 - is_normal_function(nofunc, noargs) should have the proper diagnostics ok 544 - isnt_normal_function(fnounc, noargs) should fail ok 545 - isnt_normal_function(fnounc, noargs) should have the proper description ok 546 - isnt_normal_function(fnounc, noargs) should have the proper diagnostics ok 547 - is_normal_function(func, desc) should pass ok 548 - is_normal_function(func, desc) should have the proper description ok 549 - is_normal_function(func, desc) should have the proper diagnostics ok 550 - is_normal_function(agg, desc) should fail ok 551 - is_normal_function(agg, desc) should have the proper description ok 552 - is_normal_function(agg, desc) should have the proper diagnostics ok 553 - isnt_normal_function(func, desc) should fail ok 554 - isnt_normal_function(func, desc) should have the proper description ok 555 - isnt_normal_function(func, desc) should have the proper diagnostics ok 556 - isnt_normal_function(agg, desc) should pass ok 557 - isnt_normal_function(agg, desc) should have the proper description ok 558 - isnt_normal_function(agg, desc) should have the proper diagnostics ok 559 - is_normal_function(func2, desc) should pass ok 560 - is_normal_function(func2, desc) should have the proper description ok 561 - is_normal_function(func2, desc) should have the proper diagnostics ok 562 - isnt_normal_function(func2, desc) should fail ok 563 - isnt_normal_function(func2, desc) should have the proper description ok 564 - isnt_normal_function(func2, desc) should have the proper diagnostics ok 565 - is_normal_function(nofunc, desc) should fail ok 566 - is_normal_function(nofunc, desc) should have the proper description ok 567 - is_normal_function(nofunc, desc) should have the proper diagnostics ok 568 - is_normal_function(noagg, desc) should fail ok 569 - is_normal_function(noagg, desc) should have the proper description ok 570 - is_normal_function(noagg, desc) should have the proper diagnostics ok 571 - is_normal_function(func) should pass ok 572 - is_normal_function(func) should have the proper description ok 573 - is_normal_function(func) should have the proper diagnostics ok 574 - is_normal_function(agg) should fail ok 575 - is_normal_function(agg) should have the proper description ok 576 - is_normal_function(agg) should have the proper diagnostics ok 577 - isnt_normal_function(func) should fail ok 578 - isnt_normal_function(func) should have the proper description ok 579 - isnt_normal_function(func) should have the proper diagnostics ok 580 - isnt_normal_function(agg) should pass ok 581 - isnt_normal_function(agg) should have the proper description ok 582 - isnt_normal_function(agg) should have the proper diagnostics ok 583 - is_normal_function(func2) should pass ok 584 - is_normal_function(func2) should have the proper description ok 585 - is_normal_function(func2) should have the proper diagnostics ok 586 - isnt_normal_function(func2,) should fail ok 587 - isnt_normal_function(func2,) should have the proper description ok 588 - isnt_normal_function(func2,) should have the proper diagnostics ok 589 - is_normal_function(nofunc) should fail ok 590 - is_normal_function(nofunc) should have the proper description ok 591 - is_normal_function(nofunc) should have the proper diagnostics ok 592 - is_normal_function(noagg) should fail ok 593 - is_normal_function(noagg) should have the proper description ok 594 - is_normal_function(noagg) should have the proper diagnostics ok 595 - is_normal_function(schema, proc) should fail ok 596 - is_normal_function(schema, proc) should have the proper description ok 597 - is_normal_function(schema, proc) should have the proper diagnostics ok 598 - isnt_normal_function(schema, proc) should pass ok 599 - isnt_normal_function(schema, proc) should have the proper description ok 600 - isnt_normal_function(schema, proc) should have the proper diagnostics ok 601 - is_normal_function(proc) should fail ok 602 - is_normal_function(proc) should have the proper description ok 603 - is_normal_function(proc) should have the proper diagnostics ok 604 - isnt_normal_function(proc) should pass ok 605 - isnt_normal_function(proc) should have the proper description ok 606 - isnt_normal_function(proc) should have the proper diagnostics ok 607 - is_aggregate(schema, func, arg, desc) should pass ok 608 - is_aggregate(schema, func, arg, desc) should have the proper description ok 609 - is_aggregate(schema, func, arg, desc) should have the proper diagnostics ok 610 - isnt_aggregate(schema, agg, arg, desc) should fail ok 611 - isnt_aggregate(schema, agg, arg, desc) should have the proper description ok 612 - isnt_aggregate(schema, agg, arg, desc) should have the proper diagnostics ok 613 - is_aggregate(schema, func, args, desc) should fail ok 614 - is_aggregate(schema, func, args, desc) should have the proper description ok 615 - is_aggregate(schema, func, args, desc) should have the proper diagnostics ok 616 - isnt_aggregate(schema, func, args, desc) should pass ok 617 - isnt_aggregate(schema, func, args, desc) should have the proper description ok 618 - isnt_aggregate(schema, func, args, desc) should have the proper diagnostics ok 619 - is_aggregate(schema, nofunc, arg, desc) should fail ok 620 - is_aggregate(schema, nofunc, arg, desc) should have the proper description ok 621 - is_aggregate(schema, nofunc, arg, desc) should have the proper diagnostics ok 622 - isnt_aggregate(schema, noagg, arg, desc) should fail ok 623 - isnt_aggregate(schema, noagg, arg, desc) should have the proper description ok 624 - isnt_aggregate(schema, noagg, arg, desc) should have the proper diagnostics ok 625 - is_aggregate(schema, agg, arg) should pass ok 626 - is_aggregate(schema, agg, arg) should have the proper description ok 627 - is_aggregate(schema, agg, arg) should have the proper diagnostics ok 628 - isnt_aggregate(schema, agg, arg) should fail ok 629 - isnt_aggregate(schema, agg, arg) should have the proper description ok 630 - isnt_aggregate(schema, agg, arg) should have the proper diagnostics ok 631 - is_aggregate(schema, func, args) should fail ok 632 - is_aggregate(schema, func, args) should have the proper description ok 633 - is_aggregate(schema, func, args) should have the proper diagnostics ok 634 - isnt_aggregate(schema, func, args) should pass ok 635 - isnt_aggregate(schema, func, args) should have the proper description ok 636 - isnt_aggregate(schema, func, args) should have the proper diagnostics ok 637 - is_aggregate(schema, noagg, arg) should fail ok 638 - is_aggregate(schema, noagg, arg) should have the proper description ok 639 - is_aggregate(schema, noagg, arg) should have the proper diagnostics ok 640 - isnt_aggregate(schema, noagg, arg) should fail ok 641 - isnt_aggregate(schema, noagg, arg) should have the proper description ok 642 - isnt_aggregate(schema, noagg, arg) should have the proper diagnostics ok 643 - is_aggregate(schema, agg, desc) should pass ok 644 - is_aggregate(schema, agg, desc) should have the proper description ok 645 - is_aggregate(schema, agg, desc) should have the proper diagnostics ok 646 - isnt_aggregate(schema, agg, desc) should fail ok 647 - isnt_aggregate(schema, agg, desc) should have the proper description ok 648 - isnt_aggregate(schema, agg, desc) should have the proper diagnostics ok 649 - is_aggregate(schema, noagg, desc) should fail ok 650 - is_aggregate(schema, noagg, desc) should have the proper description ok 651 - is_aggregate(schema, noagg, desc) should have the proper diagnostics ok 652 - isnt_aggregate(schema, noagg, desc) should fail ok 653 - isnt_aggregate(schema, noagg, desc) should have the proper description ok 654 - isnt_aggregate(schema, noagg, desc) should have the proper diagnostics ok 655 - is_aggregate(schema, agg) should pass ok 656 - is_aggregate(schema, agg) should have the proper description ok 657 - is_aggregate(schema, agg) should have the proper diagnostics ok 658 - isnt_aggregate(schema, agg) should fail ok 659 - isnt_aggregate(schema, agg) should have the proper description ok 660 - isnt_aggregate(schema, agg) should have the proper diagnostics ok 661 - is_aggregate(schema, noagg) should fail ok 662 - is_aggregate(schema, noagg) should have the proper description ok 663 - is_aggregate(schema, noagg) should have the proper diagnostics ok 664 - isnt_aggregate(schema, noagg) should fail ok 665 - isnt_aggregate(schema, noagg) should have the proper description ok 666 - isnt_aggregate(schema, noagg) should have the proper diagnostics ok 667 - is_aggregate(agg, arg, desc) should pass ok 668 - is_aggregate(agg, arg, desc) should have the proper description ok 669 - is_aggregate(agg, arg, desc) should have the proper diagnostics ok 670 - isnt_aggregate(agg, arg, desc) should fail ok 671 - isnt_aggregate(agg, arg, desc) should have the proper description ok 672 - isnt_aggregate(agg, arg, desc) should have the proper diagnostics ok 673 - is_aggregate(func, args, desc) should fail ok 674 - is_aggregate(func, args, desc) should have the proper description ok 675 - is_aggregate(func, args, desc) should have the proper diagnostics ok 676 - isnt_aggregate(func, args, desc) should pass ok 677 - isnt_aggregate(func, args, desc) should have the proper description ok 678 - isnt_aggregate(func, args, desc) should have the proper diagnostics ok 679 - is_aggregate(noagg, arg, desc) should fail ok 680 - is_aggregate(noagg, arg, desc) should have the proper description ok 681 - is_aggregate(noagg, arg, desc) should have the proper diagnostics ok 682 - isnt_aggregate(noagg, arg, desc) should fail ok 683 - isnt_aggregate(noagg, arg, desc) should have the proper description ok 684 - isnt_aggregate(noagg, arg, desc) should have the proper diagnostics ok 685 - is_aggregate(agg, arg) should pass ok 686 - is_aggregate(agg, arg) should have the proper description ok 687 - is_aggregate(agg, arg) should have the proper diagnostics ok 688 - isnt_aggregate(agg, arg) should fail ok 689 - isnt_aggregate(agg, arg) should have the proper description ok 690 - isnt_aggregate(agg, arg) should have the proper diagnostics ok 691 - is_aggregate(func, args) should fail ok 692 - is_aggregate(func, args) should have the proper description ok 693 - is_aggregate(func, args) should have the proper diagnostics ok 694 - isnt_aggregate(func, args) should pass ok 695 - isnt_aggregate(func, args) should have the proper description ok 696 - isnt_aggregate(func, args) should have the proper diagnostics ok 697 - is_aggregate(noagg, arg) should fail ok 698 - is_aggregate(noagg, arg) should have the proper description ok 699 - is_aggregate(noagg, arg) should have the proper diagnostics ok 700 - isnt_aggregate(noagg, arg) should fail ok 701 - isnt_aggregate(noagg, arg) should have the proper description ok 702 - isnt_aggregate(noagg, arg) should have the proper diagnostics ok 703 - is_aggregate(func, desc) should pass ok 704 - is_aggregate(func, desc) should have the proper description ok 705 - is_aggregate(func, desc) should have the proper diagnostics ok 706 - isnt_aggregate(agg, desc) should fail ok 707 - isnt_aggregate(agg, desc) should have the proper description ok 708 - isnt_aggregate(agg, desc) should have the proper diagnostics ok 709 - is_aggregate(nofunc, desc) should fail ok 710 - is_aggregate(nofunc, desc) should have the proper description ok 711 - is_aggregate(nofunc, desc) should have the proper diagnostics ok 712 - isnt_aggregate(noagg, desc) should fail ok 713 - isnt_aggregate(noagg, desc) should have the proper description ok 714 - isnt_aggregate(noagg, desc) should have the proper diagnostics ok 715 - is_aggregate(agg) should pass ok 716 - is_aggregate(agg) should have the proper description ok 717 - is_aggregate(agg) should have the proper diagnostics ok 718 - isnt_aggregate(agg) should fail ok 719 - isnt_aggregate(agg) should have the proper description ok 720 - isnt_aggregate(agg) should have the proper diagnostics ok 721 - is_aggregate(noagg) should fail ok 722 - is_aggregate(noagg) should have the proper description ok 723 - is_aggregate(noagg) should have the proper diagnostics ok 724 - isnt_aggregate(noagg) should fail ok 725 - isnt_aggregate(noagg) should have the proper description ok 726 - isnt_aggregate(noagg) should have the proper diagnostics ok 727 - is_aggregate(schema, proc) should fail ok 728 - is_aggregate(schema, proc) should have the proper description ok 729 - is_aggregate(schema, proc) should have the proper diagnostics ok 730 - is_aggregate(schema, proc) should pass ok 731 - is_aggregate(schema, proc) should have the proper description ok 732 - is_aggregate(schema, proc) should have the proper diagnostics ok 733 - is_aggregate(proc) should fail ok 734 - is_aggregate(proc) should have the proper description ok 735 - is_aggregate(proc) should have the proper diagnostics ok 736 - is_aggregate(proc) should pass ok 737 - is_aggregate(proc) should have the proper description ok 738 - is_aggregate(proc) should have the proper diagnostics ok 739 - is_window(schema, win, arg, desc) should pass ok 740 - is_window(schema, win, arg, desc) should have the proper description ok 741 - is_window(schema, win, arg, desc) should have the proper diagnostics ok 742 - isnt_window(schema, win, arg, desc) should fail ok 743 - isnt_window(schema, win, arg, desc) should have the proper description ok 744 - isnt_window(schema, win, arg, desc) should have the proper diagnostics ok 745 - is_window(schema, func, arg, desc) should fail ok 746 - is_window(schema, func, arg, desc) should have the proper description ok 747 - is_window(schema, func, arg, desc) should have the proper diagnostics ok 748 - isnt_window(schema, func, arg, desc) should pass ok 749 - isnt_window(schema, func, arg, desc) should have the proper description ok 750 - isnt_window(schema, func, arg, desc) should have the proper diagnostics ok 751 - is_window(schema, win, noargs, desc) should pass ok 752 - is_window(schema, win, noargs, desc) should have the proper description ok 753 - is_window(schema, win, noargs, desc) should have the proper diagnostics ok 754 - isnt_window(schema, win, noargs, desc) should fail ok 755 - isnt_window(schema, win, noargs, desc) should have the proper description ok 756 - isnt_window(schema, win, noargs, desc) should have the proper diagnostics ok 757 - is_window(schema, func, noarg, desc) should fail ok 758 - is_window(schema, func, noarg, desc) should have the proper description ok 759 - is_window(schema, func, noarg, desc) should have the proper diagnostics ok 760 - is_window(schema, win, noargs, desc) should fail ok 761 - is_window(schema, win, noargs, desc) should have the proper description ok 762 - is_window(schema, win, noargs, desc) should have the proper diagnostics ok 763 - is_window(schema, nowin, arg, desc) should fail ok 764 - is_window(schema, nowin, arg, desc) should have the proper description ok 765 - is_window(schema, nowin, arg, desc) should have the proper diagnostics ok 766 - isnt_window(schema, nowin, arg, desc) should fail ok 767 - isnt_window(schema, nowin, arg, desc) should have the proper description ok 768 - isnt_window(schema, nowin, arg, desc) should have the proper diagnostics ok 769 - is_window(schema, win, arg) should pass ok 770 - is_window(schema, win, arg) should have the proper description ok 771 - is_window(schema, win, arg) should have the proper diagnostics ok 772 - isnt_window(schema, win, arg) should fail ok 773 - isnt_window(schema, win, arg) should have the proper description ok 774 - isnt_window(schema, win, arg) should have the proper diagnostics ok 775 - is_window(schema, func, arg) should fail ok 776 - is_window(schema, func, arg) should have the proper description ok 777 - is_window(schema, func, arg) should have the proper diagnostics ok 778 - isnt_window(schema, func, arg) should pass ok 779 - isnt_window(schema, func, arg) should have the proper description ok 780 - isnt_window(schema, func, arg) should have the proper diagnostics ok 781 - is_window(schema, win, noargs) should pass ok 782 - is_window(schema, win, noargs) should have the proper description ok 783 - is_window(schema, win, noargs) should have the proper diagnostics ok 784 - isnt_window(schema, win, noargs) should fail ok 785 - isnt_window(schema, win, noargs) should have the proper description ok 786 - isnt_window(schema, win, noargs) should have the proper diagnostics ok 787 - is_window(schema, func, noarg) should fail ok 788 - is_window(schema, func, noarg) should have the proper description ok 789 - is_window(schema, func, noarg) should have the proper diagnostics ok 790 - isnt_window(schema, win, noargs) should fail ok 791 - isnt_window(schema, win, noargs) should have the proper description ok 792 - isnt_window(schema, win, noargs) should have the proper diagnostics ok 793 - is_window(schema, nowin, arg) should fail ok 794 - is_window(schema, nowin, arg) should have the proper description ok 795 - is_window(schema, nowin, arg) should have the proper diagnostics ok 796 - isnt_window(schema, nowin, arg) should fail ok 797 - isnt_window(schema, nowin, arg) should have the proper description ok 798 - isnt_window(schema, nowin, arg) should have the proper diagnostics ok 799 - is_window(schema, win, desc) should pass ok 800 - is_window(schema, win, desc) should have the proper description ok 801 - is_window(schema, win, desc) should have the proper diagnostics ok 802 - isnt_window(schema, win, desc) should fail ok 803 - isnt_window(schema, win, desc) should have the proper description ok 804 - isnt_window(schema, win, desc) should have the proper diagnostics ok 805 - is_window(schema, func, desc) should fail ok 806 - is_window(schema, func, desc) should have the proper description ok 807 - is_window(schema, func, desc) should have the proper diagnostics ok 808 - isnt_window(schema, func, desc) should pass ok 809 - isnt_window(schema, func, desc) should have the proper description ok 810 - isnt_window(schema, func, desc) should have the proper diagnostics ok 811 - is_window(schema, func, desc) should fail ok 812 - is_window(schema, func, desc) should have the proper description ok 813 - is_window(schema, func, desc) should have the proper diagnostics ok 814 - isnt_window(schema, win, desc) should fail ok 815 - isnt_window(schema, win, desc) should have the proper description ok 816 - isnt_window(schema, win, desc) should have the proper diagnostics ok 817 - is_window(schema, nowin, desc) should fail ok 818 - is_window(schema, nowin, desc) should have the proper description ok 819 - is_window(schema, nowin, desc) should have the proper diagnostics ok 820 - isnt_window(schema, nowin, desc) should fail ok 821 - isnt_window(schema, nowin, desc) should have the proper description ok 822 - isnt_window(schema, nowin, desc) should have the proper diagnostics ok 823 - is_window(schema, win) should pass ok 824 - is_window(schema, win) should have the proper description ok 825 - is_window(schema, win) should have the proper diagnostics ok 826 - isnt_window(schema, win) should fail ok 827 - isnt_window(schema, win) should have the proper description ok 828 - isnt_window(schema, win) should have the proper diagnostics ok 829 - is_window(schema, func) should fail ok 830 - is_window(schema, func) should have the proper description ok 831 - is_window(schema, func) should have the proper diagnostics ok 832 - isnt_window(schema, func) should pass ok 833 - isnt_window(schema, func) should have the proper description ok 834 - isnt_window(schema, func) should have the proper diagnostics ok 835 - is_window(schema, nowin) should fail ok 836 - is_window(schema, nowin) should have the proper description ok 837 - is_window(schema, nowin) should have the proper diagnostics ok 838 - isnt_window(schema, nowin) should fail ok 839 - isnt_window(schema, nowin) should have the proper description ok 840 - isnt_window(schema, nowin) should have the proper diagnostics ok 841 - is_window(win, arg, desc) should pass ok 842 - is_window(win, arg, desc) should have the proper description ok 843 - is_window(win, arg, desc) should have the proper diagnostics ok 844 - isnt_window(win, arg, desc) should fail ok 845 - isnt_window(win, arg, desc) should have the proper description ok 846 - isnt_window(win, arg, desc) should have the proper diagnostics ok 847 - is_window(func, arg, desc) should fail ok 848 - is_window(func, arg, desc) should have the proper description ok 849 - is_window(func, arg, desc) should have the proper diagnostics ok 850 - isnt_window(func, arg, desc) should pass ok 851 - isnt_window(func, arg, desc) should have the proper description ok 852 - isnt_window(func, arg, desc) should have the proper diagnostics ok 853 - is_window(win, noargs, desc) should pass ok 854 - is_window(win, noargs, desc) should have the proper description ok 855 - is_window(win, noargs, desc) should have the proper diagnostics ok 856 - isnt_window(win, noargs, desc) should fail ok 857 - isnt_window(win, noargs, desc) should have the proper description ok 858 - isnt_window(win, noargs, desc) should have the proper diagnostics ok 859 - is_window(func, noarg, desc) should fail ok 860 - is_window(func, noarg, desc) should have the proper description ok 861 - is_window(func, noarg, desc) should have the proper diagnostics ok 862 - isnt_window(win, noargs, desc) should fail ok 863 - isnt_window(win, noargs, desc) should have the proper description ok 864 - isnt_window(win, noargs, desc) should have the proper diagnostics ok 865 - is_window(nowin, arg, desc) should fail ok 866 - is_window(nowin, arg, desc) should have the proper description ok 867 - is_window(nowin, arg, desc) should have the proper diagnostics ok 868 - isnt_window(nowin, arg, desc) should fail ok 869 - isnt_window(nowin, arg, desc) should have the proper description ok 870 - isnt_window(nowin, arg, desc) should have the proper diagnostics ok 871 - is_window(win, arg, desc) should pass ok 872 - is_window(win, arg, desc) should have the proper description ok 873 - is_window(win, arg, desc) should have the proper diagnostics ok 874 - isnt_window(win, arg, desc) should fail ok 875 - isnt_window(win, arg, desc) should have the proper description ok 876 - isnt_window(win, arg, desc) should have the proper diagnostics ok 877 - is_window(func, arg, desc) should fail ok 878 - is_window(func, arg, desc) should have the proper description ok 879 - is_window(func, arg, desc) should have the proper diagnostics ok 880 - isnt_window(func, arg, desc) should pass ok 881 - isnt_window(func, arg, desc) should have the proper description ok 882 - isnt_window(func, arg, desc) should have the proper diagnostics ok 883 - is_window(win, noargs, desc) should pass ok 884 - is_window(win, noargs, desc) should have the proper description ok 885 - is_window(win, noargs, desc) should have the proper diagnostics ok 886 - isnt_window(win, noargs, desc) should fail ok 887 - isnt_window(win, noargs, desc) should have the proper description ok 888 - isnt_window(win, noargs, desc) should have the proper diagnostics ok 889 - is_window(func, noarg, desc) should fail ok 890 - is_window(func, noarg, desc) should have the proper description ok 891 - is_window(func, noarg, desc) should have the proper diagnostics ok 892 - isnt_window(win, noargs, desc) should fail ok 893 - isnt_window(win, noargs, desc) should have the proper description ok 894 - isnt_window(win, noargs, desc) should have the proper diagnostics ok 895 - is_window(nowin, arg, desc) should fail ok 896 - is_window(nowin, arg, desc) should have the proper description ok 897 - is_window(nowin, arg, desc) should have the proper diagnostics ok 898 - isnt_window(nowin, arg, desc) should fail ok 899 - isnt_window(nowin, arg, desc) should have the proper description ok 900 - isnt_window(nowin, arg, desc) should have the proper diagnostics ok 901 - is_window(win, desc) should pass ok 902 - is_window(win, desc) should have the proper description ok 903 - is_window(win, desc) should have the proper diagnostics ok 904 - isnt_window(win, desc) should fail ok 905 - isnt_window(win, desc) should have the proper description ok 906 - isnt_window(win, desc) should have the proper diagnostics ok 907 - is_window(func, desc) should fail ok 908 - is_window(func, desc) should have the proper description ok 909 - is_window(func, desc) should have the proper diagnostics ok 910 - isnt_window(func, desc) should pass ok 911 - isnt_window(func, desc) should have the proper description ok 912 - isnt_window(func, desc) should have the proper diagnostics ok 913 - is_window(func, desc) should fail ok 914 - is_window(func, desc) should have the proper description ok 915 - is_window(func, desc) should have the proper diagnostics ok 916 - is_window(nowin, desc) should fail ok 917 - is_window(nowin, desc) should have the proper description ok 918 - is_window(nowin, desc) should have the proper diagnostics ok 919 - isnt_window(nowin, desc) should fail ok 920 - isnt_window(nowin, desc) should have the proper description ok 921 - isnt_window(nowin, desc) should have the proper diagnostics ok 922 - is_window(win) should pass ok 923 - is_window(win) should have the proper description ok 924 - is_window(win) should have the proper diagnostics ok 925 - isnt_window(win) should fail ok 926 - isnt_window(win) should have the proper description ok 927 - isnt_window(win) should have the proper diagnostics ok 928 - is_window(func) should fail ok 929 - is_window(func) should have the proper description ok 930 - is_window(func) should have the proper diagnostics ok 931 - isnt_window(func) should pass ok 932 - isnt_window(func) should have the proper description ok 933 - isnt_window(func) should have the proper diagnostics ok 934 - is_window(nowin) should fail ok 935 - is_window(nowin) should have the proper description ok 936 - is_window(nowin) should have the proper diagnostics ok 937 - isnt_window(nowin) should fail ok 938 - isnt_window(nowin) should have the proper description ok 939 - isnt_window(nowin) should have the proper diagnostics ok 940 - is_window(schema, proc) should fail ok 941 - is_window(schema, proc) should have the proper description ok 942 - is_window(schema, proc) should have the proper diagnostics ok 943 - is_window(schema, proc) should pass ok 944 - is_window(schema, proc) should have the proper description ok 945 - is_window(schema, proc) should have the proper diagnostics ok 946 - is_window(proc) should fail ok 947 - is_window(proc) should have the proper description ok 948 - is_window(proc) should have the proper diagnostics ok 949 - is_window(proc) should pass ok 950 - is_window(proc) should have the proper description ok 951 - is_window(proc) should have the proper diagnostics ok 952 - is_strict(schema, func, 0 args, desc) should pass ok 953 - is_strict(schema, func, 0 args, desc) should have the proper description ok 954 - is_strict(schema, func, 0 args, desc) should have the proper diagnostics ok 955 - isnt_strict(schema, func, 0 args, desc) should fail ok 956 - isnt_strict(schema, func, 0 args, desc) should have the proper description ok 957 - isnt_strict(schema, func, 0 args, desc) should have the proper diagnostics ok 958 - is_strict(schema, func, 0 args) should pass ok 959 - is_strict(schema, func, 0 args) should have the proper description ok 960 - is_strict(schema, func, 0 args) should have the proper diagnostics ok 961 - isnt_strict(schema, func, 0 args) should fail ok 962 - isnt_strict(schema, func, 0 args) should have the proper description ok 963 - isnt_strict(schema, func, 0 args) should have the proper diagnostics ok 964 - is_strict(schema, func, args, desc) should fail ok 965 - is_strict(schema, func, args, desc) should have the proper description ok 966 - is_strict(schema, func, args, desc) should have the proper diagnostics ok 967 - isnt_strict(schema, func, args, desc) should pass ok 968 - isnt_strict(schema, func, args, desc) should have the proper description ok 969 - isnt_strict(schema, func, args, desc) should have the proper diagnostics ok 970 - is_strict(schema, func, args) should fail ok 971 - is_strict(schema, func, args) should have the proper description ok 972 - is_strict(schema, func, args) should have the proper diagnostics ok 973 - isnt_strict(schema, func, args) should pass ok 974 - isnt_strict(schema, func, args) should have the proper description ok 975 - isnt_strict(schema, func, args) should have the proper diagnostics ok 976 - is_strict(schema, func, desc) should pass ok 977 - is_strict(schema, func, desc) should have the proper description ok 978 - is_strict(schema, func, desc) should have the proper diagnostics ok 979 - isnt_strict(schema, func, desc) should fail ok 980 - isnt_strict(schema, func, desc) should have the proper description ok 981 - isnt_strict(schema, func, desc) should have the proper diagnostics ok 982 - is_strict(schema, func) should pass ok 983 - is_strict(schema, func) should have the proper description ok 984 - is_strict(schema, func) should have the proper diagnostics ok 985 - isnt_strict(schema, func) should fail ok 986 - isnt_strict(schema, func) should have the proper description ok 987 - isnt_strict(schema, func) should have the proper diagnostics ok 988 - isnt_strict(schema, func, args, desc) should pass ok 989 - isnt_strict(schema, func, args, desc) should have the proper description ok 990 - isnt_strict(schema, func, args, desc) should have the proper diagnostics ok 991 - isnt_strict(schema, func, args) should pass ok 992 - isnt_strict(schema, func, args) should have the proper description ok 993 - isnt_strict(schema, func, args) should have the proper diagnostics ok 994 - is_strict(func, 0 args, desc) should pass ok 995 - is_strict(func, 0 args, desc) should have the proper description ok 996 - is_strict(func, 0 args, desc) should have the proper diagnostics ok 997 - isnt_strict(func, 0 args, desc) should fail ok 998 - isnt_strict(func, 0 args, desc) should have the proper description ok 999 - isnt_strict(func, 0 args, desc) should have the proper diagnostics ok 1000 - is_strict(func, 0 args) should pass ok 1001 - is_strict(func, 0 args) should have the proper description ok 1002 - is_strict(func, 0 args) should have the proper diagnostics ok 1003 - isnt_strict(func, 0 args) should fail ok 1004 - isnt_strict(func, 0 args) should have the proper description ok 1005 - isnt_strict(func, 0 args) should have the proper diagnostics ok 1006 - is_strict(func, args, desc) should fail ok 1007 - is_strict(func, args, desc) should have the proper description ok 1008 - is_strict(func, args, desc) should have the proper diagnostics ok 1009 - isnt_strict(func, args, desc) should pass ok 1010 - isnt_strict(func, args, desc) should have the proper description ok 1011 - isnt_strict(func, args, desc) should have the proper diagnostics ok 1012 - is_strict(func, args) should fail ok 1013 - is_strict(func, args) should have the proper description ok 1014 - is_strict(func, args) should have the proper diagnostics ok 1015 - isnt_strict(func, args) should pass ok 1016 - isnt_strict(func, args) should have the proper description ok 1017 - isnt_strict(func, args) should have the proper diagnostics ok 1018 - is_strict(func, desc) should pass ok 1019 - is_strict(func, desc) should have the proper description ok 1020 - is_strict(func, desc) should have the proper diagnostics ok 1021 - isnt_strict(func, desc) should fail ok 1022 - isnt_strict(func, desc) should have the proper description ok 1023 - isnt_strict(func, desc) should have the proper diagnostics ok 1024 - is_strict(func) should pass ok 1025 - is_strict(func) should have the proper description ok 1026 - is_strict(func) should have the proper diagnostics ok 1027 - isnt_strict(func) should fail ok 1028 - isnt_strict(func) should have the proper description ok 1029 - isnt_strict(func) should have the proper diagnostics ok 1030 - is_strict(sch, proc) should fail ok 1031 - is_strict(sch, proc) should have the proper description ok 1032 - is_strict(sch, proc) should have the proper diagnostics ok 1033 - isnt_strict(sch, proc) should pass ok 1034 - isnt_strict(sch, proc) should have the proper description ok 1035 - isnt_strict(sch, proc) should have the proper diagnostics ok 1036 - is_strict(proc) should fail ok 1037 - is_strict(proc) should have the proper description ok 1038 - is_strict(proc) should have the proper diagnostics ok 1039 - isnt_strict(proc) should pass ok 1040 - isnt_strict(proc) should have the proper description ok 1041 - isnt_strict(proc) should have the proper diagnostics ok 1042 - function_volatility(schema, func, 0 args, volatile, desc) should pass ok 1043 - function_volatility(schema, func, 0 args, volatile, desc) should have the proper description ok 1044 - function_volatility(schema, func, 0 args, volatile, desc) should have the proper diagnostics ok 1045 - function_volatility(schema, func, 0 args, v, desc) should pass ok 1046 - function_volatility(schema, func, 0 args, v, desc) should have the proper description ok 1047 - function_volatility(schema, func, 0 args, v, desc) should have the proper diagnostics ok 1048 - function_volatility(schema, func, args, immutable, desc) should pass ok 1049 - function_volatility(schema, func, args, immutable, desc) should have the proper description ok 1050 - function_volatility(schema, func, args, immutable, desc) should have the proper diagnostics ok 1051 - function_volatility(schema, func, 0 args, stable, desc) should pass ok 1052 - function_volatility(schema, func, 0 args, stable, desc) should have the proper description ok 1053 - function_volatility(schema, func, 0 args, stable, desc) should have the proper diagnostics ok 1054 - function_volatility(schema, func, 0 args, volatile) should pass ok 1055 - function_volatility(schema, func, 0 args, volatile) should have the proper description ok 1056 - function_volatility(schema, func, 0 args, volatile) should have the proper diagnostics ok 1057 - function_volatility(schema, func, args, immutable) should pass ok 1058 - function_volatility(schema, func, args, immutable) should have the proper description ok 1059 - function_volatility(schema, func, volatile, desc) should pass ok 1060 - function_volatility(schema, func, volatile, desc) should have the proper description ok 1061 - function_volatility(schema, func, volatile, desc) should have the proper diagnostics ok 1062 - function_volatility(schema, func, volatile) should pass ok 1063 - function_volatility(schema, func, volatile) should have the proper description ok 1064 - function_volatility(schema, func, volatile) should have the proper diagnostics ok 1065 - function_volatility(schema, func, immutable, desc) should pass ok 1066 - function_volatility(schema, func, immutable, desc) should have the proper description ok 1067 - function_volatility(schema, func, immutable, desc) should have the proper diagnostics ok 1068 - function_volatility(schema, func, stable, desc) should pass ok 1069 - function_volatility(schema, func, stable, desc) should have the proper description ok 1070 - function_volatility(schema, func, stable, desc) should have the proper diagnostics ok 1071 - function_volatility(func, 0 args, volatile, desc) should pass ok 1072 - function_volatility(func, 0 args, volatile, desc) should have the proper description ok 1073 - function_volatility(func, 0 args, volatile, desc) should have the proper diagnostics ok 1074 - function_volatility(func, 0 args, v, desc) should pass ok 1075 - function_volatility(func, 0 args, v, desc) should have the proper description ok 1076 - function_volatility(func, 0 args, v, desc) should have the proper diagnostics ok 1077 - function_volatility(func, args, immutable, desc) should pass ok 1078 - function_volatility(func, args, immutable, desc) should have the proper description ok 1079 - function_volatility(func, args, immutable, desc) should have the proper diagnostics ok 1080 - function_volatility(func, 0 args, stable, desc) should pass ok 1081 - function_volatility(func, 0 args, stable, desc) should have the proper description ok 1082 - function_volatility(func, 0 args, stable, desc) should have the proper diagnostics ok 1083 - function_volatility(func, 0 args, volatile) should pass ok 1084 - function_volatility(func, 0 args, volatile) should have the proper description ok 1085 - function_volatility(func, 0 args, volatile) should have the proper diagnostics ok 1086 - function_volatility(func, args, immutable) should pass ok 1087 - function_volatility(func, args, immutable) should have the proper description ok 1088 - function_volatility(func, volatile, desc) should pass ok 1089 - function_volatility(func, volatile, desc) should have the proper description ok 1090 - function_volatility(func, volatile, desc) should have the proper diagnostics ok 1091 - function_volatility(func, volatile) should pass ok 1092 - function_volatility(func, volatile) should have the proper description ok 1093 - function_volatility(func, volatile) should have the proper diagnostics ok 1094 - function_volatility(func, immutable, desc) should pass ok 1095 - function_volatility(func, immutable, desc) should have the proper description ok 1096 - function_volatility(func, immutable, desc) should have the proper diagnostics ok 1097 - function_volatility(func, stable, desc) should pass ok 1098 - function_volatility(func, stable, desc) should have the proper description ok 1099 - function_volatility(func, stable, desc) should have the proper diagnostics ok 1100 - function_volatility(sch, proc, volatile) should pass ok 1101 - function_volatility(sch, proc, volatile) should have the proper description ok 1102 - function_volatility(sch, proc, volatile) should have the proper diagnostics ok 1103 - function_volatility(proc, volatile) should pass ok 1104 - function_volatility(proc, volatile) should have the proper description ok 1105 - function_volatility(proc, volatile) should have the proper diagnostics pgtap-1.3.2/test/expected/hastap.out000066400000000000000000002170571455775703000174520ustar00rootroot00000000000000\unset ECHO 1..1004 ok 1 - has_tablespace(non-existent tablespace) should fail ok 2 - has_tablespace(non-existent tablespace) should have the proper description ok 3 - has_tablespace(non-existent tablespace) should have the proper diagnostics ok 4 - has_tablespace(non-existent tablespace, tab) should fail ok 5 - has_tablespace(non-existent tablespace, tab) should have the proper description ok 6 - has_tablespace(non-existent tablespace, tab) should have the proper diagnostics ok 7 - has_tablespace(tablespace) should pass ok 8 - has_tablespace(tablespace) should have the proper description ok 9 - has_tablespace(tablespace) should have the proper diagnostics ok 10 - has_tablespace(tablespace, desc) should pass ok 11 - has_tablespace(tablespace, desc) should have the proper description ok 12 - has_tablespace(tablespace, desc) should have the proper diagnostics ok 13 - hasnt_tablespace(non-existent tablespace) should pass ok 14 - hasnt_tablespace(non-existent tablespace) should have the proper description ok 15 - hasnt_tablespace(non-existent tablespace) should have the proper diagnostics ok 16 - hasnt_tablespace(non-existent tablespace, tab) should pass ok 17 - hasnt_tablespace(non-existent tablespace, tab) should have the proper description ok 18 - hasnt_tablespace(non-existent tablespace, tab) should have the proper diagnostics ok 19 - hasnt_tablespace(pg_default) should fail ok 20 - hasnt_tablespace(pg_default) should have the proper description ok 21 - hasnt_tablespace(pg_default) should have the proper diagnostics ok 22 - hasnt_tablespace(tablespace, desc) should fail ok 23 - hasnt_tablespace(tablespace, desc) should have the proper description ok 24 - hasnt_tablespace(tablespace, desc) should have the proper diagnostics ok 25 - has_schema(non-existent schema) should fail ok 26 - has_schema(non-existent schema) should have the proper description ok 27 - has_schema(non-existent schema) should have the proper diagnostics ok 28 - has_schema(non-existent schema, tab) should fail ok 29 - has_schema(non-existent schema, tab) should have the proper description ok 30 - has_schema(non-existent schema, tab) should have the proper diagnostics ok 31 - has_schema(schema) should pass ok 32 - has_schema(schema) should have the proper description ok 33 - has_schema(schema) should have the proper diagnostics ok 34 - has_schema(schema, desc) should pass ok 35 - has_schema(schema, desc) should have the proper description ok 36 - has_schema(schema, desc) should have the proper diagnostics ok 37 - hasnt_schema(non-existent schema) should pass ok 38 - hasnt_schema(non-existent schema) should have the proper description ok 39 - hasnt_schema(non-existent schema) should have the proper diagnostics ok 40 - hasnt_schema(non-existent schema, tab) should pass ok 41 - hasnt_schema(non-existent schema, tab) should have the proper description ok 42 - hasnt_schema(non-existent schema, tab) should have the proper diagnostics ok 43 - hasnt_schema(schema) should fail ok 44 - hasnt_schema(schema) should have the proper description ok 45 - hasnt_schema(schema) should have the proper diagnostics ok 46 - hasnt_schema(schema, desc) should fail ok 47 - hasnt_schema(schema, desc) should have the proper description ok 48 - hasnt_schema(schema, desc) should have the proper diagnostics ok 49 - has_table(non-existent table) should fail ok 50 - has_table(non-existent table) should have the proper description ok 51 - has_table(non-existent table) should have the proper diagnostics ok 52 - has_table(non-existent schema, tab) should fail ok 53 - has_table(non-existent schema, tab) should have the proper description ok 54 - has_table(non-existent schema, tab) should have the proper diagnostics ok 55 - has_table(non-existent table, desc) should fail ok 56 - has_table(non-existent table, desc) should have the proper description ok 57 - has_table(non-existent table, desc) should have the proper diagnostics ok 58 - has_table(sch, non-existent table, desc) should fail ok 59 - has_table(sch, non-existent table, desc) should have the proper description ok 60 - has_table(sch, non-existent table, desc) should have the proper diagnostics ok 61 - has_table(tab, desc) should pass ok 62 - has_table(tab, desc) should have the proper description ok 63 - has_table(tab, desc) should have the proper diagnostics ok 64 - has_table(sch, tab, desc) should pass ok 65 - has_table(sch, tab, desc) should have the proper description ok 66 - has_table(sch, tab, desc) should have the proper diagnostics ok 67 - has_table(sch, view, desc) should fail ok 68 - has_table(sch, view, desc) should have the proper description ok 69 - has_table(sch, view, desc) should have the proper diagnostics ok 70 - has_table(type, desc) should fail ok 71 - has_table(type, desc) should have the proper description ok 72 - has_table(type, desc) should have the proper diagnostics ok 73 - has_table(sch, part, desc) should pass ok 74 - has_table(sch, part, desc) should have the proper description ok 75 - has_table(sch, part, desc) should have the proper diagnostics ok 76 - has_table(part, desc) should pass ok 77 - has_table(part, desc) should have the proper description ok 78 - has_table(part, desc) should have the proper diagnostics ok 79 - hasnt_table(non-existent table) should pass ok 80 - hasnt_table(non-existent table) should have the proper description ok 81 - hasnt_table(non-existent table) should have the proper diagnostics ok 82 - hasnt_table(non-existent schema, tab) should pass ok 83 - hasnt_table(non-existent schema, tab) should have the proper description ok 84 - hasnt_table(non-existent schema, tab) should have the proper diagnostics ok 85 - hasnt_table(non-existent table, desc) should pass ok 86 - hasnt_table(non-existent table, desc) should have the proper description ok 87 - hasnt_table(non-existent table, desc) should have the proper diagnostics ok 88 - hasnt_table(sch, non-existent tab, desc) should pass ok 89 - hasnt_table(sch, non-existent tab, desc) should have the proper description ok 90 - hasnt_table(sch, non-existent tab, desc) should have the proper diagnostics ok 91 - hasnt_table(tab, desc) should fail ok 92 - hasnt_table(tab, desc) should have the proper description ok 93 - hasnt_table(tab, desc) should have the proper diagnostics ok 94 - hasnt_table(sch, tab, desc) should fail ok 95 - hasnt_table(sch, tab, desc) should have the proper description ok 96 - hasnt_table(sch, tab, desc) should have the proper diagnostics ok 97 - hasnt_table(part, desc) should fail ok 98 - hasnt_table(part, desc) should have the proper description ok 99 - hasnt_table(part, desc) should have the proper diagnostics ok 100 - hasnt_table(sch, part, desc) should fail ok 101 - hasnt_table(sch, part, desc) should have the proper description ok 102 - hasnt_table(sch, part, desc) should have the proper diagnostics ok 103 - has_view(non-existent view) should fail ok 104 - has_view(non-existent view) should have the proper description ok 105 - has_view(non-existent view) should have the proper diagnostics ok 106 - has_view(non-existent view, desc) should fail ok 107 - has_view(non-existent view, desc) should have the proper description ok 108 - has_view(non-existent view, desc) should have the proper diagnostics ok 109 - has_view(sch, non-existent view, desc) should fail ok 110 - has_view(sch, non-existent view, desc) should have the proper description ok 111 - has_view(sch, non-existent view, desc) should have the proper diagnostics ok 112 - has_view(view, desc) should pass ok 113 - has_view(view, desc) should have the proper description ok 114 - has_view(view, desc) should have the proper diagnostics ok 115 - has_view(sch, view, desc) should pass ok 116 - has_view(sch, view, desc) should have the proper description ok 117 - has_view(sch, view, desc) should have the proper diagnostics ok 118 - has_view(sch, view) should pass ok 119 - has_view(sch, view) should have the proper description ok 120 - has_view(sch, view) should have the proper diagnostics ok 121 - has_view(sch, non-existent view, desc) should fail ok 122 - has_view(sch, non-existent view, desc) should have the proper description ok 123 - has_view(sch, non-existent view, desc) should have the proper diagnostics ok 124 - hasnt_view(non-existent view) should pass ok 125 - hasnt_view(non-existent view) should have the proper description ok 126 - hasnt_view(non-existent view) should have the proper diagnostics ok 127 - hasnt_view(non-existent view, desc) should pass ok 128 - hasnt_view(non-existent view, desc) should have the proper description ok 129 - hasnt_view(non-existent view, desc) should have the proper diagnostics ok 130 - hasnt_view(sch, non-existent view, desc) should pass ok 131 - hasnt_view(sch, non-existent view, desc) should have the proper description ok 132 - hasnt_view(sch, non-existent view, desc) should have the proper diagnostics ok 133 - hasnt_view(view, desc) should fail ok 134 - hasnt_view(view, desc) should have the proper description ok 135 - hasnt_view(view, desc) should have the proper diagnostics ok 136 - hasnt_view(sch, view, desc) should fail ok 137 - hasnt_view(sch, view, desc) should have the proper description ok 138 - hasnt_view(sch, view, desc) should have the proper diagnostics ok 139 - hasnt_view(sch, view) should fail ok 140 - hasnt_view(sch, view) should have the proper description ok 141 - hasnt_view(sch, view) should have the proper diagnostics ok 142 - hasnt_view(sch, non-existent view) should pass ok 143 - hasnt_view(sch, non-existent view) should have the proper description ok 144 - hasnt_view(sch, non-existent view) should have the proper diagnostics ok 145 - has_sequence(non-existent sequence) should fail ok 146 - has_sequence(non-existent sequence) should have the proper description ok 147 - has_sequence(non-existent sequence) should have the proper diagnostics ok 148 - has_sequence(non-existent sequence, desc) should fail ok 149 - has_sequence(non-existent sequence, desc) should have the proper description ok 150 - has_sequence(non-existent sequence, desc) should have the proper diagnostics ok 151 - has_sequence(sch, non-existent sequence, desc) should fail ok 152 - has_sequence(sch, non-existent sequence, desc) should have the proper description ok 153 - has_sequence(sch, non-existent sequence, desc) should have the proper diagnostics ok 154 - has_sequence(sequence, desc) should pass ok 155 - has_sequence(sequence, desc) should have the proper description ok 156 - has_sequence(sequence, desc) should have the proper diagnostics ok 157 - has_sequence(sch, sequence, desc) should pass ok 158 - has_sequence(sch, sequence, desc) should have the proper description ok 159 - has_sequence(sch, sequence, desc) should have the proper diagnostics ok 160 - has_sequence(sch, sequence) should pass ok 161 - has_sequence(sch, sequence) should have the proper description ok 162 - hasnt_sequence(non-existent sequence) should pass ok 163 - hasnt_sequence(non-existent sequence) should have the proper description ok 164 - hasnt_sequence(non-existent sequence) should have the proper diagnostics ok 165 - hasnt_sequence(non-existent sequence, desc) should pass ok 166 - hasnt_sequence(non-existent sequence, desc) should have the proper description ok 167 - hasnt_sequence(non-existent sequence, desc) should have the proper diagnostics ok 168 - hasnt_sequence(sch, non-existent sequence, desc) should pass ok 169 - hasnt_sequence(sch, non-existent sequence, desc) should have the proper description ok 170 - hasnt_sequence(sch, non-existent sequence, desc) should have the proper diagnostics ok 171 - hasnt_sequence(sequence, desc) should fail ok 172 - hasnt_sequence(sequence, desc) should have the proper description ok 173 - hasnt_sequence(sequence, desc) should have the proper diagnostics ok 174 - hasnt_sequence(sch, sequence, desc) should fail ok 175 - hasnt_sequence(sch, sequence, desc) should have the proper description ok 176 - hasnt_sequence(sch, sequence, desc) should have the proper diagnostics ok 177 - has_composite(non-existent composite type) should fail ok 178 - has_composite(non-existent composite type) should have the proper description ok 179 - has_composite(non-existent composite type) should have the proper diagnostics ok 180 - has_composite(non-existent schema, tab) should fail ok 181 - has_composite(non-existent schema, tab) should have the proper description ok 182 - has_composite(non-existent schema, tab) should have the proper diagnostics ok 183 - has_composite(sch, non-existent composite type, desc) should fail ok 184 - has_composite(sch, non-existent composite type, desc) should have the proper description ok 185 - has_composite(sch, non-existent composite type, desc) should have the proper diagnostics ok 186 - has_composite(tab, desc) should pass ok 187 - has_composite(tab, desc) should have the proper description ok 188 - has_composite(tab, desc) should have the proper diagnostics ok 189 - has_composite(sch, tab, desc) should pass ok 190 - has_composite(sch, tab, desc) should have the proper description ok 191 - has_composite(sch, tab, desc) should have the proper diagnostics ok 192 - has_composite(sch, view, desc) should fail ok 193 - has_composite(sch, view, desc) should have the proper description ok 194 - has_composite(sch, view, desc) should have the proper diagnostics ok 195 - has_composite(type, desc) should fail ok 196 - has_composite(type, desc) should have the proper description ok 197 - has_composite(type, desc) should have the proper diagnostics ok 198 - hasnt_composite(non-existent composite type) should pass ok 199 - hasnt_composite(non-existent composite type) should have the proper description ok 200 - hasnt_composite(non-existent composite type) should have the proper diagnostics ok 201 - hasnt_composite(non-existent schema, tab) should pass ok 202 - hasnt_composite(non-existent schema, tab) should have the proper description ok 203 - hasnt_composite(non-existent schema, tab) should have the proper diagnostics ok 204 - hasnt_composite(sch, non-existent tab, desc) should pass ok 205 - hasnt_composite(sch, non-existent tab, desc) should have the proper description ok 206 - hasnt_composite(sch, non-existent tab, desc) should have the proper diagnostics ok 207 - hasnt_composite(tab, desc) should fail ok 208 - hasnt_composite(tab, desc) should have the proper description ok 209 - hasnt_composite(tab, desc) should have the proper diagnostics ok 210 - hasnt_composite(sch, tab, desc) should fail ok 211 - hasnt_composite(sch, tab, desc) should have the proper description ok 212 - hasnt_composite(sch, tab, desc) should have the proper diagnostics ok 213 - has_type(type) should pass ok 214 - has_type(type) should have the proper description ok 215 - has_type(type) should have the proper diagnostics ok 216 - has_type(type, desc) should pass ok 217 - has_type(type, desc) should have the proper description ok 218 - has_type(type, desc) should have the proper diagnostics ok 219 - has_type(scheam, type) should pass ok 220 - has_type(scheam, type) should have the proper description ok 221 - has_type(scheam, type) should have the proper diagnostics ok 222 - has_type(schema, type, desc) should pass ok 223 - has_type(schema, type, desc) should have the proper description ok 224 - has_type(schema, type, desc) should have the proper diagnostics ok 225 - has_type(myType) should pass ok 226 - has_type(myType) should have the proper description ok 227 - has_type(myType) should have the proper diagnostics ok 228 - has_type(myType, desc) should pass ok 229 - has_type(myType, desc) should have the proper description ok 230 - has_type(myType, desc) should have the proper diagnostics ok 231 - has_type(scheam, myType) should pass ok 232 - has_type(scheam, myType) should have the proper description ok 233 - has_type(scheam, myType) should have the proper diagnostics ok 234 - has_type(schema, myType, desc) should pass ok 235 - has_type(schema, myType, desc) should have the proper description ok 236 - has_type(schema, myType, desc) should have the proper diagnostics ok 237 - has_type(type) should fail ok 238 - has_type(type) should have the proper description ok 239 - has_type(type) should have the proper diagnostics ok 240 - has_type(type, desc) should fail ok 241 - has_type(type, desc) should have the proper description ok 242 - has_type(type, desc) should have the proper diagnostics ok 243 - has_type(scheam, type) should fail ok 244 - has_type(scheam, type) should have the proper description ok 245 - has_type(scheam, type) should have the proper diagnostics ok 246 - has_type(schema, type, desc) should fail ok 247 - has_type(schema, type, desc) should have the proper description ok 248 - has_type(schema, type, desc) should have the proper diagnostics ok 249 - has_type(domain) should pass ok 250 - has_type(domain) should have the proper description ok 251 - has_type(domain) should have the proper diagnostics ok 252 - has_type(myDomain) should pass ok 253 - has_type(myDomain) should have the proper description ok 254 - has_type(myDomain) should have the proper diagnostics ok 255 - hasnt_type(type) should pass ok 256 - hasnt_type(type) should have the proper description ok 257 - hasnt_type(type) should have the proper diagnostics ok 258 - hasnt_type(type, desc) should pass ok 259 - hasnt_type(type, desc) should have the proper description ok 260 - hasnt_type(type, desc) should have the proper diagnostics ok 261 - hasnt_type(scheam, type) should pass ok 262 - hasnt_type(scheam, type) should have the proper description ok 263 - hasnt_type(scheam, type) should have the proper diagnostics ok 264 - hasnt_type(schema, type, desc) should pass ok 265 - hasnt_type(schema, type, desc) should have the proper description ok 266 - hasnt_type(schema, type, desc) should have the proper diagnostics ok 267 - hasnt_type(type) should fail ok 268 - hasnt_type(type) should have the proper description ok 269 - hasnt_type(type) should have the proper diagnostics ok 270 - hasnt_type(type, desc) should fail ok 271 - hasnt_type(type, desc) should have the proper description ok 272 - hasnt_type(type, desc) should have the proper diagnostics ok 273 - hasnt_type(scheam, type) should fail ok 274 - hasnt_type(scheam, type) should have the proper description ok 275 - hasnt_type(scheam, type) should have the proper diagnostics ok 276 - hasnt_type(schema, type, desc) should fail ok 277 - hasnt_type(schema, type, desc) should have the proper description ok 278 - hasnt_type(schema, type, desc) should have the proper diagnostics ok 279 - has_domain(domain) should pass ok 280 - has_domain(domain) should have the proper description ok 281 - has_domain(domain) should have the proper diagnostics ok 282 - has_domain(domain, desc) should pass ok 283 - has_domain(domain, desc) should have the proper description ok 284 - has_domain(domain, desc) should have the proper diagnostics ok 285 - has_domain(scheam, domain) should pass ok 286 - has_domain(scheam, domain) should have the proper description ok 287 - has_domain(scheam, domain) should have the proper diagnostics ok 288 - has_domain(schema, domain, desc) should pass ok 289 - has_domain(schema, domain, desc) should have the proper description ok 290 - has_domain(schema, domain, desc) should have the proper diagnostics ok 291 - has_domain(myDomain) should pass ok 292 - has_domain(myDomain) should have the proper description ok 293 - has_domain(myDomain) should have the proper diagnostics ok 294 - has_domain(myDomain, desc) should pass ok 295 - has_domain(myDomain, desc) should have the proper description ok 296 - has_domain(myDomain, desc) should have the proper diagnostics ok 297 - has_domain(scheam, myDomain) should pass ok 298 - has_domain(scheam, myDomain) should have the proper description ok 299 - has_domain(scheam, myDomain) should have the proper diagnostics ok 300 - has_domain(schema, myDomain, desc) should pass ok 301 - has_domain(schema, myDomain, desc) should have the proper description ok 302 - has_domain(schema, myDomain, desc) should have the proper diagnostics ok 303 - has_domain(domain) should fail ok 304 - has_domain(domain) should have the proper description ok 305 - has_domain(domain) should have the proper diagnostics ok 306 - has_domain(domain, desc) should fail ok 307 - has_domain(domain, desc) should have the proper description ok 308 - has_domain(domain, desc) should have the proper diagnostics ok 309 - has_domain(scheam, domain) should fail ok 310 - has_domain(scheam, domain) should have the proper description ok 311 - has_domain(scheam, domain) should have the proper diagnostics ok 312 - has_domain(schema, domain, desc) should fail ok 313 - has_domain(schema, domain, desc) should have the proper description ok 314 - has_domain(schema, domain, desc) should have the proper diagnostics ok 315 - hasnt_domain(domain) should pass ok 316 - hasnt_domain(domain) should have the proper description ok 317 - hasnt_domain(domain) should have the proper diagnostics ok 318 - hasnt_domain(domain, desc) should pass ok 319 - hasnt_domain(domain, desc) should have the proper description ok 320 - hasnt_domain(domain, desc) should have the proper diagnostics ok 321 - hasnt_domain(scheam, domain) should pass ok 322 - hasnt_domain(scheam, domain) should have the proper description ok 323 - hasnt_domain(scheam, domain) should have the proper diagnostics ok 324 - hasnt_domain(schema, domain, desc) should pass ok 325 - hasnt_domain(schema, domain, desc) should have the proper description ok 326 - hasnt_domain(schema, domain, desc) should have the proper diagnostics ok 327 - hasnt_domain(domain) should fail ok 328 - hasnt_domain(domain) should have the proper description ok 329 - hasnt_domain(domain) should have the proper diagnostics ok 330 - hasnt_domain(domain, desc) should fail ok 331 - hasnt_domain(domain, desc) should have the proper description ok 332 - hasnt_domain(domain, desc) should have the proper diagnostics ok 333 - hasnt_domain(scheam, domain) should fail ok 334 - hasnt_domain(scheam, domain) should have the proper description ok 335 - hasnt_domain(scheam, domain) should have the proper diagnostics ok 336 - hasnt_domain(schema, domain, desc) should fail ok 337 - hasnt_domain(schema, domain, desc) should have the proper description ok 338 - hasnt_domain(schema, domain, desc) should have the proper diagnostics ok 339 - has_column(non-existent tab, col) should fail ok 340 - has_column(non-existent tab, col) should have the proper description ok 341 - has_column(non-existent tab, col) should have the proper diagnostics ok 342 - has_column(non-existent tab, col, desc) should fail ok 343 - has_column(non-existent tab, col, desc) should have the proper description ok 344 - has_column(non-existent tab, col, desc) should have the proper diagnostics ok 345 - has_column(non-existent sch, tab, col, desc) should fail ok 346 - has_column(non-existent sch, tab, col, desc) should have the proper description ok 347 - has_column(non-existent sch, tab, col, desc) should have the proper diagnostics ok 348 - has_column(table, column) should pass ok 349 - has_column(table, column) should have the proper description ok 350 - has_column(table, column) should have the proper diagnostics ok 351 - has_column(sch, tab, col, desc) should pass ok 352 - has_column(sch, tab, col, desc) should have the proper description ok 353 - has_column(sch, tab, col, desc) should have the proper diagnostics ok 354 - has_column(table, camleCase column) should pass ok 355 - has_column(table, camleCase column) should have the proper description ok 356 - has_column(table, camleCase column) should have the proper diagnostics ok 357 - has_column(view, column) should pass ok 358 - has_column(view, column) should have the proper description ok 359 - has_column(view, column) should have the proper diagnostics ok 360 - has_column(type, column) should pass ok 361 - has_column(type, column) should have the proper description ok 362 - has_column(type, column) should have the proper diagnostics ok 363 - hasnt_column(non-existent tab, col) should pass ok 364 - hasnt_column(non-existent tab, col) should have the proper description ok 365 - hasnt_column(non-existent tab, col) should have the proper diagnostics ok 366 - hasnt_column(non-existent tab, col, desc) should pass ok 367 - hasnt_column(non-existent tab, col, desc) should have the proper description ok 368 - hasnt_column(non-existent tab, col, desc) should have the proper diagnostics ok 369 - hasnt_column(non-existent sch, tab, col, desc) should pass ok 370 - hasnt_column(non-existent sch, tab, col, desc) should have the proper description ok 371 - hasnt_column(non-existent sch, tab, col, desc) should have the proper diagnostics ok 372 - hasnt_column(table, column) should fail ok 373 - hasnt_column(table, column) should have the proper description ok 374 - hasnt_column(table, column) should have the proper diagnostics ok 375 - hasnt_column(sch, tab, col, desc) should fail ok 376 - hasnt_column(sch, tab, col, desc) should have the proper description ok 377 - hasnt_column(sch, tab, col, desc) should have the proper diagnostics ok 378 - hasnt_column(view, column) should pass ok 379 - hasnt_column(view, column) should have the proper description ok 380 - hasnt_column(view, column) should have the proper diagnostics ok 381 - hasnt_column(type, column) should pass ok 382 - hasnt_column(type, column) should have the proper description ok 383 - hasnt_column(type, column) should have the proper diagnostics ok 384 - has_cast( src, targ, schema, func, desc) should pass ok 385 - has_cast( src, targ, schema, func, desc) should have the proper description ok 386 - has_cast( src, targ, schema, func, desc) should have the proper diagnostics ok 387 - has_cast( src, targ, schema, func ) should pass ok 388 - has_cast( src, targ, schema, func ) should have the proper description ok 389 - has_cast( src, targ, schema, func ) should have the proper diagnostics ok 390 - has_cast( src, targ, func, desc ) should pass ok 391 - has_cast( src, targ, func, desc ) should have the proper description ok 392 - has_cast( src, targ, func, desc ) should have the proper diagnostics ok 393 - has_cast( src, targ, func) should pass ok 394 - has_cast( src, targ, func) should have the proper description ok 395 - has_cast( src, targ, func) should have the proper diagnostics ok 396 - has_cast( src, targ, desc ) should pass ok 397 - has_cast( src, targ, desc ) should have the proper description ok 398 - has_cast( src, targ, desc ) should have the proper diagnostics ok 399 - has_cast( src, targ ) should pass ok 400 - has_cast( src, targ ) should have the proper description ok 401 - has_cast( src, targ ) should have the proper diagnostics ok 402 - has_cast( src, targ, schema, func, desc) fail should fail ok 403 - has_cast( src, targ, schema, func, desc) fail should have the proper description ok 404 - has_cast( src, targ, schema, func, desc) fail should have the proper diagnostics ok 405 - has_cast( src, targ, func, desc ) fail should fail ok 406 - has_cast( src, targ, func, desc ) fail should have the proper description ok 407 - has_cast( src, targ, func, desc ) fail should have the proper diagnostics ok 408 - has_cast( src, targ, desc ) fail should fail ok 409 - has_cast( src, targ, desc ) fail should have the proper description ok 410 - has_cast( src, targ, desc ) fail should have the proper diagnostics ok 411 - hasnt_cast( src, targ, schema, func, desc) should fail ok 412 - hasnt_cast( src, targ, schema, func, desc) should have the proper description ok 413 - hasnt_cast( src, targ, schema, func, desc) should have the proper diagnostics ok 414 - hasnt_cast( src, targ, schema, func ) should fail ok 415 - hasnt_cast( src, targ, schema, func ) should have the proper description ok 416 - hasnt_cast( src, targ, schema, func ) should have the proper diagnostics ok 417 - hasnt_cast( src, targ, func, desc ) should fail ok 418 - hasnt_cast( src, targ, func, desc ) should have the proper description ok 419 - hasnt_cast( src, targ, func, desc ) should have the proper diagnostics ok 420 - hasnt_cast( src, targ, func) should fail ok 421 - hasnt_cast( src, targ, func) should have the proper description ok 422 - hasnt_cast( src, targ, func) should have the proper diagnostics ok 423 - hasnt_cast( src, targ, desc ) should fail ok 424 - hasnt_cast( src, targ, desc ) should have the proper description ok 425 - hasnt_cast( src, targ, desc ) should have the proper diagnostics ok 426 - hasnt_cast( src, targ ) should fail ok 427 - hasnt_cast( src, targ ) should have the proper description ok 428 - hasnt_cast( src, targ ) should have the proper diagnostics ok 429 - hasnt_cast( src, targ, schema, func, desc) fail should pass ok 430 - hasnt_cast( src, targ, schema, func, desc) fail should have the proper description ok 431 - hasnt_cast( src, targ, schema, func, desc) fail should have the proper diagnostics ok 432 - hasnt_cast( src, targ, func, desc ) fail should pass ok 433 - hasnt_cast( src, targ, func, desc ) fail should have the proper description ok 434 - hasnt_cast( src, targ, func, desc ) fail should have the proper diagnostics ok 435 - hasnt_cast( src, targ, desc ) fail should pass ok 436 - hasnt_cast( src, targ, desc ) fail should have the proper description ok 437 - hasnt_cast( src, targ, desc ) fail should have the proper diagnostics ok 438 - cast_context_is( src, targ, context, desc ) should pass ok 439 - cast_context_is( src, targ, context, desc ) should have the proper description ok 440 - cast_context_is( src, targ, context, desc ) should have the proper diagnostics ok 441 - cast_context_is( src, targ, context ) should pass ok 442 - cast_context_is( src, targ, context ) should have the proper description ok 443 - cast_context_is( src, targ, context ) should have the proper diagnostics ok 444 - cast_context_is( src, targ, i, desc ) should pass ok 445 - cast_context_is( src, targ, i, desc ) should have the proper description ok 446 - cast_context_is( src, targ, i, desc ) should have the proper diagnostics ok 447 - cast_context_is( src, targ, IMPL, desc ) should pass ok 448 - cast_context_is( src, targ, IMPL, desc ) should have the proper description ok 449 - cast_context_is( src, targ, IMPL, desc ) should have the proper diagnostics ok 450 - cast_context_is( src, targ, assignment, desc ) should pass ok 451 - cast_context_is( src, targ, assignment, desc ) should have the proper description ok 452 - cast_context_is( src, targ, assignment, desc ) should have the proper diagnostics ok 453 - cast_context_is( src, targ, a, desc ) should pass ok 454 - cast_context_is( src, targ, a, desc ) should have the proper description ok 455 - cast_context_is( src, targ, a, desc ) should have the proper diagnostics ok 456 - cast_context_is( src, targ, ASS, desc ) should pass ok 457 - cast_context_is( src, targ, ASS, desc ) should have the proper description ok 458 - cast_context_is( src, targ, ASS, desc ) should have the proper diagnostics ok 459 - cast_context_is( src, targ, explicit, desc ) should pass ok 460 - cast_context_is( src, targ, explicit, desc ) should have the proper description ok 461 - cast_context_is( src, targ, explicit, desc ) should have the proper diagnostics ok 462 - cast_context_is( src, targ, e, desc ) should pass ok 463 - cast_context_is( src, targ, e, desc ) should have the proper description ok 464 - cast_context_is( src, targ, e, desc ) should have the proper diagnostics ok 465 - cast_context_is( src, targ, EX, desc ) should pass ok 466 - cast_context_is( src, targ, EX, desc ) should have the proper description ok 467 - cast_context_is( src, targ, EX, desc ) should have the proper diagnostics ok 468 - cast_context_is( src, targ, context, desc ) fail should fail ok 469 - cast_context_is( src, targ, context, desc ) fail should have the proper description ok 470 - cast_context_is( src, targ, context, desc ) fail should have the proper diagnostics ok 471 - cast_context_is( src, targ, context ) fail should fail ok 472 - cast_context_is( src, targ, context ) fail should have the proper description ok 473 - cast_context_is( src, targ, context ) fail should have the proper diagnostics ok 474 - cast_context_is( src, targ, context, desc ) noexist should fail ok 475 - cast_context_is( src, targ, context, desc ) noexist should have the proper description ok 476 - cast_context_is( src, targ, context, desc ) noexist should have the proper diagnostics ok 477 - has_operator( left, schema, name, right, result, desc ) should pass ok 478 - has_operator( left, schema, name, right, result, desc ) should have the proper description ok 479 - has_operator( left, schema, name, right, result, desc ) should have the proper diagnostics ok 480 - has_operator( left, schema, name, right, result ) should pass ok 481 - has_operator( left, schema, name, right, result ) should have the proper description ok 482 - has_operator( left, schema, name, right, result ) should have the proper diagnostics ok 483 - has_operator( left, name, right, result, desc ) should pass ok 484 - has_operator( left, name, right, result, desc ) should have the proper description ok 485 - has_operator( left, name, right, result, desc ) should have the proper diagnostics ok 486 - has_operator( left, name, right, result ) should pass ok 487 - has_operator( left, name, right, result ) should have the proper description ok 488 - has_operator( left, name, right, result ) should have the proper diagnostics ok 489 - has_operator( left, name, right, desc ) should pass ok 490 - has_operator( left, name, right, desc ) should have the proper description ok 491 - has_operator( left, name, right, desc ) should have the proper diagnostics ok 492 - has_operator( left, name, right ) should pass ok 493 - has_operator( left, name, right ) should have the proper description ok 494 - has_operator( left, name, right ) should have the proper diagnostics ok 495 - has_operator( left, schema, name, right, result, desc ) fail should fail ok 496 - has_operator( left, schema, name, right, result, desc ) fail should have the proper description ok 497 - has_operator( left, schema, name, right, result, desc ) fail should have the proper diagnostics ok 498 - has_operator( left, schema, name, right, result ) fail should fail ok 499 - has_operator( left, schema, name, right, result ) fail should have the proper description ok 500 - has_operator( left, schema, name, right, result ) fail should have the proper diagnostics ok 501 - has_operator( left, name, right, result, desc ) fail should fail ok 502 - has_operator( left, name, right, result, desc ) fail should have the proper description ok 503 - has_operator( left, name, right, result, desc ) fail should have the proper diagnostics ok 504 - has_operator( left, name, right, result ) fail should fail ok 505 - has_operator( left, name, right, result ) fail should have the proper description ok 506 - has_operator( left, name, right, result ) fail should have the proper diagnostics ok 507 - has_operator( left, name, right, desc ) fail should fail ok 508 - has_operator( left, name, right, desc ) fail should have the proper description ok 509 - has_operator( left, name, right, desc ) fail should have the proper diagnostics ok 510 - has_operator( left, name, right ) fail should fail ok 511 - has_operator( left, name, right ) fail should have the proper description ok 512 - has_operator( left, name, right ) fail should have the proper diagnostics ok 513 - hasnt_operator( left, schema, name, right, result, desc ) fail should fail ok 514 - hasnt_operator( left, schema, name, right, result, desc ) fail should have the proper description ok 515 - hasnt_operator( left, schema, name, right, result, desc ) fail should have the proper diagnostics ok 516 - hasnt_operator( left, schema, name, right, result ) fail should fail ok 517 - hasnt_operator( left, schema, name, right, result ) fail should have the proper description ok 518 - hasnt_operator( left, schema, name, right, result ) fail should have the proper diagnostics ok 519 - hasnt_operator( left, name, right, result, desc ) fail should fail ok 520 - hasnt_operator( left, name, right, result, desc ) fail should have the proper description ok 521 - hasnt_operator( left, name, right, result, desc ) fail should have the proper diagnostics ok 522 - hasnt_operator( left, name, right, result ) fail should fail ok 523 - hasnt_operator( left, name, right, result ) fail should have the proper description ok 524 - hasnt_operator( left, name, right, result ) fail should have the proper diagnostics ok 525 - hasnt_operator( left, name, right, desc ) fail should fail ok 526 - hasnt_operator( left, name, right, desc ) fail should have the proper description ok 527 - hasnt_operator( left, name, right, desc ) fail should have the proper diagnostics ok 528 - hasnt_operator( left, name, right ) fail should fail ok 529 - hasnt_operator( left, name, right ) fail should have the proper description ok 530 - hasnt_operator( left, name, right ) fail should have the proper diagnostics ok 531 - hasnt_operator( left, schema, name, right, result, desc ) should pass ok 532 - hasnt_operator( left, schema, name, right, result, desc ) should have the proper description ok 533 - hasnt_operator( left, schema, name, right, result, desc ) should have the proper diagnostics ok 534 - hasnt_operator( left, schema, name, right, result ) should pass ok 535 - hasnt_operator( left, schema, name, right, result ) should have the proper description ok 536 - hasnt_operator( left, schema, name, right, result ) should have the proper diagnostics ok 537 - hasnt_operator( left, name, right, result, desc ) should pass ok 538 - hasnt_operator( left, name, right, result, desc ) should have the proper description ok 539 - hasnt_operator( left, name, right, result, desc ) should have the proper diagnostics ok 540 - hasnt_operator( left, name, right, result ) should pass ok 541 - hasnt_operator( left, name, right, result ) should have the proper description ok 542 - hasnt_operator( left, name, right, result ) should have the proper diagnostics ok 543 - hasnt_operator( left, name, right, desc ) should pass ok 544 - hasnt_operator( left, name, right, desc ) should have the proper description ok 545 - hasnt_operator( left, name, right, desc ) should have the proper diagnostics ok 546 - hasnt_operator( left, name, right ) should pass ok 547 - hasnt_operator( left, name, right ) should have the proper description ok 548 - hasnt_operator( left, name, right ) should have the proper diagnostics ok 549 - has_leftop( schema, name, right, result, desc ) should pass ok 550 - has_leftop( schema, name, right, result, desc ) should have the proper description ok 551 - has_leftop( schema, name, right, result, desc ) should have the proper diagnostics ok 552 - has_leftop( schema, name, right, result ) should pass ok 553 - has_leftop( schema, name, right, result ) should have the proper description ok 554 - has_leftop( schema, name, right, result ) should have the proper diagnostics ok 555 - has_leftop( name, right, result, desc ) should pass ok 556 - has_leftop( name, right, result, desc ) should have the proper description ok 557 - has_leftop( name, right, result, desc ) should have the proper diagnostics ok 558 - has_leftop( name, right, result ) should pass ok 559 - has_leftop( name, right, result ) should have the proper description ok 560 - has_leftop( name, right, result ) should have the proper diagnostics ok 561 - has_leftop( name, right, desc ) should pass ok 562 - has_leftop( name, right, desc ) should have the proper description ok 563 - has_leftop( name, right, desc ) should have the proper diagnostics ok 564 - has_leftop( name, right ) should pass ok 565 - has_leftop( name, right ) should have the proper description ok 566 - has_leftop( name, right ) should have the proper diagnostics ok 567 - has_leftop( schema, name, right, result, desc ) fail should fail ok 568 - has_leftop( schema, name, right, result, desc ) fail should have the proper description ok 569 - has_leftop( schema, name, right, result, desc ) fail should have the proper diagnostics ok 570 - has_leftop( schema, name, right, result ) fail should fail ok 571 - has_leftop( schema, name, right, result ) fail should have the proper description ok 572 - has_leftop( schema, name, right, result ) fail should have the proper diagnostics ok 573 - has_leftop( name, right, result, desc ) fail should fail ok 574 - has_leftop( name, right, result, desc ) fail should have the proper description ok 575 - has_leftop( name, right, result, desc ) fail should have the proper diagnostics ok 576 - has_leftop( name, right, result ) fail should fail ok 577 - has_leftop( name, right, result ) fail should have the proper description ok 578 - has_leftop( name, right, result ) fail should have the proper diagnostics ok 579 - has_leftop( name, right, desc ) fail should fail ok 580 - has_leftop( name, right, desc ) fail should have the proper description ok 581 - has_leftop( name, right, desc ) fail should have the proper diagnostics ok 582 - has_leftop( name, right ) fail should fail ok 583 - has_leftop( name, right ) fail should have the proper description ok 584 - has_leftop( name, right ) fail should have the proper diagnostics ok 585 - hasnt_leftop( schema, name, right, result, desc ) fail should fail ok 586 - hasnt_leftop( schema, name, right, result, desc ) fail should have the proper description ok 587 - hasnt_leftop( schema, name, right, result, desc ) fail should have the proper diagnostics ok 588 - hasnt_leftop( schema, name, right, result ) fail should fail ok 589 - hasnt_leftop( schema, name, right, result ) fail should have the proper description ok 590 - hasnt_leftop( schema, name, right, result ) fail should have the proper diagnostics ok 591 - hasnt_leftop( name, right, result, desc ) fail should fail ok 592 - hasnt_leftop( name, right, result, desc ) fail should have the proper description ok 593 - hasnt_leftop( name, right, result, desc ) fail should have the proper diagnostics ok 594 - hasnt_leftop( name, right, result ) fail should fail ok 595 - hasnt_leftop( name, right, result ) fail should have the proper description ok 596 - hasnt_leftop( name, right, result ) fail should have the proper diagnostics ok 597 - hasnt_leftop( name, right, desc ) fail should fail ok 598 - hasnt_leftop( name, right, desc ) fail should have the proper description ok 599 - hasnt_leftop( name, right, desc ) fail should have the proper diagnostics ok 600 - hasnt_leftop( name, right ) fail should fail ok 601 - hasnt_leftop( name, right ) fail should have the proper description ok 602 - hasnt_leftop( name, right ) fail should have the proper diagnostics ok 603 - hasnt_leftop( schema, name, right, result, desc ) should pass ok 604 - hasnt_leftop( schema, name, right, result, desc ) should have the proper description ok 605 - hasnt_leftop( schema, name, right, result, desc ) should have the proper diagnostics ok 606 - hasnt_leftop( schema, name, right, result ) should pass ok 607 - hasnt_leftop( schema, name, right, result ) should have the proper description ok 608 - hasnt_leftop( schema, name, right, result ) should have the proper diagnostics ok 609 - hasnt_leftop( name, right, result, desc ) should pass ok 610 - hasnt_leftop( name, right, result, desc ) should have the proper description ok 611 - hasnt_leftop( name, right, result, desc ) should have the proper diagnostics ok 612 - hasnt_leftop( name, right, result ) should pass ok 613 - hasnt_leftop( name, right, result ) should have the proper description ok 614 - hasnt_leftop( name, right, result ) should have the proper diagnostics ok 615 - hasnt_leftop( name, right, desc ) should pass ok 616 - hasnt_leftop( name, right, desc ) should have the proper description ok 617 - hasnt_leftop( name, right, desc ) should have the proper diagnostics ok 618 - hasnt_leftop( name, right ) should pass ok 619 - hasnt_leftop( name, right ) should have the proper description ok 620 - hasnt_leftop( name, right ) should have the proper diagnostics ok 621 - has_rightop( left, schema, name, result, desc ) should pass ok 622 - has_rightop( left, schema, name, result, desc ) should have the proper description ok 623 - has_rightop( left, schema, name, result, desc ) should have the proper diagnostics ok 624 - has_rightop( left, schema, name, result ) should pass ok 625 - has_rightop( left, schema, name, result ) should have the proper description ok 626 - has_rightop( left, schema, name, result ) should have the proper diagnostics ok 627 - has_rightop( left, name, result, desc ) should pass ok 628 - has_rightop( left, name, result, desc ) should have the proper description ok 629 - has_rightop( left, name, result, desc ) should have the proper diagnostics ok 630 - has_rightop( left, name, result ) should pass ok 631 - has_rightop( left, name, result ) should have the proper description ok 632 - has_rightop( left, name, result ) should have the proper diagnostics ok 633 - has_rightop( left, name, desc ) should pass ok 634 - has_rightop( left, name, desc ) should have the proper description ok 635 - has_rightop( left, name, desc ) should have the proper diagnostics ok 636 - has_rightop( left, name ) should pass ok 637 - has_rightop( left, name ) should have the proper description ok 638 - has_rightop( left, name ) should have the proper diagnostics ok 639 - has_rightop( left, schema, name, result, desc ) fail should fail ok 640 - has_rightop( left, schema, name, result, desc ) fail should have the proper description ok 641 - has_rightop( left, schema, name, result, desc ) fail should have the proper diagnostics ok 642 - has_rightop( left, schema, name, result ) fail should fail ok 643 - has_rightop( left, schema, name, result ) fail should have the proper description ok 644 - has_rightop( left, schema, name, result ) fail should have the proper diagnostics ok 645 - has_rightop( left, name, result, desc ) fail should fail ok 646 - has_rightop( left, name, result, desc ) fail should have the proper description ok 647 - has_rightop( left, name, result, desc ) fail should have the proper diagnostics ok 648 - has_rightop( left, name, result ) fail should fail ok 649 - has_rightop( left, name, result ) fail should have the proper description ok 650 - has_rightop( left, name, result ) fail should have the proper diagnostics ok 651 - has_rightop( left, name, desc ) fail should fail ok 652 - has_rightop( left, name, desc ) fail should have the proper description ok 653 - has_rightop( left, name, desc ) fail should have the proper diagnostics ok 654 - has_rightop( left, name ) fail should fail ok 655 - has_rightop( left, name ) fail should have the proper description ok 656 - has_rightop( left, name ) fail should have the proper diagnostics ok 657 - hasnt_rightop( left, schema, name, result, desc ) fail should fail ok 658 - hasnt_rightop( left, schema, name, result, desc ) fail should have the proper description ok 659 - hasnt_rightop( left, schema, name, result, desc ) fail should have the proper diagnostics ok 660 - hasnt_rightop( left, schema, name, result ) fail should fail ok 661 - hasnt_rightop( left, schema, name, result ) fail should have the proper description ok 662 - hasnt_rightop( left, schema, name, result ) fail should have the proper diagnostics ok 663 - hasnt_rightop( left, name, result, desc ) fail should fail ok 664 - hasnt_rightop( left, name, result, desc ) fail should have the proper description ok 665 - hasnt_rightop( left, name, result, desc ) fail should have the proper diagnostics ok 666 - hasnt_rightop( left, name, result ) fail should fail ok 667 - hasnt_rightop( left, name, result ) fail should have the proper description ok 668 - hasnt_rightop( left, name, result ) fail should have the proper diagnostics ok 669 - hasnt_rightop( left, name, desc ) fail should fail ok 670 - hasnt_rightop( left, name, desc ) fail should have the proper description ok 671 - hasnt_rightop( left, name, desc ) fail should have the proper diagnostics ok 672 - hasnt_rightop( left, name ) fail should fail ok 673 - hasnt_rightop( left, name ) fail should have the proper description ok 674 - hasnt_rightop( left, name ) fail should have the proper diagnostics ok 675 - hasnt_rightop( left, schema, name, result, desc ) should pass ok 676 - hasnt_rightop( left, schema, name, result, desc ) should have the proper description ok 677 - hasnt_rightop( left, schema, name, result, desc ) should have the proper diagnostics ok 678 - hasnt_rightop( left, schema, name, result ) should pass ok 679 - hasnt_rightop( left, schema, name, result ) should have the proper description ok 680 - hasnt_rightop( left, schema, name, result ) should have the proper diagnostics ok 681 - hasnt_rightop( left, name, result, desc ) should pass ok 682 - hasnt_rightop( left, name, result, desc ) should have the proper description ok 683 - hasnt_rightop( left, name, result, desc ) should have the proper diagnostics ok 684 - hasnt_rightop( left, name, result ) should pass ok 685 - hasnt_rightop( left, name, result ) should have the proper description ok 686 - hasnt_rightop( left, name, result ) should have the proper diagnostics ok 687 - hasnt_rightop( left, name, desc ) should pass ok 688 - hasnt_rightop( left, name, desc ) should have the proper description ok 689 - hasnt_rightop( left, name, desc ) should have the proper diagnostics ok 690 - hasnt_rightop( left, name ) should pass ok 691 - hasnt_rightop( left, name ) should have the proper description ok 692 - hasnt_rightop( left, name ) should have the proper diagnostics ok 693 - has_language(language) should pass ok 694 - has_language(language) should have the proper description ok 695 - has_language(language) should have the proper diagnostics ok 696 - has_language(language, desc) should pass ok 697 - has_language(language, desc) should have the proper description ok 698 - has_language(language, desc) should have the proper diagnostics ok 699 - has_language(nonexistent language) should fail ok 700 - has_language(nonexistent language) should have the proper description ok 701 - has_language(nonexistent language) should have the proper diagnostics ok 702 - has_language(nonexistent language, desc) should fail ok 703 - has_language(nonexistent language, desc) should have the proper description ok 704 - has_language(nonexistent language, desc) should have the proper diagnostics ok 705 - hasnt_language(language) should fail ok 706 - hasnt_language(language) should have the proper description ok 707 - hasnt_language(language) should have the proper diagnostics ok 708 - hasnt_language(language, desc) should fail ok 709 - hasnt_language(language, desc) should have the proper description ok 710 - hasnt_language(language, desc) should have the proper diagnostics ok 711 - hasnt_language(nonexistent language) should pass ok 712 - hasnt_language(nonexistent language) should have the proper description ok 713 - hasnt_language(nonexistent language) should have the proper diagnostics ok 714 - hasnt_language(nonexistent language, desc) should pass ok 715 - hasnt_language(nonexistent language, desc) should have the proper description ok 716 - hasnt_language(nonexistent language, desc) should have the proper diagnostics ok 717 - language_is_trusted(language, desc) should pass ok 718 - language_is_trusted(language, desc) should have the proper description ok 719 - language_is_trusted(language, desc) should have the proper diagnostics ok 720 - language_is_trusted(language) should pass ok 721 - language_is_trusted(language) should have the proper description ok 722 - language_is_trusted(language) should have the proper diagnostics ok 723 - language_is_trusted(language, desc) fail should fail ok 724 - language_is_trusted(language, desc) fail should have the proper description ok 725 - language_is_trusted(language, desc) fail should have the proper diagnostics ok 726 - language_is_trusted(language, desc) non-existent should fail ok 727 - language_is_trusted(language, desc) non-existent should have the proper description ok 728 - language_is_trusted(language, desc) non-existent should have the proper diagnostics ok 729 - has_opclass( schema, name, desc ) should pass ok 730 - has_opclass( schema, name, desc ) should have the proper description ok 731 - has_opclass( schema, name, desc ) should have the proper diagnostics ok 732 - has_opclass( schema, name ) should pass ok 733 - has_opclass( schema, name ) should have the proper description ok 734 - has_opclass( schema, name ) should have the proper diagnostics ok 735 - has_opclass( name, desc ) should pass ok 736 - has_opclass( name, desc ) should have the proper description ok 737 - has_opclass( name, desc ) should have the proper diagnostics ok 738 - has_opclass( name ) should pass ok 739 - has_opclass( name ) should have the proper description ok 740 - has_opclass( name ) should have the proper diagnostics ok 741 - has_opclass( schema, name, desc ) fail should fail ok 742 - has_opclass( schema, name, desc ) fail should have the proper description ok 743 - has_opclass( schema, name, desc ) fail should have the proper diagnostics ok 744 - has_opclass( name, desc ) fail should fail ok 745 - has_opclass( name, desc ) fail should have the proper description ok 746 - has_opclass( name, desc ) fail should have the proper diagnostics ok 747 - hasnt_opclass( schema, name, desc ) should fail ok 748 - hasnt_opclass( schema, name, desc ) should have the proper description ok 749 - hasnt_opclass( schema, name, desc ) should have the proper diagnostics ok 750 - hasnt_opclass( schema, name ) should fail ok 751 - hasnt_opclass( schema, name ) should have the proper description ok 752 - hasnt_opclass( schema, name ) should have the proper diagnostics ok 753 - hasnt_opclass( name, desc ) should fail ok 754 - hasnt_opclass( name, desc ) should have the proper description ok 755 - hasnt_opclass( name, desc ) should have the proper diagnostics ok 756 - hasnt_opclass( name ) should fail ok 757 - hasnt_opclass( name ) should have the proper description ok 758 - hasnt_opclass( name ) should have the proper diagnostics ok 759 - hasnt_opclass( schema, name, desc ) fail should pass ok 760 - hasnt_opclass( schema, name, desc ) fail should have the proper description ok 761 - hasnt_opclass( schema, name, desc ) fail should have the proper diagnostics ok 762 - hasnt_opclass( name, desc ) fail should pass ok 763 - hasnt_opclass( name, desc ) fail should have the proper description ok 764 - hasnt_opclass( name, desc ) fail should have the proper diagnostics ok 765 - domain_type_is(schema, domain, schema, type, desc) should pass ok 766 - domain_type_is(schema, domain, schema, type, desc) should have the proper description ok 767 - domain_type_is(schema, domain, schema, type, desc) should have the proper diagnostics ok 768 - domain_type_is(schema, domain, schema, type) should pass ok 769 - domain_type_is(schema, domain, schema, type) should have the proper description ok 770 - domain_type_is(schema, domain, schema, type) should have the proper diagnostics ok 771 - domain_type_is(schema, domain, schema, type, desc) fail should fail ok 772 - domain_type_is(schema, domain, schema, type, desc) fail should have the proper description ok 773 - domain_type_is(schema, domain, schema, type, desc) fail should have the proper diagnostics ok 774 - domain_type_is(schema, nondomain, schema, type, desc) should fail ok 775 - domain_type_is(schema, nondomain, schema, type, desc) should have the proper description ok 776 - domain_type_is(schema, nondomain, schema, type, desc) should have the proper diagnostics ok 777 - domain_type_is(schema, type, schema, type, desc) fail should fail ok 778 - domain_type_is(schema, type, schema, type, desc) fail should have the proper description ok 779 - domain_type_is(schema, type, schema, type, desc) fail should have the proper diagnostics ok 780 - domain_type_is(schema, domain, type, desc) should pass ok 781 - domain_type_is(schema, domain, type, desc) should have the proper description ok 782 - domain_type_is(schema, domain, type, desc) should have the proper diagnostics ok 783 - domain_type_is(schema, domain, type) should pass ok 784 - domain_type_is(schema, domain, type) should have the proper description ok 785 - domain_type_is(schema, domain, type) should have the proper diagnostics ok 786 - domain_type_is(schema, domain, type, desc) fail should fail ok 787 - domain_type_is(schema, domain, type, desc) fail should have the proper description ok 788 - domain_type_is(schema, domain, type, desc) fail should have the proper diagnostics ok 789 - domain_type_is(schema, nondomain, type, desc) should fail ok 790 - domain_type_is(schema, nondomain, type, desc) should have the proper description ok 791 - domain_type_is(schema, nondomain, type, desc) should have the proper diagnostics ok 792 - domain_type_is(schema, type, type, desc) fail should fail ok 793 - domain_type_is(schema, type, type, desc) fail should have the proper description ok 794 - domain_type_is(schema, type, type, desc) fail should have the proper diagnostics ok 795 - domain_type_is(domain, type, desc) should pass ok 796 - domain_type_is(domain, type, desc) should have the proper description ok 797 - domain_type_is(domain, type, desc) should have the proper diagnostics ok 798 - domain_type_is(domain, type) should pass ok 799 - domain_type_is(domain, type) should have the proper description ok 800 - domain_type_is(domain, type) should have the proper diagnostics ok 801 - domain_type_is(domain, type, desc) fail should fail ok 802 - domain_type_is(domain, type, desc) fail should have the proper description ok 803 - domain_type_is(domain, type, desc) fail should have the proper diagnostics ok 804 - domain_type_is(nondomain, type, desc) should fail ok 805 - domain_type_is(nondomain, type, desc) should have the proper description ok 806 - domain_type_is(nondomain, type, desc) should have the proper diagnostics ok 807 - domain_type_is(type, type, desc) fail should fail ok 808 - domain_type_is(type, type, desc) fail should have the proper description ok 809 - domain_type_is(type, type, desc) fail should have the proper diagnostics ok 810 - domain_type_isnt(schema, domain, schema, type, desc) should pass ok 811 - domain_type_isnt(schema, domain, schema, type, desc) should have the proper description ok 812 - domain_type_isnt(schema, domain, schema, type, desc) should have the proper diagnostics ok 813 - domain_type_isnt(schema, domain, schema, type) should pass ok 814 - domain_type_isnt(schema, domain, schema, type) should have the proper description ok 815 - domain_type_isnt(schema, domain, schema, type) should have the proper diagnostics ok 816 - domain_type_isnt(schema, domain, schema, type, desc) fail should fail ok 817 - domain_type_isnt(schema, domain, schema, type, desc) fail should have the proper description ok 818 - domain_type_isnt(schema, domain, schema, type, desc) fail should have the proper diagnostics ok 819 - domain_type_isnt(schema, nondomain, schema, type, desc) should fail ok 820 - domain_type_isnt(schema, nondomain, schema, type, desc) should have the proper description ok 821 - domain_type_isnt(schema, nondomain, schema, type, desc) should have the proper diagnostics ok 822 - domain_type_isnt(schema, type, schema, type, desc) should fail ok 823 - domain_type_isnt(schema, type, schema, type, desc) should have the proper description ok 824 - domain_type_isnt(schema, type, schema, type, desc) should have the proper diagnostics ok 825 - domain_type_isnt(schema, domain, type, desc) should pass ok 826 - domain_type_isnt(schema, domain, type, desc) should have the proper description ok 827 - domain_type_isnt(schema, domain, type, desc) should have the proper diagnostics ok 828 - domain_type_isnt(schema, domain, type) should pass ok 829 - domain_type_isnt(schema, domain, type) should have the proper description ok 830 - domain_type_isnt(schema, domain, type) should have the proper diagnostics ok 831 - domain_type_isnt(schema, domain, type, desc) fail should fail ok 832 - domain_type_isnt(schema, domain, type, desc) fail should have the proper description ok 833 - domain_type_isnt(schema, domain, type, desc) fail should have the proper diagnostics ok 834 - domain_type_isnt(schema, nondomain, type, desc) should fail ok 835 - domain_type_isnt(schema, nondomain, type, desc) should have the proper description ok 836 - domain_type_isnt(schema, nondomain, type, desc) should have the proper diagnostics ok 837 - domain_type_isnt(schema, type, type, desc) should fail ok 838 - domain_type_isnt(schema, type, type, desc) should have the proper description ok 839 - domain_type_isnt(schema, type, type, desc) should have the proper diagnostics ok 840 - domain_type_isnt(domain, type, desc) should pass ok 841 - domain_type_isnt(domain, type, desc) should have the proper description ok 842 - domain_type_isnt(domain, type, desc) should have the proper diagnostics ok 843 - domain_type_isnt(domain, type) should pass ok 844 - domain_type_isnt(domain, type) should have the proper description ok 845 - domain_type_isnt(domain, type) should have the proper diagnostics ok 846 - domain_type_isnt(domain, type, desc) fail should fail ok 847 - domain_type_isnt(domain, type, desc) fail should have the proper description ok 848 - domain_type_isnt(domain, type, desc) fail should have the proper diagnostics ok 849 - domain_type_isnt(nondomain, type, desc) should fail ok 850 - domain_type_isnt(nondomain, type, desc) should have the proper description ok 851 - domain_type_isnt(nondomain, type, desc) should have the proper diagnostics ok 852 - domain_type_isnt(type, type, desc) should fail ok 853 - domain_type_isnt(type, type, desc) should have the proper description ok 854 - domain_type_isnt(type, type, desc) should have the proper diagnostics ok 855 - has_relation(non-existent relation) should fail ok 856 - has_relation(non-existent relation) should have the proper description ok 857 - has_relation(non-existent relation) should have the proper diagnostics ok 858 - has_relation(non-existent schema, tab) should fail ok 859 - has_relation(non-existent schema, tab) should have the proper description ok 860 - has_relation(non-existent schema, tab) should have the proper diagnostics ok 861 - has_relation(sch, non-existent relation, desc) should fail ok 862 - has_relation(sch, non-existent relation, desc) should have the proper description ok 863 - has_relation(sch, non-existent relation, desc) should have the proper diagnostics ok 864 - has_relation(tab, desc) should pass ok 865 - has_relation(tab, desc) should have the proper description ok 866 - has_relation(tab, desc) should have the proper diagnostics ok 867 - has_relation(sch, tab, desc) should pass ok 868 - has_relation(sch, tab, desc) should have the proper description ok 869 - has_relation(sch, tab, desc) should have the proper diagnostics ok 870 - has_relation(sch, view, desc) should pass ok 871 - has_relation(sch, view, desc) should have the proper description ok 872 - has_relation(sch, view, desc) should have the proper diagnostics ok 873 - has_relation(type, desc) should pass ok 874 - has_relation(type, desc) should have the proper description ok 875 - has_relation(type, desc) should have the proper diagnostics ok 876 - hasnt_relation(non-existent relation) should pass ok 877 - hasnt_relation(non-existent relation) should have the proper description ok 878 - hasnt_relation(non-existent relation) should have the proper diagnostics ok 879 - hasnt_relation(non-existent schema, tab) should pass ok 880 - hasnt_relation(non-existent schema, tab) should have the proper description ok 881 - hasnt_relation(non-existent schema, tab) should have the proper diagnostics ok 882 - hasnt_relation(sch, non-existent tab, desc) should pass ok 883 - hasnt_relation(sch, non-existent tab, desc) should have the proper description ok 884 - hasnt_relation(sch, non-existent tab, desc) should have the proper diagnostics ok 885 - hasnt_relation(tab, desc) should fail ok 886 - hasnt_relation(tab, desc) should have the proper description ok 887 - hasnt_relation(tab, desc) should have the proper diagnostics ok 888 - hasnt_relation(sch, tab, desc) should fail ok 889 - hasnt_relation(sch, tab, desc) should have the proper description ok 890 - hasnt_relation(sch, tab, desc) should have the proper diagnostics ok 891 - has_foreign_table(non-existent table) should fail ok 892 - has_foreign_table(non-existent table) should have the proper description ok 893 - has_foreign_table(non-existent table) should have the proper diagnostics ok 894 - has_foreign_table(non-existent schema, tab) should fail ok 895 - has_foreign_table(non-existent schema, tab) should have the proper description ok 896 - has_foreign_table(non-existent schema, tab) should have the proper diagnostics ok 897 - has_foreign_table(non-existent table, desc) should fail ok 898 - has_foreign_table(non-existent table, desc) should have the proper description ok 899 - has_foreign_table(non-existent table, desc) should have the proper diagnostics ok 900 - has_foreign_table(sch, non-existent table, desc) should fail ok 901 - has_foreign_table(sch, non-existent table, desc) should have the proper description ok 902 - has_foreign_table(sch, non-existent table, desc) should have the proper diagnostics ok 903 - has_foreign_table(tab, desc) should pass ok 904 - has_foreign_table(tab, desc) should have the proper description ok 905 - has_foreign_table(tab, desc) should have the proper diagnostics ok 906 - has_foreign_table(sch, tab, desc) should pass ok 907 - has_foreign_table(sch, tab, desc) should have the proper description ok 908 - has_foreign_table(sch, tab, desc) should have the proper diagnostics ok 909 - has_foreign_table(sch, view, desc) should fail ok 910 - has_foreign_table(sch, view, desc) should have the proper description ok 911 - has_foreign_table(sch, view, desc) should have the proper diagnostics ok 912 - has_foreign_table(type, desc) should fail ok 913 - has_foreign_table(type, desc) should have the proper description ok 914 - has_foreign_table(type, desc) should have the proper diagnostics ok 915 - hasnt_foreign_table(non-existent table) should pass ok 916 - hasnt_foreign_table(non-existent table) should have the proper description ok 917 - hasnt_foreign_table(non-existent table) should have the proper diagnostics ok 918 - hasnt_foreign_table(non-existent schema, tab) should pass ok 919 - hasnt_foreign_table(non-existent schema, tab) should have the proper description ok 920 - hasnt_foreign_table(non-existent schema, tab) should have the proper diagnostics ok 921 - hasnt_foreign_table(non-existent table, desc) should pass ok 922 - hasnt_foreign_table(non-existent table, desc) should have the proper description ok 923 - hasnt_foreign_table(non-existent table, desc) should have the proper diagnostics ok 924 - hasnt_foreign_table(sch, non-existent tab, desc) should pass ok 925 - hasnt_foreign_table(sch, non-existent tab, desc) should have the proper description ok 926 - hasnt_foreign_table(sch, non-existent tab, desc) should have the proper diagnostics ok 927 - hasnt_foreign_table(tab, desc) should fail ok 928 - hasnt_foreign_table(tab, desc) should have the proper description ok 929 - hasnt_foreign_table(tab, desc) should have the proper diagnostics ok 930 - hasnt_foreign_table(sch, tab, desc) should fail ok 931 - hasnt_foreign_table(sch, tab, desc) should have the proper description ok 932 - hasnt_foreign_table(sch, tab, desc) should have the proper diagnostics ok 933 - has_materialized_view(non-existent materialized_view) should fail ok 934 - has_materialized_view(non-existent materialized_view) should have the proper description ok 935 - has_materialized_view(non-existent materialized_view) should have the proper diagnostics ok 936 - has_materialized_view(non-existent materialized_view, desc) should fail ok 937 - has_materialized_view(non-existent materialized_view, desc) should have the proper description ok 938 - has_materialized_view(non-existent materialized_view, desc) should have the proper diagnostics ok 939 - has_materialized_view(sch, non-existent materialized_view, desc) should fail ok 940 - has_materialized_view(sch, non-existent materialized_view, desc) should have the proper description ok 941 - has_materialized_view(sch, non-existent materialized_view, desc) should have the proper diagnostics ok 942 - has_materialized_view(materialized_view, desc) should pass ok 943 - has_materialized_view(materialized_view, desc) should have the proper description ok 944 - has_materialized_view(materialized_view, desc) should have the proper diagnostics ok 945 - has_materialized_view(sch, materialized_view, desc) should pass ok 946 - has_materialized_view(sch, materialized_view, desc) should have the proper description ok 947 - has_materialized_view(sch, materialized_view, desc) should have the proper diagnostics ok 948 - hasnt_materialized_view(non-existent materialized_view) should pass ok 949 - hasnt_materialized_view(non-existent materialized_view) should have the proper description ok 950 - hasnt_materialized_view(non-existent materialized_view) should have the proper diagnostics ok 951 - hasnt_materialized_view(non-existent materialized_view, desc) should pass ok 952 - hasnt_materialized_view(non-existent materialized_view, desc) should have the proper description ok 953 - hasnt_materialized_view(non-existent materialized_view, desc) should have the proper diagnostics ok 954 - hasnt_materialized_view(sch, non-existent materialized_view, desc) should pass ok 955 - hasnt_materialized_view(sch, non-existent materialized_view, desc) should have the proper description ok 956 - hasnt_materialized_view(sch, non-existent materialized_view, desc) should have the proper diagnostics ok 957 - hasnt_materialized_view(materialized_view, desc) should fail ok 958 - hasnt_materialized_view(materialized_view, desc) should have the proper description ok 959 - hasnt_materialized_view(materialized_view, desc) should have the proper diagnostics ok 960 - hasnt_materialized_view(sch, materialized_view, desc) should fail ok 961 - hasnt_materialized_view(sch, materialized_view, desc) should have the proper description ok 962 - hasnt_materialized_view(sch, materialized_view, desc) should have the proper diagnostics ok 963 - is_partitioned(non-existent part) should fail ok 964 - is_partitioned(non-existent part) should have the proper description ok 965 - is_partitioned(non-existent part) should have the proper diagnostics ok 966 - is_partitioned(non-existent part, desc) should fail ok 967 - is_partitioned(non-existent part, desc) should have the proper description ok 968 - is_partitioned(non-existent part, desc) should have the proper diagnostics ok 969 - is_partitioned(sch, non-existent part, desc) should fail ok 970 - is_partitioned(sch, non-existent part, desc) should have the proper description ok 971 - is_partitioned(sch, non-existent part, desc) should have the proper diagnostics ok 972 - is_partitioned(sch, part, desc) should pass ok 973 - is_partitioned(sch, part, desc) should have the proper description ok 974 - is_partitioned(sch, part, desc) should have the proper diagnostics ok 975 - is_partitioned(sch, part) should pass ok 976 - is_partitioned(sch, part) should have the proper description ok 977 - is_partitioned(sch, part) should have the proper diagnostics ok 978 - is_partitioned(part, desc) should pass ok 979 - is_partitioned(part, desc) should have the proper description ok 980 - is_partitioned(part, desc) should have the proper diagnostics ok 981 - is_partitioned(part) should pass ok 982 - is_partitioned(part) should have the proper description ok 983 - is_partitioned(part) should have the proper diagnostics ok 984 - isnt_partitioned(non-existent part) should pass ok 985 - isnt_partitioned(non-existent part) should have the proper description ok 986 - isnt_partitioned(non-existent part) should have the proper diagnostics ok 987 - isnt_partitioned(non-existent part, desc) should pass ok 988 - isnt_partitioned(non-existent part, desc) should have the proper description ok 989 - isnt_partitioned(non-existent part, desc) should have the proper diagnostics ok 990 - isnt_partitioned(sch, non-existent part, desc) should pass ok 991 - isnt_partitioned(sch, non-existent part, desc) should have the proper description ok 992 - isnt_partitioned(sch, non-existent part, desc) should have the proper diagnostics ok 993 - isnt_partitioned(sch, part, desc) should fail ok 994 - isnt_partitioned(sch, part, desc) should have the proper description ok 995 - isnt_partitioned(sch, part, desc) should have the proper diagnostics ok 996 - isnt_partitioned(sch, part) should fail ok 997 - isnt_partitioned(sch, part) should have the proper description ok 998 - isnt_partitioned(sch, part) should have the proper diagnostics ok 999 - isnt_partitioned(part, desc) should fail ok 1000 - isnt_partitioned(part, desc) should have the proper description ok 1001 - isnt_partitioned(part, desc) should have the proper diagnostics ok 1002 - isnt_partitioned(part) should fail ok 1003 - isnt_partitioned(part) should have the proper description ok 1004 - isnt_partitioned(part) should have the proper diagnostics pgtap-1.3.2/test/expected/index.out000066400000000000000000000433221455775703000172710ustar00rootroot00000000000000\unset ECHO 1..270 ok 1 - has_index() single column should pass ok 2 - has_index() single column should have the proper description ok 3 - has_index() single column should have the proper diagnostics ok 4 - has_index() single column no desc should pass ok 5 - has_index() single column no desc should have the proper description ok 6 - has_index() single column no desc should have the proper diagnostics ok 7 - has_index() hash index should pass ok 8 - has_index() hash index should have the proper description ok 9 - has_index() hash index should have the proper diagnostics ok 10 - has_index() hash index no desc should pass ok 11 - has_index() hash index no desc should have the proper description ok 12 - has_index() hash index no desc should have the proper diagnostics ok 13 - has_index() multi-column should pass ok 14 - has_index() multi-column should have the proper description ok 15 - has_index() multi-column should have the proper diagnostics ok 16 - has_index() multi-column no desc should pass ok 17 - has_index() multi-column no desc should have the proper description ok 18 - has_index() multi-column no desc should have the proper diagnostics ok 19 - has_index() functional should pass ok 20 - has_index() functional should have the proper description ok 21 - has_index() functional should have the proper diagnostics ok 22 - has_index() [functional] should pass ok 23 - has_index() [functional] should have the proper description ok 24 - has_index() [functional] should have the proper diagnostics ok 25 - has_index() [col, expr] should pass ok 26 - has_index() [col, expr] should have the proper description ok 27 - has_index() [col, expr] should have the proper diagnostics ok 28 - has_index() [expr, col, expr] should pass ok 29 - has_index() [expr, col, expr] should have the proper description ok 30 - has_index() [expr, col, expr] should have the proper diagnostics ok 31 - has_index() no cols should pass ok 32 - has_index() no cols should have the proper description ok 33 - has_index() no cols should have the proper diagnostics ok 34 - has_index() hash index should pass ok 35 - has_index() hash index should have the proper description ok 36 - has_index() hash index should have the proper diagnostics ok 37 - has_index() no cols no desc should pass ok 38 - has_index() no cols no desc should have the proper description ok 39 - has_index() no cols no desc should have the proper diagnostics ok 40 - has_index() no cols hash index no desc should pass ok 41 - has_index() no cols hash index no desc should have the proper description ok 42 - has_index() no cols hash index no desc should have the proper diagnostics ok 43 - has_index() no schema single column should pass ok 44 - has_index() no schema single column should have the proper description ok 45 - has_index() no schema single column should have the proper diagnostics ok 46 - has_index() no schema single column no desc should pass ok 47 - has_index() no schema single column no desc should have the proper description ok 48 - has_index() no schema single column no desc should have the proper diagnostics ok 49 - has_index() no schema multi-column should pass ok 50 - has_index() no schema multi-column should have the proper description ok 51 - has_index() no schema multi-column should have the proper diagnostics ok 52 - has_index() no schema multi-column no desc should pass ok 53 - has_index() no schema multi-column no desc should have the proper description ok 54 - has_index() no schema multi-column no desc should have the proper diagnostics ok 55 - has_index() no schema functional should pass ok 56 - has_index() no schema functional should have the proper description ok 57 - has_index() no schema functional should have the proper diagnostics ok 58 - has_index() no schema functional no desc should pass ok 59 - has_index() no schema functional no desc should have the proper description ok 60 - has_index() no schema functional no desc should have the proper diagnostics ok 61 - has_index() no schema or cols should pass ok 62 - has_index() no schema or cols should have the proper description ok 63 - has_index() no schema or cols should have the proper diagnostics ok 64 - has_index() hash index no schema or cols should pass ok 65 - has_index() hash index no schema or cols should have the proper description ok 66 - has_index() hash index no schema or cols should have the proper diagnostics ok 67 - has_index() no schema or cols or desc should pass ok 68 - has_index() no schema or cols or desc should have the proper description ok 69 - has_index() no schema or cols or desc should have the proper diagnostics ok 70 - has_index() hash index no schema or cols or desc should pass ok 71 - has_index() hash index no schema or cols or desc should have the proper description ok 72 - has_index() hash index no schema or cols or desc should have the proper diagnostics ok 73 - has_index() non-existent should fail ok 74 - has_index() non-existent should have the proper description ok 75 - has_index() non-existent should have the proper diagnostics ok 76 - has_index() missing should fail ok 77 - has_index() missing should have the proper description ok 78 - has_index() missing should have the proper diagnostics ok 79 - has_index() invalid should fail ok 80 - has_index() invalid should have the proper description ok 81 - has_index() invalid should have the proper diagnostics ok 82 - has_index() missing column should fail ok 83 - has_index() missing column should have the proper description ok 84 - has_index() missing column should have the proper diagnostics ok 85 - has_index() missing no schema should fail ok 86 - has_index() missing no schema should have the proper description ok 87 - has_index() missing no schema should have the proper diagnostics ok 88 - has_index() invalid no schema should fail ok 89 - has_index() invalid no schema should have the proper description ok 90 - has_index() invalid no schema should have the proper diagnostics ok 91 - has_index() functional fail should fail ok 92 - has_index() functional fail should have the proper description ok 93 - has_index() functional fail should have the proper diagnostics ok 94 - has_index() functional fail no schema should fail ok 95 - has_index() functional fail no schema should have the proper description ok 96 - has_index() functional fail no schema should have the proper diagnostics ok 97 - hasnt_index(schema, table, index, desc) should fail ok 98 - hasnt_index(schema, table, index, desc) should have the proper description ok 99 - hasnt_index(schema, table, index, desc) should have the proper diagnostics ok 100 - hasnt_index(schema, table, index) should fail ok 101 - hasnt_index(schema, table, index) should have the proper description ok 102 - hasnt_index(schema, table, index) should have the proper diagnostics ok 103 - hasnt_index(schema, table, non-index, desc) should pass ok 104 - hasnt_index(schema, table, non-index, desc) should have the proper description ok 105 - hasnt_index(schema, table, non-index, desc) should have the proper diagnostics ok 106 - hasnt_index(schema, table, non-index) should pass ok 107 - hasnt_index(schema, table, non-index) should have the proper description ok 108 - hasnt_index(schema, table, non-index) should have the proper diagnostics ok 109 - hasnt_index(table, index, desc) should fail ok 110 - hasnt_index(table, index, desc) should have the proper description ok 111 - hasnt_index(table, index, desc) should have the proper diagnostics ok 112 - hasnt_index(table, index) should fail ok 113 - hasnt_index(table, index) should have the proper description ok 114 - hasnt_index(table, index) should have the proper diagnostics ok 115 - hasnt_index(table, non-index, desc) should pass ok 116 - hasnt_index(table, non-index, desc) should have the proper description ok 117 - hasnt_index(table, non-index, desc) should have the proper diagnostics ok 118 - hasnt_index(table, non-index) should pass ok 119 - hasnt_index(table, non-index) should have the proper description ok 120 - hasnt_index(table, non-index) should have the proper diagnostics ok 121 - index_is_unique() should pass ok 122 - index_is_unique() should have the proper description ok 123 - index_is_unique() should have the proper diagnostics ok 124 - index_is_unique() no desc should pass ok 125 - index_is_unique() no desc should have the proper description ok 126 - index_is_unique() no desc should have the proper diagnostics ok 127 - index_is_unique() no schema should pass ok 128 - index_is_unique() no schema should have the proper description ok 129 - index_is_unique() no schema should have the proper diagnostics ok 130 - index_is_unique() index only should pass ok 131 - index_is_unique() index only should have the proper description ok 132 - index_is_unique() index only should have the proper diagnostics ok 133 - index_is_unique() on pk should pass ok 134 - index_is_unique() on pk should have the proper description ok 135 - index_is_unique() on pk should have the proper diagnostics ok 136 - index_is_unique() on pk no desc should pass ok 137 - index_is_unique() on pk no desc should have the proper description ok 138 - index_is_unique() on pk no desc should have the proper diagnostics ok 139 - index_is_unique() on pk no schema should pass ok 140 - index_is_unique() on pk no schema should have the proper description ok 141 - index_is_unique() on pk no schema should have the proper diagnostics ok 142 - index_is_unique() on pk index only should pass ok 143 - index_is_unique() on pk index only should have the proper description ok 144 - index_is_unique() on pk index only should have the proper diagnostics ok 145 - index_is_unique() fail should fail ok 146 - index_is_unique() fail should have the proper description ok 147 - index_is_unique() fail should have the proper diagnostics ok 148 - index_is_unique() fail no desc should fail ok 149 - index_is_unique() fail no desc should have the proper description ok 150 - index_is_unique() fail no desc should have the proper diagnostics ok 151 - index_is_unique() fail no schema should fail ok 152 - index_is_unique() fail no schema should have the proper description ok 153 - index_is_unique() fail no schema should have the proper diagnostics ok 154 - index_is_unique() fail index only should fail ok 155 - index_is_unique() fail index only should have the proper description ok 156 - index_is_unique() fail index only should have the proper diagnostics ok 157 - index_is_unique() no such index should fail ok 158 - index_is_unique() no such index should have the proper description ok 159 - index_is_unique() no such index should have the proper diagnostics ok 160 - index_is_primary() should pass ok 161 - index_is_primary() should have the proper description ok 162 - index_is_primary() should have the proper diagnostics ok 163 - index_is_primary() no desc should pass ok 164 - index_is_primary() no desc should have the proper description ok 165 - index_is_primary() no desc should have the proper diagnostics ok 166 - index_is_primary() no schema should pass ok 167 - index_is_primary() no schema should have the proper description ok 168 - index_is_primary() no schema should have the proper diagnostics ok 169 - index_is_primary() index only should pass ok 170 - index_is_primary() index only should have the proper description ok 171 - index_is_primary() index only should have the proper diagnostics ok 172 - index_is_primary() fail should fail ok 173 - index_is_primary() fail should have the proper description ok 174 - index_is_primary() fail should have the proper diagnostics ok 175 - index_is_primary() fail no desc should fail ok 176 - index_is_primary() fail no desc should have the proper description ok 177 - index_is_primary() fail no desc should have the proper diagnostics ok 178 - index_is_primary() fail no schema should fail ok 179 - index_is_primary() fail no schema should have the proper description ok 180 - index_is_primary() fail no schema should have the proper diagnostics ok 181 - index_is_primary() fail index only should fail ok 182 - index_is_primary() fail index only should have the proper description ok 183 - index_is_primary() fail index only should have the proper diagnostics ok 184 - index_is_primary() no such index should fail ok 185 - index_is_primary() no such index should have the proper description ok 186 - index_is_primary() no such index should have the proper diagnostics ok 187 - is_clustered() fail should fail ok 188 - is_clustered() fail should have the proper description ok 189 - is_clustered() fail should have the proper diagnostics ok 190 - is_clustered() fail no desc should fail ok 191 - is_clustered() fail no desc should have the proper description ok 192 - is_clustered() fail no desc should have the proper diagnostics ok 193 - is_clustered() fail no schema should fail ok 194 - is_clustered() fail no schema should have the proper description ok 195 - is_clustered() fail no schema should have the proper diagnostics ok 196 - is_clustered() fail index only should fail ok 197 - is_clustered() fail index only should have the proper description ok 198 - is_clustered() fail index only should have the proper diagnostics ok 199 - is_clustered() should pass ok 200 - is_clustered() should have the proper description ok 201 - is_clustered() should have the proper diagnostics ok 202 - is_clustered() no desc should pass ok 203 - is_clustered() no desc should have the proper description ok 204 - is_clustered() no desc should have the proper diagnostics ok 205 - is_clustered() no schema should pass ok 206 - is_clustered() no schema should have the proper description ok 207 - is_clustered() no schema should have the proper diagnostics ok 208 - is_clustered() index only should pass ok 209 - is_clustered() index only should have the proper description ok 210 - is_clustered() index only should have the proper diagnostics ok 211 - index_is_type() should pass ok 212 - index_is_type() should have the proper description ok 213 - index_is_type() should have the proper diagnostics ok 214 - index_is_type() no desc should pass ok 215 - index_is_type() no desc should have the proper description ok 216 - index_is_type() no desc should have the proper diagnostics ok 217 - index_is_type() fail should fail ok 218 - index_is_type() fail should have the proper description ok 219 - index_is_type() fail should have the proper diagnostics ok 220 - index_is_type() no schema should pass ok 221 - index_is_type() no schema should have the proper description ok 222 - index_is_type() no schema should have the proper diagnostics ok 223 - index_is_type() no schema fail should fail ok 224 - index_is_type() no schema fail should have the proper description ok 225 - index_is_type() no schema fail should have the proper diagnostics ok 226 - index_is_type() no table should pass ok 227 - index_is_type() no table should have the proper description ok 228 - index_is_type() no table should have the proper diagnostics ok 229 - index_is_type() no table fail should fail ok 230 - index_is_type() no table fail should have the proper description ok 231 - index_is_type() no table fail should have the proper diagnostics ok 232 - index_is_type() hash should pass ok 233 - index_is_type() hash should have the proper description ok 234 - index_is_type() hash should have the proper diagnostics ok 235 - is_indexed( schema, table, columns[], description ) should pass ok 236 - is_indexed( schema, table, columns[], description ) should have the proper description ok 237 - is_indexed( schema, table, columns[], description ) should have the proper diagnostics ok 238 - is_indexed( schema, table, columns[] ) should pass ok 239 - is_indexed( schema, table, columns[] ) should have the proper description ok 240 - is_indexed( schema, table, columns[] ) should have the proper diagnostics ok 241 - is_indexed( table, columns[], description ) should pass ok 242 - is_indexed( table, columns[], description ) should have the proper description ok 243 - is_indexed( table, columns[], description ) should have the proper diagnostics ok 244 - is_indexed( table, columns[] ) should pass ok 245 - is_indexed( table, columns[] ) should have the proper description ok 246 - is_indexed( table, columns[] ) should have the proper diagnostics ok 247 - is_indexed( schema, table, column, description ) should pass ok 248 - is_indexed( schema, table, column, description ) should have the proper description ok 249 - is_indexed( schema, table, column, description ) should have the proper diagnostics ok 250 - is_indexed( schema, table, column ) should pass ok 251 - is_indexed( schema, table, column ) should have the proper description ok 252 - is_indexed( schema, table, column ) should have the proper diagnostics ok 253 - is_indexed( schema, table, column ) fail should fail ok 254 - is_indexed( schema, table, column ) fail should have the proper description ok 255 - is_indexed( schema, table, column ) fail should have the proper diagnostics ok 256 - is_indexed( schema, table, columns[] ) fail, column order matters should fail ok 257 - is_indexed( schema, table, columns[] ) fail, column order matters should have the proper description ok 258 - is_indexed( schema, table, columns[] ) fail, column order matters should have the proper diagnostics ok 259 - is_indexed(schema, table, expressions) should pass ok 260 - is_indexed(schema, table, expressions) should have the proper description ok 261 - is_indexed(schema, table, expressions) should have the proper diagnostics ok 262 - is_indexed(schema, table, expression) should pass ok 263 - is_indexed(schema, table, expression) should have the proper description ok 264 - is_indexed(schema, table, expression) should have the proper diagnostics ok 265 - is_indexed(table, expressions) should pass ok 266 - is_indexed(table, expressions) should have the proper description ok 267 - is_indexed(table, expressions) should have the proper diagnostics ok 268 - is_indexed( table, expression) should pass ok 269 - is_indexed( table, expression) should have the proper description ok 270 - is_indexed( table, expression) should have the proper diagnostics pgtap-1.3.2/test/expected/inheritance.out000066400000000000000000000742331455775703000204600ustar00rootroot00000000000000\unset ECHO 1..408 ok 1 - has_inherited_tables(sch, tab, desc) should pass ok 2 - has_inherited_tables(sch, tab, desc) should have the proper description ok 3 - has_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 4 - has_inherited_tables(sch, tab, desc) fail should fail ok 5 - has_inherited_tables(sch, tab, desc) fail should have the proper description ok 6 - has_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 7 - has_inherited_tables(sch, nonesuch, desc) should fail ok 8 - has_inherited_tables(sch, nonesuch, desc) should have the proper description ok 9 - has_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 10 - has_inherited_tables(sch, tab) should pass ok 11 - has_inherited_tables(sch, tab) should have the proper description ok 12 - has_inherited_tables(sch, tab) should have the proper diagnostics ok 13 - has_inherited_tables(sch, tab) fail should fail ok 14 - has_inherited_tables(sch, tab) fail should have the proper description ok 15 - has_inherited_tables(sch, tab) fail should have the proper diagnostics ok 16 - has_inherited_tables(sch, nonesuch) should fail ok 17 - has_inherited_tables(sch, nonesuch) should have the proper description ok 18 - has_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 19 - has_inherited_tables(tab, desc) should pass ok 20 - has_inherited_tables(tab, desc) should have the proper description ok 21 - has_inherited_tables(tab, desc) should have the proper diagnostics ok 22 - has_inherited_tables(tab, desc) fail should fail ok 23 - has_inherited_tables(tab, desc) fail should have the proper description ok 24 - has_inherited_tables(tab, desc) fail should have the proper diagnostics ok 25 - has_inherited_tables(nonesuch, desc) should fail ok 26 - has_inherited_tables(nonesuch, desc) should have the proper description ok 27 - has_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 28 - has_inherited_tables(tab) should pass ok 29 - has_inherited_tables(tab) should have the proper description ok 30 - has_inherited_tables(tab) should have the proper diagnostics ok 31 - has_inherited_tables(tab) fail should fail ok 32 - has_inherited_tables(tab) fail should have the proper description ok 33 - has_inherited_tables(tab) fail should have the proper diagnostics ok 34 - has_inherited_tables(nonesuch) should fail ok 35 - has_inherited_tables(nonesuch) should have the proper description ok 36 - has_inherited_tables(nonesuch) should have the proper diagnostics ok 37 - hasnt_inherited_tables(sch, tab, desc) should pass ok 38 - hasnt_inherited_tables(sch, tab, desc) should have the proper description ok 39 - hasnt_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 40 - hasnt_inherited_tables(sch, tab, desc) fail should fail ok 41 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper description ok 42 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 43 - hasnt_inherited_tables(sch, nonesuch, desc) should pass ok 44 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper description ok 45 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 46 - hasnt_inherited_tables(sch, tab) should pass ok 47 - hasnt_inherited_tables(sch, tab) should have the proper description ok 48 - hasnt_inherited_tables(sch, tab) should have the proper diagnostics ok 49 - hasnt_inherited_tables(sch, tab) fail should fail ok 50 - hasnt_inherited_tables(sch, tab) fail should have the proper description ok 51 - hasnt_inherited_tables(sch, tab) fail should have the proper diagnostics ok 52 - hasnt_inherited_tables(sch, nonesuch) should pass ok 53 - hasnt_inherited_tables(sch, nonesuch) should have the proper description ok 54 - hasnt_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 55 - hasnt_inherited_tables(tab, desc) should pass ok 56 - hasnt_inherited_tables(tab, desc) should have the proper description ok 57 - hasnt_inherited_tables(tab, desc) should have the proper diagnostics ok 58 - hasnt_inherited_tables(tab, desc) fail should fail ok 59 - hasnt_inherited_tables(tab, desc) fail should have the proper description ok 60 - hasnt_inherited_tables(tab, desc) fail should have the proper diagnostics ok 61 - hasnt_inherited_tables(nonesuch, desc) should pass ok 62 - hasnt_inherited_tables(nonesuch, desc) should have the proper description ok 63 - hasnt_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 64 - hasnt_inherited_tables(tab) should pass ok 65 - hasnt_inherited_tables(tab) should have the proper description ok 66 - hasnt_inherited_tables(tab) should have the proper diagnostics ok 67 - hasnt_inherited_tables(tab) fail should fail ok 68 - hasnt_inherited_tables(tab) fail should have the proper description ok 69 - hasnt_inherited_tables(tab) fail should have the proper diagnostics ok 70 - hasnt_inherited_tables(nonesuch) should pass ok 71 - hasnt_inherited_tables(nonesuch) should have the proper description ok 72 - hasnt_inherited_tables(nonesuch) should have the proper diagnostics ok 73 - is_ancestor_of(psch, ptab, csch, ctab, 1, desc) should pass ok 74 - is_ancestor_of(psch, ptab, csch, ctab, 1, desc) should have the proper description ok 75 - is_ancestor_of(psch, ptab, csch, ctab, 1, desc) should have the proper diagnostics ok 76 - is_ancestor_of(psch, ptab, csch, ctab, 2, desc) should pass ok 77 - is_ancestor_of(psch, ptab, csch, ctab, 2, desc) should have the proper description ok 78 - is_ancestor_of(psch, ptab, csch, ctab, 2, desc) should have the proper diagnostics ok 79 - is_ancestor_of(psch, nope, csch, ctab, 1, desc) should fail ok 80 - is_ancestor_of(psch, nope, csch, ctab, 1, desc) should have the proper description ok 81 - is_ancestor_of(psch, nope, csch, ctab, 1, desc) should have the proper diagnostics ok 82 - is_ancestor_of(psch, ptab, csch, nope, desc) should fail ok 83 - is_ancestor_of(psch, ptab, csch, nope, desc) should have the proper description ok 84 - is_ancestor_of(psch, ptab, csch, nope, desc) should have the proper diagnostics ok 85 - is_ancestor_of(psch, ptab, csch, ctab, 1) should pass ok 86 - is_ancestor_of(psch, ptab, csch, ctab, 1) should have the proper description ok 87 - is_ancestor_of(psch, ptab, csch, ctab, 1) should have the proper diagnostics ok 88 - is_ancestor_of(psch, nope, csch, ctab, 1) should fail ok 89 - is_ancestor_of(psch, nope, csch, ctab, 1) should have the proper description ok 90 - is_ancestor_of(psch, nope, csch, ctab, 1) should have the proper diagnostics ok 91 - is_ancestor_of(psch, ptab, csch, nope, 1) should fail ok 92 - is_ancestor_of(psch, ptab, csch, nope, 1) should have the proper description ok 93 - is_ancestor_of(psch, ptab, csch, nope, 1) should have the proper diagnostics ok 94 - is_ancestor_of(psch, ptab, csch, ctab, 2) should pass ok 95 - is_ancestor_of(psch, ptab, csch, ctab, 2) should have the proper description ok 96 - is_ancestor_of(psch, ptab, csch, ctab, 2) should have the proper diagnostics ok 97 - is_ancestor_of(psch, nope, csch, ctab, 2) should fail ok 98 - is_ancestor_of(psch, nope, csch, ctab, 2) should have the proper description ok 99 - is_ancestor_of(psch, nope, csch, ctab, 2) should have the proper diagnostics ok 100 - is_ancestor_of(psch, ptab, csch, nope, 2) should fail ok 101 - is_ancestor_of(psch, ptab, csch, nope, 2) should have the proper description ok 102 - is_ancestor_of(psch, ptab, csch, nope, 2) should have the proper diagnostics ok 103 - is_ancestor_of(psch, ptab, csch, ctab, desc) should pass ok 104 - is_ancestor_of(psch, ptab, csch, ctab, desc) should have the proper description ok 105 - is_ancestor_of(psch, ptab, csch, ctab, desc) should have the proper diagnostics ok 106 - is_ancestor_of(psch, ptab, csch, ctab2, desc) should pass ok 107 - is_ancestor_of(psch, ptab, csch, ctab2, desc) should have the proper description ok 108 - is_ancestor_of(psch, ptab, csch, ctab2, desc) should have the proper diagnostics ok 109 - is_ancestor_of(psch, ptab, csch, ctab) should pass ok 110 - is_ancestor_of(psch, ptab, csch, ctab) should have the proper description ok 111 - is_ancestor_of(psch, ptab, csch, ctab) should have the proper diagnostics ok 112 - is_ancestor_of(psch, ptab, csch, ctab2) should pass ok 113 - is_ancestor_of(psch, ptab, csch, ctab2) should have the proper description ok 114 - is_ancestor_of(psch, ptab, csch, ctab2) should have the proper diagnostics ok 115 - is_ancestor_of(psch, nope, csch, ctab) should fail ok 116 - is_ancestor_of(psch, nope, csch, ctab) should have the proper description ok 117 - is_ancestor_of(psch, nope, csch, ctab) should have the proper diagnostics ok 118 - is_ancestor_of(psch, ptab, csch, nope) should fail ok 119 - is_ancestor_of(psch, ptab, csch, nope) should have the proper description ok 120 - is_ancestor_of(psch, ptab, csch, nope) should have the proper diagnostics ok 121 - is_ancestor_of(ptab, ctab, 1, desc) should pass ok 122 - is_ancestor_of(ptab, ctab, 1, desc) should have the proper description ok 123 - is_ancestor_of(ptab, ctab, 1, desc) should have the proper diagnostics ok 124 - is_ancestor_of(ptab, ctab, 2, desc) should pass ok 125 - is_ancestor_of(ptab, ctab, 2, desc) should have the proper description ok 126 - is_ancestor_of(ptab, ctab, 2, desc) should have the proper diagnostics ok 127 - is_ancestor_of(ptab, ctab, 1, desc) fail should fail ok 128 - is_ancestor_of(ptab, ctab, 1, desc) fail should have the proper description ok 129 - is_ancestor_of(ptab, ctab, 1, desc) fail should have the proper diagnostics ok 130 - is_ancestor_of(ptab, nope, 1, desc) should fail ok 131 - is_ancestor_of(ptab, nope, 1, desc) should have the proper description ok 132 - is_ancestor_of(ptab, nope, 1, desc) should have the proper diagnostics ok 133 - is_ancestor_of(ptab, ctab, 1) should pass ok 134 - is_ancestor_of(ptab, ctab, 1) should have the proper description ok 135 - is_ancestor_of(ptab, ctab, 1) should have the proper diagnostics ok 136 - is_ancestor_of(ptab, ctab, 2) should pass ok 137 - is_ancestor_of(ptab, ctab, 2) should have the proper description ok 138 - is_ancestor_of(ptab, ctab, 2) should have the proper diagnostics ok 139 - is_ancestor_of(ptab, ctab, 1) fail should fail ok 140 - is_ancestor_of(ptab, ctab, 1) fail should have the proper description ok 141 - is_ancestor_of(ptab, ctab, 1) fail should have the proper diagnostics ok 142 - is_ancestor_of(ptab, nope, 1) should fail ok 143 - is_ancestor_of(ptab, nope, 1) should have the proper description ok 144 - is_ancestor_of(ptab, nope, 1) should have the proper diagnostics ok 145 - is_ancestor_of(ptab, ctab) should pass ok 146 - is_ancestor_of(ptab, ctab) should have the proper description ok 147 - is_ancestor_of(ptab, ctab) should have the proper diagnostics ok 148 - is_ancestor_of(ptab, ctab2) should pass ok 149 - is_ancestor_of(ptab, ctab2) should have the proper description ok 150 - is_ancestor_of(ptab, ctab2) should have the proper diagnostics ok 151 - is_ancestor_of(ptab, nope) should fail ok 152 - is_ancestor_of(ptab, nope) should have the proper description ok 153 - is_ancestor_of(ptab, nope) should have the proper diagnostics ok 154 - is_ancestor_of(nope, ctab2) should fail ok 155 - is_ancestor_of(nope, ctab2) should have the proper description ok 156 - is_ancestor_of(nope, ctab2) should have the proper diagnostics ok 157 - isnt_ancestor_of(psch, ptab, csch, ctab, 1, desc) should fail ok 158 - isnt_ancestor_of(psch, ptab, csch, ctab, 1, desc) should have the proper description ok 159 - isnt_ancestor_of(psch, ptab, csch, ctab, 1, desc) should have the proper diagnostics ok 160 - isnt_ancestor_of(psch, ptab, csch, ctab, 2, desc) should fail ok 161 - isnt_ancestor_of(psch, ptab, csch, ctab, 2, desc) should have the proper description ok 162 - isnt_ancestor_of(psch, ptab, csch, ctab, 2, desc) should have the proper diagnostics ok 163 - isnt_ancestor_of(psch, nope, csch, ctab, 1, desc) should pass ok 164 - isnt_ancestor_of(psch, nope, csch, ctab, 1, desc) should have the proper description ok 165 - isnt_ancestor_of(psch, nope, csch, ctab, 1, desc) should have the proper diagnostics ok 166 - isnt_ancestor_of(psch, ptab, csch, nope, desc) should pass ok 167 - isnt_ancestor_of(psch, ptab, csch, nope, desc) should have the proper description ok 168 - isnt_ancestor_of(psch, ptab, csch, nope, desc) should have the proper diagnostics ok 169 - isnt_ancestor_of(psch, ptab, csch, ctab, 1) should fail ok 170 - isnt_ancestor_of(psch, ptab, csch, ctab, 1) should have the proper description ok 171 - isnt_ancestor_of(psch, ptab, csch, ctab, 1) should have the proper diagnostics ok 172 - isnt_ancestor_of(psch, nope, csch, ctab, 1) should pass ok 173 - isnt_ancestor_of(psch, nope, csch, ctab, 1) should have the proper description ok 174 - isnt_ancestor_of(psch, nope, csch, ctab, 1) should have the proper diagnostics ok 175 - isnt_ancestor_of(psch, ptab, csch, nope, 1) should pass ok 176 - isnt_ancestor_of(psch, ptab, csch, nope, 1) should have the proper description ok 177 - isnt_ancestor_of(psch, ptab, csch, nope, 1) should have the proper diagnostics ok 178 - isnt_ancestor_of(psch, ptab, csch, ctab, 2) should fail ok 179 - isnt_ancestor_of(psch, ptab, csch, ctab, 2) should have the proper description ok 180 - isnt_ancestor_of(psch, ptab, csch, ctab, 2) should have the proper diagnostics ok 181 - isnt_ancestor_of(psch, nope, csch, ctab, 2) should pass ok 182 - isnt_ancestor_of(psch, nope, csch, ctab, 2) should have the proper description ok 183 - isnt_ancestor_of(psch, nope, csch, ctab, 2) should have the proper diagnostics ok 184 - isnt_ancestor_of(psch, ptab, csch, nope, 2) should pass ok 185 - isnt_ancestor_of(psch, ptab, csch, nope, 2) should have the proper description ok 186 - isnt_ancestor_of(psch, ptab, csch, nope, 2) should have the proper diagnostics ok 187 - isnt_ancestor_of(psch, ptab, csch, ctab, desc) should fail ok 188 - isnt_ancestor_of(psch, ptab, csch, ctab, desc) should have the proper description ok 189 - isnt_ancestor_of(psch, ptab, csch, ctab, desc) should have the proper diagnostics ok 190 - isnt_ancestor_of(psch, ptab, csch, ctab2, desc) should fail ok 191 - isnt_ancestor_of(psch, ptab, csch, ctab2, desc) should have the proper description ok 192 - isnt_ancestor_of(psch, ptab, csch, ctab2, desc) should have the proper diagnostics ok 193 - isnt_ancestor_of(psch, ptab, csch, ctab) should fail ok 194 - isnt_ancestor_of(psch, ptab, csch, ctab) should have the proper description ok 195 - isnt_ancestor_of(psch, ptab, csch, ctab) should have the proper diagnostics ok 196 - isnt_ancestor_of(psch, ptab, csch, ctab2) should fail ok 197 - isnt_ancestor_of(psch, ptab, csch, ctab2) should have the proper description ok 198 - isnt_ancestor_of(psch, ptab, csch, ctab2) should have the proper diagnostics ok 199 - isnt_ancestor_of(psch, nope, csch, ctab) should pass ok 200 - isnt_ancestor_of(psch, nope, csch, ctab) should have the proper description ok 201 - isnt_ancestor_of(psch, nope, csch, ctab) should have the proper diagnostics ok 202 - isnt_ancestor_of(psch, ptab, csch, nope) should pass ok 203 - isnt_ancestor_of(psch, ptab, csch, nope) should have the proper description ok 204 - isnt_ancestor_of(psch, ptab, csch, nope) should have the proper diagnostics ok 205 - isnt_ancestor_of(ptab, ctab, 1, desc) should fail ok 206 - isnt_ancestor_of(ptab, ctab, 1, desc) should have the proper description ok 207 - isnt_ancestor_of(ptab, ctab, 1, desc) should have the proper diagnostics ok 208 - isnt_ancestor_of(ptab, ctab, 2, desc) should fail ok 209 - isnt_ancestor_of(ptab, ctab, 2, desc) should have the proper description ok 210 - isnt_ancestor_of(ptab, ctab, 2, desc) should have the proper diagnostics ok 211 - isnt_ancestor_of(ptab, ctab, 1, desc) fail should pass ok 212 - isnt_ancestor_of(ptab, ctab, 1, desc) fail should have the proper description ok 213 - isnt_ancestor_of(ptab, ctab, 1, desc) fail should have the proper diagnostics ok 214 - isnt_ancestor_of(ptab, nope, 1, desc) should pass ok 215 - isnt_ancestor_of(ptab, nope, 1, desc) should have the proper description ok 216 - isnt_ancestor_of(ptab, nope, 1, desc) should have the proper diagnostics ok 217 - isnt_ancestor_of(ptab, ctab, 1) should fail ok 218 - isnt_ancestor_of(ptab, ctab, 1) should have the proper description ok 219 - isnt_ancestor_of(ptab, ctab, 1) should have the proper diagnostics ok 220 - isnt_ancestor_of(ptab, ctab, 2) should fail ok 221 - isnt_ancestor_of(ptab, ctab, 2) should have the proper description ok 222 - isnt_ancestor_of(ptab, ctab, 2) should have the proper diagnostics ok 223 - isnt_ancestor_of(ptab, ctab, 1) fail should pass ok 224 - isnt_ancestor_of(ptab, ctab, 1) fail should have the proper description ok 225 - isnt_ancestor_of(ptab, ctab, 1) fail should have the proper diagnostics ok 226 - isnt_ancestor_of(ptab, nope, 1) should pass ok 227 - isnt_ancestor_of(ptab, nope, 1) should have the proper description ok 228 - isnt_ancestor_of(ptab, nope, 1) should have the proper diagnostics ok 229 - isnt_ancestor_of(ptab, ctab) should fail ok 230 - isnt_ancestor_of(ptab, ctab) should have the proper description ok 231 - isnt_ancestor_of(ptab, ctab) should have the proper diagnostics ok 232 - isnt_ancestor_of(ptab, ctab2) should fail ok 233 - isnt_ancestor_of(ptab, ctab2) should have the proper description ok 234 - isnt_ancestor_of(ptab, ctab2) should have the proper diagnostics ok 235 - isnt_ancestor_of(ptab, nope) should pass ok 236 - isnt_ancestor_of(ptab, nope) should have the proper description ok 237 - isnt_ancestor_of(ptab, nope) should have the proper diagnostics ok 238 - isnt_ancestor_of(nope, ctab2) should pass ok 239 - isnt_ancestor_of(nope, ctab2) should have the proper description ok 240 - isnt_ancestor_of(nope, ctab2) should have the proper diagnostics ok 241 - is_descendent_of(csch, ctab, psch, ptab, 1, desc) should pass ok 242 - is_descendent_of(csch, ctab, psch, ptab, 1, desc) should have the proper description ok 243 - is_descendent_of(csch, ctab, psch, ptab, 1, desc) should have the proper diagnostics ok 244 - is_descendent_of(csch, ctab, psch, ptab, 2, desc) should pass ok 245 - is_descendent_of(csch, ctab, psch, ptab, 2, desc) should have the proper description ok 246 - is_descendent_of(csch, ctab, psch, ptab, 2, desc) should have the proper diagnostics ok 247 - is_descendent_of(csch, ctab, psch, nope, 1, desc) should fail ok 248 - is_descendent_of(csch, ctab, psch, nope, 1, desc) should have the proper description ok 249 - is_descendent_of(csch, ctab, psch, nope, 1, desc) should have the proper diagnostics ok 250 - is_descendent_of(csch, nope, psch, ptab, desc) should fail ok 251 - is_descendent_of(csch, nope, psch, ptab, desc) should have the proper description ok 252 - is_descendent_of(csch, nope, psch, ptab, desc) should have the proper diagnostics ok 253 - is_descendent_of(csch, ctab, psch, ptab, 1) should pass ok 254 - is_descendent_of(csch, ctab, psch, ptab, 1) should have the proper description ok 255 - is_descendent_of(csch, ctab, psch, ptab, 1) should have the proper diagnostics ok 256 - is_descendent_of(csch, ctab, psch, nope, 1) should fail ok 257 - is_descendent_of(csch, ctab, psch, nope, 1) should have the proper description ok 258 - is_descendent_of(csch, ctab, psch, nope, 1) should have the proper diagnostics ok 259 - is_descendent_of(csch, nope, psch, ptab, 1) should fail ok 260 - is_descendent_of(csch, nope, psch, ptab, 1) should have the proper description ok 261 - is_descendent_of(csch, nope, psch, ptab, 1) should have the proper diagnostics ok 262 - is_descendent_of(csch, ctab, psch, ptab, 2) should pass ok 263 - is_descendent_of(csch, ctab, psch, ptab, 2) should have the proper description ok 264 - is_descendent_of(csch, ctab, psch, ptab, 2) should have the proper diagnostics ok 265 - is_descendent_of(csch, ctab, psch, nope, 2) should fail ok 266 - is_descendent_of(csch, ctab, psch, nope, 2) should have the proper description ok 267 - is_descendent_of(csch, ctab, psch, nope, 2) should have the proper diagnostics ok 268 - is_descendent_of(csch, nope, psch, ptab, 2) should fail ok 269 - is_descendent_of(csch, nope, psch, ptab, 2) should have the proper description ok 270 - is_descendent_of(csch, nope, psch, ptab, 2) should have the proper diagnostics ok 271 - is_descendent_of(csch, ctab, psch, ptab, desc) should pass ok 272 - is_descendent_of(csch, ctab, psch, ptab, desc) should have the proper description ok 273 - is_descendent_of(csch, ctab, psch, ptab, desc) should have the proper diagnostics ok 274 - is_descendent_of(csch, ctab2, psch, ptab, desc) should pass ok 275 - is_descendent_of(csch, ctab2, psch, ptab, desc) should have the proper description ok 276 - is_descendent_of(csch, ctab2, psch, ptab, desc) should have the proper diagnostics ok 277 - is_descendent_of(csch, ctab, psch, ptab) should pass ok 278 - is_descendent_of(csch, ctab, psch, ptab) should have the proper description ok 279 - is_descendent_of(csch, ctab, psch, ptab) should have the proper diagnostics ok 280 - is_descendent_of(csch, ctab2, psch, ptab) should pass ok 281 - is_descendent_of(csch, ctab2, psch, ptab) should have the proper description ok 282 - is_descendent_of(csch, ctab2, psch, ptab) should have the proper diagnostics ok 283 - is_descendent_of(csch, ctab, psch, nope) should fail ok 284 - is_descendent_of(csch, ctab, psch, nope) should have the proper description ok 285 - is_descendent_of(csch, ctab, psch, nope) should have the proper diagnostics ok 286 - is_descendent_of(csch, nope, psch, ptab) should fail ok 287 - is_descendent_of(csch, nope, psch, ptab) should have the proper description ok 288 - is_descendent_of(csch, nope, psch, ptab) should have the proper diagnostics ok 289 - is_descendent_of(ctab, ptab, 1, desc) should pass ok 290 - is_descendent_of(ctab, ptab, 1, desc) should have the proper description ok 291 - is_descendent_of(ctab, ptab, 1, desc) should have the proper diagnostics ok 292 - is_descendent_of(ctab, ptab, 2, desc) should pass ok 293 - is_descendent_of(ctab, ptab, 2, desc) should have the proper description ok 294 - is_descendent_of(ctab, ptab, 2, desc) should have the proper diagnostics ok 295 - is_descendent_of(ctab, ptab, 1, desc) fail should fail ok 296 - is_descendent_of(ctab, ptab, 1, desc) fail should have the proper description ok 297 - is_descendent_of(ctab, ptab, 1, desc) fail should have the proper diagnostics ok 298 - is_descendent_of(nope, ptab, 1, desc) should fail ok 299 - is_descendent_of(nope, ptab, 1, desc) should have the proper description ok 300 - is_descendent_of(nope, ptab, 1, desc) should have the proper diagnostics ok 301 - is_descendent_of(ctab, ptab, 1) should pass ok 302 - is_descendent_of(ctab, ptab, 1) should have the proper description ok 303 - is_descendent_of(ctab, ptab, 1) should have the proper diagnostics ok 304 - is_descendent_of(ctab, ptab, 2) should pass ok 305 - is_descendent_of(ctab, ptab, 2) should have the proper description ok 306 - is_descendent_of(ctab, ptab, 2) should have the proper diagnostics ok 307 - is_descendent_of(ctab, ptab, 1) fail should fail ok 308 - is_descendent_of(ctab, ptab, 1) fail should have the proper description ok 309 - is_descendent_of(ctab, ptab, 1) fail should have the proper diagnostics ok 310 - is_descendent_of(nope, ptab, 1) should fail ok 311 - is_descendent_of(nope, ptab, 1) should have the proper description ok 312 - is_descendent_of(nope, ptab, 1) should have the proper diagnostics ok 313 - is_descendent_of(ctab, ptab) should pass ok 314 - is_descendent_of(ctab, ptab) should have the proper description ok 315 - is_descendent_of(ctab, ptab) should have the proper diagnostics ok 316 - is_descendent_of( ctab2, ptab ) should pass ok 317 - is_descendent_of( ctab2, ptab ) should have the proper description ok 318 - is_descendent_of( ctab2, ptab ) should have the proper diagnostics ok 319 - is_descendent_of(nope, ptab) should fail ok 320 - is_descendent_of(nope, ptab) should have the proper description ok 321 - is_descendent_of(nope, ptab) should have the proper diagnostics ok 322 - is_descendent_of(ctab2, nope) should fail ok 323 - is_descendent_of(ctab2, nope) should have the proper description ok 324 - is_descendent_of(ctab2, nope) should have the proper diagnostics ok 325 - isnt_descendent_of(csch, ctab, psch, ptab, 1, desc) should fail ok 326 - isnt_descendent_of(csch, ctab, psch, ptab, 1, desc) should have the proper description ok 327 - isnt_descendent_of(csch, ctab, psch, ptab, 1, desc) should have the proper diagnostics ok 328 - isnt_descendent_of(csch, ctab, psch, ptab, 2, desc) should fail ok 329 - isnt_descendent_of(csch, ctab, psch, ptab, 2, desc) should have the proper description ok 330 - isnt_descendent_of(csch, ctab, psch, ptab, 2, desc) should have the proper diagnostics ok 331 - isnt_descendent_of(csch, ctab, psch, nope, 1, desc) should pass ok 332 - isnt_descendent_of(csch, ctab, psch, nope, 1, desc) should have the proper description ok 333 - isnt_descendent_of(csch, ctab, psch, nope, 1, desc) should have the proper diagnostics ok 334 - isnt_descendent_of(csch, nope, psch, ptab, desc) should pass ok 335 - isnt_descendent_of(csch, nope, psch, ptab, desc) should have the proper description ok 336 - isnt_descendent_of(csch, nope, psch, ptab, desc) should have the proper diagnostics ok 337 - isnt_descendent_of(csch, ctab, psch, ptab, 1) should fail ok 338 - isnt_descendent_of(csch, ctab, psch, ptab, 1) should have the proper description ok 339 - isnt_descendent_of(csch, ctab, psch, ptab, 1) should have the proper diagnostics ok 340 - isnt_descendent_of(csch, ctab, psch, nope, 1) should pass ok 341 - isnt_descendent_of(csch, ctab, psch, nope, 1) should have the proper description ok 342 - isnt_descendent_of(csch, ctab, psch, nope, 1) should have the proper diagnostics ok 343 - isnt_descendent_of(csch, nope, psch, ptab, 1) should pass ok 344 - isnt_descendent_of(csch, nope, psch, ptab, 1) should have the proper description ok 345 - isnt_descendent_of(csch, nope, psch, ptab, 1) should have the proper diagnostics ok 346 - isnt_descendent_of(csch, ctab, psch, ptab, 2) should fail ok 347 - isnt_descendent_of(csch, ctab, psch, ptab, 2) should have the proper description ok 348 - isnt_descendent_of(csch, ctab, psch, ptab, 2) should have the proper diagnostics ok 349 - isnt_descendent_of(csch, ctab, psch, nope, 2) should pass ok 350 - isnt_descendent_of(csch, ctab, psch, nope, 2) should have the proper description ok 351 - isnt_descendent_of(csch, ctab, psch, nope, 2) should have the proper diagnostics ok 352 - isnt_descendent_of(csch, nope, psch, ptab, 2) should pass ok 353 - isnt_descendent_of(csch, nope, psch, ptab, 2) should have the proper description ok 354 - isnt_descendent_of(csch, nope, psch, ptab, 2) should have the proper diagnostics ok 355 - isnt_descendent_of(csch, ctab, psch, ptab, desc) should fail ok 356 - isnt_descendent_of(csch, ctab, psch, ptab, desc) should have the proper description ok 357 - isnt_descendent_of(csch, ctab, psch, ptab, desc) should have the proper diagnostics ok 358 - isnt_descendent_of(csch, ctab2, psch, ptab, desc) should fail ok 359 - isnt_descendent_of(csch, ctab2, psch, ptab, desc) should have the proper description ok 360 - isnt_descendent_of(csch, ctab2, psch, ptab, desc) should have the proper diagnostics ok 361 - isnt_descendent_of(csch, ctab, psch, ptab) should fail ok 362 - isnt_descendent_of(csch, ctab, psch, ptab) should have the proper description ok 363 - isnt_descendent_of(csch, ctab, psch, ptab) should have the proper diagnostics ok 364 - isnt_descendent_of(csch, ctab2, psch, ptab) should fail ok 365 - isnt_descendent_of(csch, ctab2, psch, ptab) should have the proper description ok 366 - isnt_descendent_of(csch, ctab2, psch, ptab) should have the proper diagnostics ok 367 - isnt_descendent_of(csch, ctab, psch, nope) should pass ok 368 - isnt_descendent_of(csch, ctab, psch, nope) should have the proper description ok 369 - isnt_descendent_of(csch, ctab, psch, nope) should have the proper diagnostics ok 370 - isnt_descendent_of(csch, nope, psch, ptab) should pass ok 371 - isnt_descendent_of(csch, nope, psch, ptab) should have the proper description ok 372 - isnt_descendent_of(csch, nope, psch, ptab) should have the proper diagnostics ok 373 - isnt_descendent_of(ctab, ptab, 1, desc) should fail ok 374 - isnt_descendent_of(ctab, ptab, 1, desc) should have the proper description ok 375 - isnt_descendent_of(ctab, ptab, 1, desc) should have the proper diagnostics ok 376 - isnt_descendent_of(ctab, ptab, 2, desc) should fail ok 377 - isnt_descendent_of(ctab, ptab, 2, desc) should have the proper description ok 378 - isnt_descendent_of(ctab, ptab, 2, desc) should have the proper diagnostics ok 379 - isnt_descendent_of(ctab, ptab, 1, desc) fail should pass ok 380 - isnt_descendent_of(ctab, ptab, 1, desc) fail should have the proper description ok 381 - isnt_descendent_of(ctab, ptab, 1, desc) fail should have the proper diagnostics ok 382 - isnt_descendent_of(nope, ptab, 1, desc) should pass ok 383 - isnt_descendent_of(nope, ptab, 1, desc) should have the proper description ok 384 - isnt_descendent_of(nope, ptab, 1, desc) should have the proper diagnostics ok 385 - isnt_descendent_of(ctab, ptab, 1) should fail ok 386 - isnt_descendent_of(ctab, ptab, 1) should have the proper description ok 387 - isnt_descendent_of(ctab, ptab, 1) should have the proper diagnostics ok 388 - isnt_descendent_of(ctab, ptab, 2) should fail ok 389 - isnt_descendent_of(ctab, ptab, 2) should have the proper description ok 390 - isnt_descendent_of(ctab, ptab, 2) should have the proper diagnostics ok 391 - isnt_descendent_of(ctab, ptab, 1) fail should pass ok 392 - isnt_descendent_of(ctab, ptab, 1) fail should have the proper description ok 393 - isnt_descendent_of(ctab, ptab, 1) fail should have the proper diagnostics ok 394 - isnt_descendent_of(nope, ptab, 1) should pass ok 395 - isnt_descendent_of(nope, ptab, 1) should have the proper description ok 396 - isnt_descendent_of(nope, ptab, 1) should have the proper diagnostics ok 397 - isnt_descendent_of(ctab, ptab) should fail ok 398 - isnt_descendent_of(ctab, ptab) should have the proper description ok 399 - isnt_descendent_of(ctab, ptab) should have the proper diagnostics ok 400 - isnt_descendent_of( ctab2, ptab ) should fail ok 401 - isnt_descendent_of( ctab2, ptab ) should have the proper description ok 402 - isnt_descendent_of( ctab2, ptab ) should have the proper diagnostics ok 403 - isnt_descendent_of(nope, ptab) should pass ok 404 - isnt_descendent_of(nope, ptab) should have the proper description ok 405 - isnt_descendent_of(nope, ptab) should have the proper diagnostics ok 406 - isnt_descendent_of(ctab2, nope) should pass ok 407 - isnt_descendent_of(ctab2, nope) should have the proper description ok 408 - isnt_descendent_of(ctab2, nope) should have the proper diagnostics pgtap-1.3.2/test/expected/inheritance_1.out000066400000000000000000000124621455775703000206740ustar00rootroot00000000000000\unset ECHO 1..408 ok 1 - has_inherited_tables(sch, tab, desc) should pass ok 2 - has_inherited_tables(sch, tab, desc) should have the proper description ok 3 - has_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 4 - has_inherited_tables(sch, tab, desc) fail should fail ok 5 - has_inherited_tables(sch, tab, desc) fail should have the proper description ok 6 - has_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 7 - has_inherited_tables(sch, nonesuch, desc) should fail ok 8 - has_inherited_tables(sch, nonesuch, desc) should have the proper description ok 9 - has_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 10 - has_inherited_tables(sch, tab) should pass ok 11 - has_inherited_tables(sch, tab) should have the proper description ok 12 - has_inherited_tables(sch, tab) should have the proper diagnostics ok 13 - has_inherited_tables(sch, tab) fail should fail ok 14 - has_inherited_tables(sch, tab) fail should have the proper description ok 15 - has_inherited_tables(sch, tab) fail should have the proper diagnostics ok 16 - has_inherited_tables(sch, nonesuch) should fail ok 17 - has_inherited_tables(sch, nonesuch) should have the proper description ok 18 - has_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 19 - has_inherited_tables(tab, desc) should pass ok 20 - has_inherited_tables(tab, desc) should have the proper description ok 21 - has_inherited_tables(tab, desc) should have the proper diagnostics ok 22 - has_inherited_tables(tab, desc) fail should fail ok 23 - has_inherited_tables(tab, desc) fail should have the proper description ok 24 - has_inherited_tables(tab, desc) fail should have the proper diagnostics ok 25 - has_inherited_tables(nonesuch, desc) should fail ok 26 - has_inherited_tables(nonesuch, desc) should have the proper description ok 27 - has_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 28 - has_inherited_tables(tab) should pass ok 29 - has_inherited_tables(tab) should have the proper description ok 30 - has_inherited_tables(tab) should have the proper diagnostics ok 31 - has_inherited_tables(tab) fail should fail ok 32 - has_inherited_tables(tab) fail should have the proper description ok 33 - has_inherited_tables(tab) fail should have the proper diagnostics ok 34 - has_inherited_tables(nonesuch) should fail ok 35 - has_inherited_tables(nonesuch) should have the proper description ok 36 - has_inherited_tables(nonesuch) should have the proper diagnostics ok 37 - hasnt_inherited_tables(sch, tab, desc) should pass ok 38 - hasnt_inherited_tables(sch, tab, desc) should have the proper description ok 39 - hasnt_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 40 - hasnt_inherited_tables(sch, tab, desc) fail should fail ok 41 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper description ok 42 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 43 - hasnt_inherited_tables(sch, nonesuch, desc) should pass ok 44 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper description ok 45 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 46 - hasnt_inherited_tables(sch, tab) should pass ok 47 - hasnt_inherited_tables(sch, tab) should have the proper description ok 48 - hasnt_inherited_tables(sch, tab) should have the proper diagnostics ok 49 - hasnt_inherited_tables(sch, tab) fail should fail ok 50 - hasnt_inherited_tables(sch, tab) fail should have the proper description ok 51 - hasnt_inherited_tables(sch, tab) fail should have the proper diagnostics ok 52 - hasnt_inherited_tables(sch, nonesuch) should pass ok 53 - hasnt_inherited_tables(sch, nonesuch) should have the proper description ok 54 - hasnt_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 55 - hasnt_inherited_tables(tab, desc) should pass ok 56 - hasnt_inherited_tables(tab, desc) should have the proper description ok 57 - hasnt_inherited_tables(tab, desc) should have the proper diagnostics ok 58 - hasnt_inherited_tables(tab, desc) fail should fail ok 59 - hasnt_inherited_tables(tab, desc) fail should have the proper description ok 60 - hasnt_inherited_tables(tab, desc) fail should have the proper diagnostics ok 61 - hasnt_inherited_tables(nonesuch, desc) should pass ok 62 - hasnt_inherited_tables(nonesuch, desc) should have the proper description ok 63 - hasnt_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 64 - hasnt_inherited_tables(tab) should pass ok 65 - hasnt_inherited_tables(tab) should have the proper description ok 66 - hasnt_inherited_tables(tab) should have the proper diagnostics ok 67 - hasnt_inherited_tables(tab) fail should fail ok 68 - hasnt_inherited_tables(tab) fail should have the proper description ok 69 - hasnt_inherited_tables(tab) fail should have the proper diagnostics ok 70 - hasnt_inherited_tables(nonesuch) should pass ok 71 - hasnt_inherited_tables(nonesuch) should have the proper description ok 72 - hasnt_inherited_tables(nonesuch) should have the proper diagnostics ERROR: function is_ancestor_of(unknown, unknown, unknown, unknown, integer, unknown) does not exist LINE 2: is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', ... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. pgtap-1.3.2/test/expected/inheritance_2.out000066400000000000000000000124721455775703000206760ustar00rootroot00000000000000\unset ECHO 1..408 ok 1 - has_inherited_tables(sch, tab, desc) should pass ok 2 - has_inherited_tables(sch, tab, desc) should have the proper description ok 3 - has_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 4 - has_inherited_tables(sch, tab, desc) fail should fail ok 5 - has_inherited_tables(sch, tab, desc) fail should have the proper description ok 6 - has_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 7 - has_inherited_tables(sch, nonesuch, desc) should fail ok 8 - has_inherited_tables(sch, nonesuch, desc) should have the proper description ok 9 - has_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 10 - has_inherited_tables(sch, tab) should pass ok 11 - has_inherited_tables(sch, tab) should have the proper description ok 12 - has_inherited_tables(sch, tab) should have the proper diagnostics ok 13 - has_inherited_tables(sch, tab) fail should fail ok 14 - has_inherited_tables(sch, tab) fail should have the proper description ok 15 - has_inherited_tables(sch, tab) fail should have the proper diagnostics ok 16 - has_inherited_tables(sch, nonesuch) should fail ok 17 - has_inherited_tables(sch, nonesuch) should have the proper description ok 18 - has_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 19 - has_inherited_tables(tab, desc) should pass ok 20 - has_inherited_tables(tab, desc) should have the proper description ok 21 - has_inherited_tables(tab, desc) should have the proper diagnostics ok 22 - has_inherited_tables(tab, desc) fail should fail ok 23 - has_inherited_tables(tab, desc) fail should have the proper description ok 24 - has_inherited_tables(tab, desc) fail should have the proper diagnostics ok 25 - has_inherited_tables(nonesuch, desc) should fail ok 26 - has_inherited_tables(nonesuch, desc) should have the proper description ok 27 - has_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 28 - has_inherited_tables(tab) should pass ok 29 - has_inherited_tables(tab) should have the proper description ok 30 - has_inherited_tables(tab) should have the proper diagnostics ok 31 - has_inherited_tables(tab) fail should fail ok 32 - has_inherited_tables(tab) fail should have the proper description ok 33 - has_inherited_tables(tab) fail should have the proper diagnostics ok 34 - has_inherited_tables(nonesuch) should fail ok 35 - has_inherited_tables(nonesuch) should have the proper description ok 36 - has_inherited_tables(nonesuch) should have the proper diagnostics ok 37 - hasnt_inherited_tables(sch, tab, desc) should pass ok 38 - hasnt_inherited_tables(sch, tab, desc) should have the proper description ok 39 - hasnt_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 40 - hasnt_inherited_tables(sch, tab, desc) fail should fail ok 41 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper description ok 42 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 43 - hasnt_inherited_tables(sch, nonesuch, desc) should pass ok 44 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper description ok 45 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 46 - hasnt_inherited_tables(sch, tab) should pass ok 47 - hasnt_inherited_tables(sch, tab) should have the proper description ok 48 - hasnt_inherited_tables(sch, tab) should have the proper diagnostics ok 49 - hasnt_inherited_tables(sch, tab) fail should fail ok 50 - hasnt_inherited_tables(sch, tab) fail should have the proper description ok 51 - hasnt_inherited_tables(sch, tab) fail should have the proper diagnostics ok 52 - hasnt_inherited_tables(sch, nonesuch) should pass ok 53 - hasnt_inherited_tables(sch, nonesuch) should have the proper description ok 54 - hasnt_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 55 - hasnt_inherited_tables(tab, desc) should pass ok 56 - hasnt_inherited_tables(tab, desc) should have the proper description ok 57 - hasnt_inherited_tables(tab, desc) should have the proper diagnostics ok 58 - hasnt_inherited_tables(tab, desc) fail should fail ok 59 - hasnt_inherited_tables(tab, desc) fail should have the proper description ok 60 - hasnt_inherited_tables(tab, desc) fail should have the proper diagnostics ok 61 - hasnt_inherited_tables(nonesuch, desc) should pass ok 62 - hasnt_inherited_tables(nonesuch, desc) should have the proper description ok 63 - hasnt_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 64 - hasnt_inherited_tables(tab) should pass ok 65 - hasnt_inherited_tables(tab) should have the proper description ok 66 - hasnt_inherited_tables(tab) should have the proper diagnostics ok 67 - hasnt_inherited_tables(tab) fail should fail ok 68 - hasnt_inherited_tables(tab) fail should have the proper description ok 69 - hasnt_inherited_tables(tab) fail should have the proper diagnostics ok 70 - hasnt_inherited_tables(nonesuch) should pass ok 71 - hasnt_inherited_tables(nonesuch) should have the proper description ok 72 - hasnt_inherited_tables(nonesuch) should have the proper diagnostics ERROR: function is_ancestor_of("unknown", "unknown", "unknown", "unknown", integer, "unknown") does not exist LINE 2: is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', ... ^ HINT: No function matches the given name and argument types. You may need to add explicit type casts. pgtap-1.3.2/test/expected/inheritance_3.out000066400000000000000000000123441455775703000206750ustar00rootroot00000000000000\unset ECHO 1..408 ok 1 - has_inherited_tables(sch, tab, desc) should pass ok 2 - has_inherited_tables(sch, tab, desc) should have the proper description ok 3 - has_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 4 - has_inherited_tables(sch, tab, desc) fail should fail ok 5 - has_inherited_tables(sch, tab, desc) fail should have the proper description ok 6 - has_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 7 - has_inherited_tables(sch, nonesuch, desc) should fail ok 8 - has_inherited_tables(sch, nonesuch, desc) should have the proper description ok 9 - has_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 10 - has_inherited_tables(sch, tab) should pass ok 11 - has_inherited_tables(sch, tab) should have the proper description ok 12 - has_inherited_tables(sch, tab) should have the proper diagnostics ok 13 - has_inherited_tables(sch, tab) fail should fail ok 14 - has_inherited_tables(sch, tab) fail should have the proper description ok 15 - has_inherited_tables(sch, tab) fail should have the proper diagnostics ok 16 - has_inherited_tables(sch, nonesuch) should fail ok 17 - has_inherited_tables(sch, nonesuch) should have the proper description ok 18 - has_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 19 - has_inherited_tables(tab, desc) should pass ok 20 - has_inherited_tables(tab, desc) should have the proper description ok 21 - has_inherited_tables(tab, desc) should have the proper diagnostics ok 22 - has_inherited_tables(tab, desc) fail should fail ok 23 - has_inherited_tables(tab, desc) fail should have the proper description ok 24 - has_inherited_tables(tab, desc) fail should have the proper diagnostics ok 25 - has_inherited_tables(nonesuch, desc) should fail ok 26 - has_inherited_tables(nonesuch, desc) should have the proper description ok 27 - has_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 28 - has_inherited_tables(tab) should pass ok 29 - has_inherited_tables(tab) should have the proper description ok 30 - has_inherited_tables(tab) should have the proper diagnostics ok 31 - has_inherited_tables(tab) fail should fail ok 32 - has_inherited_tables(tab) fail should have the proper description ok 33 - has_inherited_tables(tab) fail should have the proper diagnostics ok 34 - has_inherited_tables(nonesuch) should fail ok 35 - has_inherited_tables(nonesuch) should have the proper description ok 36 - has_inherited_tables(nonesuch) should have the proper diagnostics ok 37 - hasnt_inherited_tables(sch, tab, desc) should pass ok 38 - hasnt_inherited_tables(sch, tab, desc) should have the proper description ok 39 - hasnt_inherited_tables(sch, tab, desc) should have the proper diagnostics ok 40 - hasnt_inherited_tables(sch, tab, desc) fail should fail ok 41 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper description ok 42 - hasnt_inherited_tables(sch, tab, desc) fail should have the proper diagnostics ok 43 - hasnt_inherited_tables(sch, nonesuch, desc) should pass ok 44 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper description ok 45 - hasnt_inherited_tables(sch, nonesuch, desc) should have the proper diagnostics ok 46 - hasnt_inherited_tables(sch, tab) should pass ok 47 - hasnt_inherited_tables(sch, tab) should have the proper description ok 48 - hasnt_inherited_tables(sch, tab) should have the proper diagnostics ok 49 - hasnt_inherited_tables(sch, tab) fail should fail ok 50 - hasnt_inherited_tables(sch, tab) fail should have the proper description ok 51 - hasnt_inherited_tables(sch, tab) fail should have the proper diagnostics ok 52 - hasnt_inherited_tables(sch, nonesuch) should pass ok 53 - hasnt_inherited_tables(sch, nonesuch) should have the proper description ok 54 - hasnt_inherited_tables(sch, nonesuch) should have the proper diagnostics ok 55 - hasnt_inherited_tables(tab, desc) should pass ok 56 - hasnt_inherited_tables(tab, desc) should have the proper description ok 57 - hasnt_inherited_tables(tab, desc) should have the proper diagnostics ok 58 - hasnt_inherited_tables(tab, desc) fail should fail ok 59 - hasnt_inherited_tables(tab, desc) fail should have the proper description ok 60 - hasnt_inherited_tables(tab, desc) fail should have the proper diagnostics ok 61 - hasnt_inherited_tables(nonesuch, desc) should pass ok 62 - hasnt_inherited_tables(nonesuch, desc) should have the proper description ok 63 - hasnt_inherited_tables(nonesuch, desc) should have the proper diagnostics ok 64 - hasnt_inherited_tables(tab) should pass ok 65 - hasnt_inherited_tables(tab) should have the proper description ok 66 - hasnt_inherited_tables(tab) should have the proper diagnostics ok 67 - hasnt_inherited_tables(tab) fail should fail ok 68 - hasnt_inherited_tables(tab) fail should have the proper description ok 69 - hasnt_inherited_tables(tab) fail should have the proper diagnostics ok 70 - hasnt_inherited_tables(nonesuch) should pass ok 71 - hasnt_inherited_tables(nonesuch) should have the proper description ok 72 - hasnt_inherited_tables(nonesuch) should have the proper diagnostics ERROR: function is_ancestor_of("unknown", "unknown", "unknown", "unknown", integer, "unknown") does not exist HINT: No function matches the given name and argument types. You may need to add explicit type casts. pgtap-1.3.2/test/expected/istap.out000066400000000000000000000044501455775703000173010ustar00rootroot00000000000000\unset ECHO 1..47 ok 1 - is(1, 1) should pass ok 2 - is(1, 1) should have the proper description ok 3 - is(1, 1) should have the proper diagnostics ok 4 - is('x', 'x') should pass ok 5 - is('x', 'x') should have the proper description ok 6 - is('x', 'x') should have the proper diagnostics ok 7 - is(1.1, 1.10) should pass ok 8 - is(1.1, 1.10) should have the proper description ok 9 - is(1.1, 1.10) should have the proper diagnostics ok 10 - is(true, true) should pass ok 11 - is(true, true) should have the proper description ok 12 - is(true, true) should have the proper diagnostics ok 13 - is(false, false) should pass ok 14 - is(false, false) should have the proper description ok 15 - is(false, false) should have the proper diagnostics ok 16 - is(1, 1, desc) should pass ok 17 - is(1, 1, desc) should have the proper description ok 18 - is(1, 1, desc) should have the proper diagnostics ok 19 - is(1, 2) should fail ok 20 - is(1, 2) should have the proper description ok 21 - is(1, 2) should have the proper diagnostics ok 22 - isnt(1, 2) should pass ok 23 - isnt(1, 2) should have the proper description ok 24 - isnt(1, 2) should have the proper diagnostics ok 25 - isnt(1, 1) should fail ok 26 - isnt(1, 1) should have the proper description ok 27 - isnt(1, 1) should have the proper diagnostics ok 28 - is() should work with psql variables ok 29 - is(NULL, NULL) should pass ok 30 - is(NULL, NULL) should have the proper description ok 31 - is(NULL, NULL) should have the proper diagnostics ok 32 - is(NULL, foo) should fail ok 33 - is(NULL, foo) should have the proper description ok 34 - is(NULL, foo) should have the proper diagnostics ok 35 - is(foo, NULL) should fail ok 36 - is(foo, NULL) should have the proper description ok 37 - is(foo, NULL) should have the proper diagnostics ok 38 - with records! ok 39 - is(mumble, row) fail should fail ok 40 - is(mumble, row) fail should have the proper description ok 41 - is(mumble, row) fail should have the proper diagnostics ok 42 - is(mumble, row) fail with NULL should fail ok 43 - is(mumble, row) fail with NULL should have the proper description ok 44 - is(mumble, row) fail with NULL should have the proper diagnostics ok 45 - is(mumble, NULL) should fail ok 46 - is(mumble, NULL) should have the proper description ok 47 - is(mumble, NULL) should have the proper diagnostics pgtap-1.3.2/test/expected/matching.out000066400000000000000000000021131455775703000177450ustar00rootroot00000000000000\unset ECHO 1..24 ok 1 - matches() should work ok 2 - matches() should work with a regex ok 3 - imatches() should work with a regex ok 4 - matches() fail should fail ok 5 - matches() fail should have the proper description ok 6 - matches() fail should have the proper diagnostics ok 7 - doesnt_match() should work ok 8 - doesnt_match() should work with a regex ok 9 - doesnt_imatch() should work with a regex ok 10 - doesnt_match() fail should fail ok 11 - doesnt_match() fail should have the proper description ok 12 - doesnt_match() fail should have the proper diagnostics ok 13 - alike() should work ok 14 - alike() should work with a regex ok 15 - ialike() should work with a regex ok 16 - alike() fail should fail ok 17 - alike() fail should have the proper description ok 18 - alike() fail should have the proper diagnostics ok 19 - unalike() should work ok 20 - unalike() should work with a regex ok 21 - iunalike() should work with a regex ok 22 - unalike() fail should fail ok 23 - unalike() fail should have the proper description ok 24 - unalike() fail should have the proper diagnostics pgtap-1.3.2/test/expected/moretap.out000066400000000000000000000046201455775703000176270ustar00rootroot00000000000000\unset ECHO 1..54 ok 1 - Modify internal plan value ok 2 - My pass() passed, w00t! ok 3 - Testing fail() ok 4 - We should get the proper output from fail() ok 5 - The output of finish() should reflect the test failure ok 6 - Increase internal plan value after testing finish ok 7 - The output of finish(false) should reflect the test failure ok 8 - Increase internal plan value after testing finish ok 9 - The output of finish(NULL) should reflect the test failure ok 10 - Increase internal plan value after testing finish ok 11 - finish(true) should throw an exception ok 12 - We should have one failure ok 13 - Reset internal failure count ok 14 - We should now have no failures ok 15 - diag() should work properly ok 16 - multiline diag() should work properly ok 17 - multiline diag() should work properly with existing comments ok 18 - diag(int) ok 19 - diag(numeric) ok 20 - diag(timestamptz) ok 21 - variadic text ok 22 - variadic int ok 23 - variadic unknown ok 24 - no_plan() should have stored a plan of 0 ok 25 - Set the plan to 4000 ok 26 - The output of finish() should reflect a high test plan ok 27 - Set the plan to 4 ok 28 - The output of finish() should reflect a low test plan ok 29 - Reset the plan ok 30 - plan() should have stored the test count ok 31 - ok(true) should pass ok 32 - ok(true) should have the proper description ok 33 - ok(true) should have the proper diagnostics ok 34 - ok(true, '') should pass ok 35 - ok(true, '') should have the proper description ok 36 - ok(true, '') should have the proper diagnostics ok 37 - ok(true, 'foo') should pass ok 38 - ok(true, 'foo') should have the proper description ok 39 - ok(true, 'foo') should have the proper diagnostics ok 40 - ok(false) should fail ok 41 - ok(false) should have the proper description ok 42 - ok(false) should have the proper diagnostics ok 43 - ok(false, '') should fail ok 44 - ok(false, '') should have the proper description ok 45 - ok(false, '') should have the proper diagnostics ok 46 - ok(false, 'foo') should fail ok 47 - ok(false, 'foo') should have the proper description ok 48 - ok(false, 'foo') should have the proper diagnostics ok 49 - ok(NULL, 'null') should fail ok 50 - ok(NULL, 'null') should have the proper description ok 51 - ok(NULL, 'null') should have the proper diagnostics ok 52 - multiline desc should pass ok 53 - multiline desc should have the proper description ok 54 - multiline desc should have the proper diagnostics pgtap-1.3.2/test/expected/ownership.out000066400000000000000000000755511455775703000202110ustar00rootroot00000000000000\unset ECHO 1..411 ok 1 - db_owner_is(db, user, desc) should pass ok 2 - db_owner_is(db, user, desc) should have the proper description ok 3 - db_owner_is(db, user, desc) should have the proper diagnostics ok 4 - db_owner_is(db, user) should pass ok 5 - db_owner_is(db, user) should have the proper description ok 6 - db_owner_is(db, user) should have the proper diagnostics ok 7 - db_owner_is(non-db, user) should fail ok 8 - db_owner_is(non-db, user) should have the proper description ok 9 - db_owner_is(non-db, user) should have the proper diagnostics ok 10 - db_owner_is(db, non-user) should fail ok 11 - db_owner_is(db, non-user) should have the proper description ok 12 - db_owner_is(db, non-user) should have the proper diagnostics ok 13 - schema_owner_is(schema, user, desc) should pass ok 14 - schema_owner_is(schema, user, desc) should have the proper description ok 15 - schema_owner_is(schema, user, desc) should have the proper diagnostics ok 16 - schema_owner_is(schema, user) should pass ok 17 - schema_owner_is(schema, user) should have the proper description ok 18 - schema_owner_is(schema, user) should have the proper diagnostics ok 19 - schema_owner_is(non-schema, user) should fail ok 20 - schema_owner_is(non-schema, user) should have the proper description ok 21 - schema_owner_is(non-schema, user) should have the proper diagnostics ok 22 - schema_owner_is(schema, non-user) should fail ok 23 - schema_owner_is(schema, non-user) should have the proper description ok 24 - schema_owner_is(schema, non-user) should have the proper diagnostics ok 25 - relation_owner_is(sch, tab, user, desc) should pass ok 26 - relation_owner_is(sch, tab, user, desc) should have the proper description ok 27 - relation_owner_is(sch, tab, user, desc) should have the proper diagnostics ok 28 - relation_owner_is(sch, tab, user) should pass ok 29 - relation_owner_is(sch, tab, user) should have the proper description ok 30 - relation_owner_is(sch, tab, user) should have the proper diagnostics ok 31 - relation_owner_is(non-sch, tab, user) should fail ok 32 - relation_owner_is(non-sch, tab, user) should have the proper description ok 33 - relation_owner_is(non-sch, tab, user) should have the proper diagnostics ok 34 - relation_owner_is(sch, non-tab, user) should fail ok 35 - relation_owner_is(sch, non-tab, user) should have the proper description ok 36 - relation_owner_is(sch, non-tab, user) should have the proper diagnostics ok 37 - relation_owner_is(tab, user, desc) should pass ok 38 - relation_owner_is(tab, user, desc) should have the proper description ok 39 - relation_owner_is(tab, user, desc) should have the proper diagnostics ok 40 - relation_owner_is(tab, user) should pass ok 41 - relation_owner_is(tab, user) should have the proper description ok 42 - relation_owner_is(tab, user) should have the proper diagnostics ok 43 - relation_owner_is(non-tab, user) should fail ok 44 - relation_owner_is(non-tab, user) should have the proper description ok 45 - relation_owner_is(non-tab, user) should have the proper diagnostics ok 46 - relation_owner_is(sch, part, user, desc) should pass ok 47 - relation_owner_is(sch, part, user, desc) should have the proper description ok 48 - relation_owner_is(sch, part, user, desc) should have the proper diagnostics ok 49 - relation_owner_is(sch, part, user) should pass ok 50 - relation_owner_is(sch, part, user) should have the proper description ok 51 - relation_owner_is(sch, part, user) should have the proper diagnostics ok 52 - relation_owner_is(non-sch, part, user) should fail ok 53 - relation_owner_is(non-sch, part, user) should have the proper description ok 54 - relation_owner_is(non-sch, part, user) should have the proper diagnostics ok 55 - relation_owner_is(sch, non-part, user) should fail ok 56 - relation_owner_is(sch, non-part, user) should have the proper description ok 57 - relation_owner_is(sch, non-part, user) should have the proper diagnostics ok 58 - relation_owner_is(part, user, desc) should pass ok 59 - relation_owner_is(part, user, desc) should have the proper description ok 60 - relation_owner_is(part, user, desc) should have the proper diagnostics ok 61 - relation_owner_is(part, user) should pass ok 62 - relation_owner_is(part, user) should have the proper description ok 63 - relation_owner_is(part, user) should have the proper diagnostics ok 64 - relation_owner_is(non-part, user) should fail ok 65 - relation_owner_is(non-part, user) should have the proper description ok 66 - relation_owner_is(non-part, user) should have the proper diagnostics ok 67 - relation_owner_is(sch, seq, user, desc) should pass ok 68 - relation_owner_is(sch, seq, user, desc) should have the proper description ok 69 - relation_owner_is(sch, seq, user, desc) should have the proper diagnostics ok 70 - relation_owner_is(sch, seq, user) should pass ok 71 - relation_owner_is(sch, seq, user) should have the proper description ok 72 - relation_owner_is(sch, seq, user) should have the proper diagnostics ok 73 - relation_owner_is(non-sch, seq, user) should fail ok 74 - relation_owner_is(non-sch, seq, user) should have the proper description ok 75 - relation_owner_is(non-sch, seq, user) should have the proper diagnostics ok 76 - relation_owner_is(sch, non-seq, user) should fail ok 77 - relation_owner_is(sch, non-seq, user) should have the proper description ok 78 - relation_owner_is(sch, non-seq, user) should have the proper diagnostics ok 79 - relation_owner_is(seq, user, desc) should pass ok 80 - relation_owner_is(seq, user, desc) should have the proper description ok 81 - relation_owner_is(seq, user, desc) should have the proper diagnostics ok 82 - relation_owner_is(seq, user) should pass ok 83 - relation_owner_is(seq, user) should have the proper description ok 84 - relation_owner_is(seq, user) should have the proper diagnostics ok 85 - relation_owner_is(non-seq, user) should fail ok 86 - relation_owner_is(non-seq, user) should have the proper description ok 87 - relation_owner_is(non-seq, user) should have the proper diagnostics ok 88 - table_owner_is(sch, tab, user, desc) should pass ok 89 - table_owner_is(sch, tab, user, desc) should have the proper description ok 90 - table_owner_is(sch, tab, user, desc) should have the proper diagnostics ok 91 - table_owner_is(sch, tab, user) should pass ok 92 - table_owner_is(sch, tab, user) should have the proper description ok 93 - table_owner_is(sch, tab, user) should have the proper diagnostics ok 94 - table_owner_is(non-sch, tab, user) should fail ok 95 - table_owner_is(non-sch, tab, user) should have the proper description ok 96 - table_owner_is(non-sch, tab, user) should have the proper diagnostics ok 97 - table_owner_is(sch, non-tab, user) should fail ok 98 - table_owner_is(sch, non-tab, user) should have the proper description ok 99 - table_owner_is(sch, non-tab, user) should have the proper diagnostics ok 100 - table_owner_is(tab, user, desc) should pass ok 101 - table_owner_is(tab, user, desc) should have the proper description ok 102 - table_owner_is(tab, user, desc) should have the proper diagnostics ok 103 - table_owner_is(tab, user) should pass ok 104 - table_owner_is(tab, user) should have the proper description ok 105 - table_owner_is(tab, user) should have the proper diagnostics ok 106 - table_owner_is(non-tab, user) should fail ok 107 - table_owner_is(non-tab, user) should have the proper description ok 108 - table_owner_is(non-tab, user) should have the proper diagnostics ok 109 - table_owner_is(sch, seq, user, desc) should fail ok 110 - table_owner_is(sch, seq, user, desc) should have the proper description ok 111 - table_owner_is(sch, seq, user, desc) should have the proper diagnostics ok 112 - table_owner_is(seq, user, desc) should fail ok 113 - table_owner_is(seq, user, desc) should have the proper description ok 114 - table_owner_is(seq, user, desc) should have the proper diagnostics ok 115 - table_owner_is(sch, part, user, desc) should pass ok 116 - table_owner_is(sch, part, user, desc) should have the proper description ok 117 - table_owner_is(sch, part, user, desc) should have the proper diagnostics ok 118 - table_owner_is(part, user, desc) should pass ok 119 - table_owner_is(part, user, desc) should have the proper description ok 120 - table_owner_is(part, user, desc) should have the proper diagnostics ok 121 - view_owner_is(sch, view, user, desc) should pass ok 122 - view_owner_is(sch, view, user, desc) should have the proper description ok 123 - view_owner_is(sch, view, user, desc) should have the proper diagnostics ok 124 - view_owner_is(sch, view, user) should pass ok 125 - view_owner_is(sch, view, user) should have the proper description ok 126 - view_owner_is(sch, view, user) should have the proper diagnostics ok 127 - view_owner_is(non-sch, view, user) should fail ok 128 - view_owner_is(non-sch, view, user) should have the proper description ok 129 - view_owner_is(non-sch, view, user) should have the proper diagnostics ok 130 - view_owner_is(sch, non-view, user) should fail ok 131 - view_owner_is(sch, non-view, user) should have the proper description ok 132 - view_owner_is(sch, non-view, user) should have the proper diagnostics ok 133 - view_owner_is(view, user, desc) should pass ok 134 - view_owner_is(view, user, desc) should have the proper description ok 135 - view_owner_is(view, user, desc) should have the proper diagnostics ok 136 - view_owner_is(view, user) should pass ok 137 - view_owner_is(view, user) should have the proper description ok 138 - view_owner_is(view, user) should have the proper diagnostics ok 139 - view_owner_is(non-view, user) should fail ok 140 - view_owner_is(non-view, user) should have the proper description ok 141 - view_owner_is(non-view, user) should have the proper diagnostics ok 142 - view_owner_is(sch, seq, user, desc) should fail ok 143 - view_owner_is(sch, seq, user, desc) should have the proper description ok 144 - view_owner_is(sch, seq, user, desc) should have the proper diagnostics ok 145 - view_owner_is(seq, user, desc) should fail ok 146 - view_owner_is(seq, user, desc) should have the proper description ok 147 - view_owner_is(seq, user, desc) should have the proper diagnostics ok 148 - sequence_owner_is(sch, sequence, user, desc) should pass ok 149 - sequence_owner_is(sch, sequence, user, desc) should have the proper description ok 150 - sequence_owner_is(sch, sequence, user, desc) should have the proper diagnostics ok 151 - sequence_owner_is(sch, sequence, user) should pass ok 152 - sequence_owner_is(sch, sequence, user) should have the proper description ok 153 - sequence_owner_is(sch, sequence, user) should have the proper diagnostics ok 154 - sequence_owner_is(non-sch, sequence, user) should fail ok 155 - sequence_owner_is(non-sch, sequence, user) should have the proper description ok 156 - sequence_owner_is(non-sch, sequence, user) should have the proper diagnostics ok 157 - sequence_owner_is(sch, non-sequence, user) should fail ok 158 - sequence_owner_is(sch, non-sequence, user) should have the proper description ok 159 - sequence_owner_is(sch, non-sequence, user) should have the proper diagnostics ok 160 - sequence_owner_is(sequence, user, desc) should pass ok 161 - sequence_owner_is(sequence, user, desc) should have the proper description ok 162 - sequence_owner_is(sequence, user, desc) should have the proper diagnostics ok 163 - sequence_owner_is(sequence, user) should pass ok 164 - sequence_owner_is(sequence, user) should have the proper description ok 165 - sequence_owner_is(sequence, user) should have the proper diagnostics ok 166 - sequence_owner_is(non-sequence, user) should fail ok 167 - sequence_owner_is(non-sequence, user) should have the proper description ok 168 - sequence_owner_is(non-sequence, user) should have the proper diagnostics ok 169 - sequence_owner_is(sch, view, user, desc) should fail ok 170 - sequence_owner_is(sch, view, user, desc) should have the proper description ok 171 - sequence_owner_is(sch, view, user, desc) should have the proper diagnostics ok 172 - sequence_owner_is(view, user, desc) should fail ok 173 - sequence_owner_is(view, user, desc) should have the proper description ok 174 - sequence_owner_is(view, user, desc) should have the proper diagnostics ok 175 - composite_owner_is(sch, composite, user, desc) should pass ok 176 - composite_owner_is(sch, composite, user, desc) should have the proper description ok 177 - composite_owner_is(sch, composite, user, desc) should have the proper diagnostics ok 178 - composite_owner_is(sch, composite, user) should pass ok 179 - composite_owner_is(sch, composite, user) should have the proper description ok 180 - composite_owner_is(sch, composite, user) should have the proper diagnostics ok 181 - composite_owner_is(non-sch, composite, user) should fail ok 182 - composite_owner_is(non-sch, composite, user) should have the proper description ok 183 - composite_owner_is(non-sch, composite, user) should have the proper diagnostics ok 184 - composite_owner_is(sch, non-composite, user) should fail ok 185 - composite_owner_is(sch, non-composite, user) should have the proper description ok 186 - composite_owner_is(sch, non-composite, user) should have the proper diagnostics ok 187 - composite_owner_is(composite, user, desc) should pass ok 188 - composite_owner_is(composite, user, desc) should have the proper description ok 189 - composite_owner_is(composite, user, desc) should have the proper diagnostics ok 190 - composite_owner_is(composite, user) should pass ok 191 - composite_owner_is(composite, user) should have the proper description ok 192 - composite_owner_is(composite, user) should have the proper diagnostics ok 193 - composite_owner_is(non-composite, user) should fail ok 194 - composite_owner_is(non-composite, user) should have the proper description ok 195 - composite_owner_is(non-composite, user) should have the proper diagnostics ok 196 - composite_owner_is(sch, view, user, desc) should fail ok 197 - composite_owner_is(sch, view, user, desc) should have the proper description ok 198 - composite_owner_is(sch, view, user, desc) should have the proper diagnostics ok 199 - composite_owner_is(view, user, desc) should fail ok 200 - composite_owner_is(view, user, desc) should have the proper description ok 201 - composite_owner_is(view, user, desc) should have the proper diagnostics ok 202 - foreign_table_owner_is(sch, tab, user, desc) should pass ok 203 - foreign_table_owner_is(sch, tab, user, desc) should have the proper description ok 204 - foreign_table_owner_is(sch, tab, user, desc) should have the proper diagnostics ok 205 - foreign_table_owner_is(sch, tab, user) should pass ok 206 - foreign_table_owner_is(sch, tab, user) should have the proper description ok 207 - foreign_table_owner_is(sch, tab, user) should have the proper diagnostics ok 208 - foreign_table_owner_is(non-sch, tab, user) should fail ok 209 - foreign_table_owner_is(non-sch, tab, user) should have the proper description ok 210 - foreign_table_owner_is(non-sch, tab, user) should have the proper diagnostics ok 211 - foreign_table_owner_is(sch, non-tab, user) should fail ok 212 - foreign_table_owner_is(sch, non-tab, user) should have the proper description ok 213 - foreign_table_owner_is(sch, non-tab, user) should have the proper diagnostics ok 214 - foreign_table_owner_is(tab, user, desc) should pass ok 215 - foreign_table_owner_is(tab, user, desc) should have the proper description ok 216 - foreign_table_owner_is(tab, user, desc) should have the proper diagnostics ok 217 - foreign_table_owner_is(tab, user) should pass ok 218 - foreign_table_owner_is(tab, user) should have the proper description ok 219 - foreign_table_owner_is(tab, user) should have the proper diagnostics ok 220 - foreign_table_owner_is(non-tab, user) should fail ok 221 - foreign_table_owner_is(non-tab, user) should have the proper description ok 222 - foreign_table_owner_is(non-tab, user) should have the proper diagnostics ok 223 - foreign_table_owner_is(sch, tab, user, desc) should fail ok 224 - foreign_table_owner_is(sch, tab, user, desc) should have the proper description ok 225 - foreign_table_owner_is(sch, tab, user, desc) should have the proper diagnostics ok 226 - foreign_table_owner_is(tab, user, desc) should fail ok 227 - foreign_table_owner_is(tab, user, desc) should have the proper description ok 228 - foreign_table_owner_is(tab, user, desc) should have the proper diagnostics ok 229 - function_owner_is(sch, function, args[integer], user, desc) should pass ok 230 - function_owner_is(sch, function, args[integer], user, desc) should have the proper description ok 231 - function_owner_is(sch, function, args[integer], user, desc) should have the proper diagnostics ok 232 - function_owner_is(sch, function, args[integer], user) should pass ok 233 - function_owner_is(sch, function, args[integer], user) should have the proper description ok 234 - function_owner_is(sch, function, args[integer], user) should have the proper diagnostics ok 235 - function_owner_is(sch, function, args[], user, desc) should pass ok 236 - function_owner_is(sch, function, args[], user, desc) should have the proper description ok 237 - function_owner_is(sch, function, args[], user, desc) should have the proper diagnostics ok 238 - function_owner_is(sch, function, args[], user) should pass ok 239 - function_owner_is(sch, function, args[], user) should have the proper description ok 240 - function_owner_is(sch, function, args[], user) should have the proper diagnostics ok 241 - function_owner_is(function, args[integer], user, desc) should pass ok 242 - function_owner_is(function, args[integer], user, desc) should have the proper description ok 243 - function_owner_is(function, args[integer], user, desc) should have the proper diagnostics ok 244 - function_owner_is(function, args[integer], user) should pass ok 245 - function_owner_is(function, args[integer], user) should have the proper description ok 246 - function_owner_is(function, args[integer], user) should have the proper diagnostics ok 247 - function_owner_is(function, args[], user, desc) should pass ok 248 - function_owner_is(function, args[], user, desc) should have the proper description ok 249 - function_owner_is(function, args[], user, desc) should have the proper diagnostics ok 250 - function_owner_is(function, args[], user) should pass ok 251 - function_owner_is(function, args[], user) should have the proper description ok 252 - function_owner_is(function, args[], user) should have the proper diagnostics ok 253 - function_owner_is(sch, non-function, args[integer], user, desc) should fail ok 254 - function_owner_is(sch, non-function, args[integer], user, desc) should have the proper description ok 255 - function_owner_is(sch, non-function, args[integer], user, desc) should have the proper diagnostics ok 256 - function_owner_is(non-sch, function, args[integer], user, desc) should fail ok 257 - function_owner_is(non-sch, function, args[integer], user, desc) should have the proper description ok 258 - function_owner_is(non-sch, function, args[integer], user, desc) should have the proper diagnostics ok 259 - function_owner_is(non-function, args[integer], user, desc) should fail ok 260 - function_owner_is(non-function, args[integer], user, desc) should have the proper description ok 261 - function_owner_is(non-function, args[integer], user, desc) should have the proper diagnostics ok 262 - function_owner_is(sch, function, args[integer], non-user, desc) should fail ok 263 - function_owner_is(sch, function, args[integer], non-user, desc) should have the proper description ok 264 - function_owner_is(sch, function, args[integer], non-user, desc) should have the proper diagnostics ok 265 - function_owner_is(function, args[integer], non-user, desc) should fail ok 266 - function_owner_is(function, args[integer], non-user, desc) should have the proper description ok 267 - function_owner_is(function, args[integer], non-user, desc) should have the proper diagnostics ok 268 - tablespace_owner_is(tablespace, user, desc) should pass ok 269 - tablespace_owner_is(tablespace, user, desc) should have the proper description ok 270 - tablespace_owner_is(tablespace, user, desc) should have the proper diagnostics ok 271 - tablespace_owner_is(tablespace, user) should pass ok 272 - tablespace_owner_is(tablespace, user) should have the proper description ok 273 - tablespace_owner_is(tablespace, user) should have the proper diagnostics ok 274 - tablespace_owner_is(non-tablespace, user) should fail ok 275 - tablespace_owner_is(non-tablespace, user) should have the proper description ok 276 - tablespace_owner_is(non-tablespace, user) should have the proper diagnostics ok 277 - tablespace_owner_is(tablespace, non-user) should fail ok 278 - tablespace_owner_is(tablespace, non-user) should have the proper description ok 279 - tablespace_owner_is(tablespace, non-user) should have the proper diagnostics ok 280 - index_owner_is(schema, table, index, user, desc) should pass ok 281 - index_owner_is(schema, table, index, user, desc) should have the proper description ok 282 - index_owner_is(schema, table, index, user, desc) should have the proper diagnostics ok 283 - index_owner_is(schema, table, index, user) should pass ok 284 - index_owner_is(schema, table, index, user) should have the proper description ok 285 - index_owner_is(schema, table, index, user) should have the proper diagnostics ok 286 - index_owner_is(schema, table, non-index, user, desc) should fail ok 287 - index_owner_is(schema, table, non-index, user, desc) should have the proper description ok 288 - index_owner_is(schema, table, non-index, user, desc) should have the proper diagnostics ok 289 - index_owner_is(schema, non-table, index, user, desc) should fail ok 290 - index_owner_is(schema, non-table, index, user, desc) should have the proper description ok 291 - index_owner_is(schema, non-table, index, user, desc) should have the proper diagnostics ok 292 - index_owner_is(non-schema, table, index, user, desc) should fail ok 293 - index_owner_is(non-schema, table, index, user, desc) should have the proper description ok 294 - index_owner_is(non-schema, table, index, user, desc) should have the proper diagnostics ok 295 - index_owner_is(schema, table, index, non-user, desc) should fail ok 296 - index_owner_is(schema, table, index, non-user, desc) should have the proper description ok 297 - index_owner_is(schema, table, index, non-user, desc) should have the proper diagnostics ok 298 - index_owner_is(invisible-table, index, user, desc) should fail ok 299 - index_owner_is(invisible-table, index, user, desc) should have the proper description ok 300 - index_owner_is(invisible-table, index, user, desc) should have the proper diagnostics ok 301 - index_owner_is(table, index, user, desc) should pass ok 302 - index_owner_is(table, index, user, desc) should have the proper description ok 303 - index_owner_is(table, index, user, desc) should have the proper diagnostics ok 304 - index_owner_is(table, index, user) should pass ok 305 - index_owner_is(table, index, user) should have the proper description ok 306 - index_owner_is(table, index, user) should have the proper diagnostics ok 307 - index_owner_is(non-table, index, user) should fail ok 308 - index_owner_is(non-table, index, user) should have the proper description ok 309 - index_owner_is(non-table, index, user) should have the proper diagnostics ok 310 - index_owner_is(table, non-index, user) should fail ok 311 - index_owner_is(table, non-index, user) should have the proper description ok 312 - index_owner_is(table, non-index, user) should have the proper diagnostics ok 313 - index_owner_is(table, index, non-user) should fail ok 314 - index_owner_is(table, index, non-user) should have the proper description ok 315 - index_owner_is(table, index, non-user) should have the proper diagnostics ok 316 - language_owner_is(language, user, desc) should pass ok 317 - language_owner_is(language, user, desc) should have the proper description ok 318 - language_owner_is(language, user, desc) should have the proper diagnostics ok 319 - language_owner_is(language, user) should pass ok 320 - language_owner_is(language, user) should have the proper description ok 321 - language_owner_is(language, user) should have the proper diagnostics ok 322 - language_owner_is(non-language, user) should fail ok 323 - language_owner_is(non-language, user) should have the proper description ok 324 - language_owner_is(non-language, user) should have the proper diagnostics ok 325 - language_owner_is(language, non-user) should fail ok 326 - language_owner_is(language, non-user) should have the proper description ok 327 - language_owner_is(language, non-user) should have the proper diagnostics ok 328 - opclass_owner_is(schema, opclass, user, desc) should pass ok 329 - opclass_owner_is(schema, opclass, user, desc) should have the proper description ok 330 - opclass_owner_is(schema, opclass, user, desc) should have the proper diagnostics ok 331 - opclass_owner_is(schema, opclass, user) should pass ok 332 - opclass_owner_is(schema, opclass, user) should have the proper description ok 333 - opclass_owner_is(schema, opclass, user) should have the proper diagnostics ok 334 - opclass_owner_is(non-schema, opclass, user, desc) should fail ok 335 - opclass_owner_is(non-schema, opclass, user, desc) should have the proper description ok 336 - opclass_owner_is(non-schema, opclass, user, desc) should have the proper diagnostics ok 337 - opclass_owner_is(schema, not-opclass, user, desc) should fail ok 338 - opclass_owner_is(schema, not-opclass, user, desc) should have the proper description ok 339 - opclass_owner_is(schema, not-opclass, user, desc) should have the proper diagnostics ok 340 - opclass_owner_is(schema, opclass, non-user, desc) should fail ok 341 - opclass_owner_is(schema, opclass, non-user, desc) should have the proper description ok 342 - opclass_owner_is(schema, opclass, non-user, desc) should have the proper diagnostics ok 343 - opclass_owner_is(opclass, user, desc) should pass ok 344 - opclass_owner_is(opclass, user, desc) should have the proper description ok 345 - opclass_owner_is(opclass, user, desc) should have the proper diagnostics ok 346 - opclass_owner_is(opclass, user) should pass ok 347 - opclass_owner_is(opclass, user) should have the proper description ok 348 - opclass_owner_is(opclass, user) should have the proper diagnostics ok 349 - opclass_owner_is(non-opclass, user, desc) should fail ok 350 - opclass_owner_is(non-opclass, user, desc) should have the proper description ok 351 - opclass_owner_is(non-opclass, user, desc) should have the proper diagnostics ok 352 - opclass_owner_is(opclass, non-user, desc) should fail ok 353 - opclass_owner_is(opclass, non-user, desc) should have the proper description ok 354 - opclass_owner_is(opclass, non-user, desc) should have the proper diagnostics ok 355 - type_owner_is(schema, type, user, desc) should pass ok 356 - type_owner_is(schema, type, user, desc) should have the proper description ok 357 - type_owner_is(schema, type, user, desc) should have the proper diagnostics ok 358 - type_owner_is(schema, type, user) should pass ok 359 - type_owner_is(schema, type, user) should have the proper description ok 360 - type_owner_is(schema, type, user) should have the proper diagnostics ok 361 - type_owner_is(non-schema, type, user, desc) should fail ok 362 - type_owner_is(non-schema, type, user, desc) should have the proper description ok 363 - type_owner_is(non-schema, type, user, desc) should have the proper diagnostics ok 364 - type_owner_is(schema, non-type, user, desc) should fail ok 365 - type_owner_is(schema, non-type, user, desc) should have the proper description ok 366 - type_owner_is(schema, non-type, user, desc) should have the proper diagnostics ok 367 - type_owner_is(schema, type, non-user, desc) should fail ok 368 - type_owner_is(schema, type, non-user, desc) should have the proper description ok 369 - type_owner_is(schema, type, non-user, desc) should have the proper diagnostics ok 370 - type_owner_is( invisible-type, user, desc) should fail ok 371 - type_owner_is( invisible-type, user, desc) should have the proper description ok 372 - type_owner_is( invisible-type, user, desc) should have the proper diagnostics ok 373 - type_owner_is(type, user, desc) should pass ok 374 - type_owner_is(type, user, desc) should have the proper description ok 375 - type_owner_is(type, user, desc) should have the proper diagnostics ok 376 - type_owner_is(type, user) should pass ok 377 - type_owner_is(type, user) should have the proper description ok 378 - type_owner_is(type, user) should have the proper diagnostics ok 379 - type_owner_is(non-type, user, desc) should fail ok 380 - type_owner_is(non-type, user, desc) should have the proper description ok 381 - type_owner_is(non-type, user, desc) should have the proper diagnostics ok 382 - type_owner_is(type, non-user, desc) should fail ok 383 - type_owner_is(type, non-user, desc) should have the proper description ok 384 - type_owner_is(type, non-user, desc) should have the proper diagnostics ok 385 - materialized_view_owner_is(sch, materialized_view, user, desc) should pass ok 386 - materialized_view_owner_is(sch, materialized_view, user, desc) should have the proper description ok 387 - materialized_view_owner_is(sch, materialized_view, user, desc) should have the proper diagnostics ok 388 - materialized_view_owner_is(sch, materialized_view, user) should pass ok 389 - materialized_view_owner_is(sch, materialized_view, user) should have the proper description ok 390 - materialized_view_owner_is(sch, materialized_view, user) should have the proper diagnostics ok 391 - materialized_view_owner_is(non-sch, materialized_view, user) should fail ok 392 - materialized_view_owner_is(non-sch, materialized_view, user) should have the proper description ok 393 - materialized_view_owner_is(non-sch, materialized_view, user) should have the proper diagnostics ok 394 - materialized_view_owner_is(sch, non-materialized_view, user) should fail ok 395 - materialized_view_owner_is(sch, non-materialized_view, user) should have the proper description ok 396 - materialized_view_owner_is(sch, non-materialized_view, user) should have the proper diagnostics ok 397 - materialized_view_owner_is(materialized_view, user, desc) should pass ok 398 - materialized_view_owner_is(materialized_view, user, desc) should have the proper description ok 399 - materialized_view_owner_is(materialized_view, user, desc) should have the proper diagnostics ok 400 - materialized_view_owner_is(view, user) should pass ok 401 - materialized_view_owner_is(view, user) should have the proper description ok 402 - materialized_view_owner_is(view, user) should have the proper diagnostics ok 403 - materialized_view_owner_is(non-materialized_view, user) should fail ok 404 - materialized_view_owner_is(non-materialized_view, user) should have the proper description ok 405 - materialized_view_owner_is(non-materialized_view, user) should have the proper diagnostics ok 406 - materialized_view_owner_is(sch, seq, user, desc) should fail ok 407 - materialized_view_owner_is(sch, seq, user, desc) should have the proper description ok 408 - materialized_view_owner_is(sch, seq, user, desc) should have the proper diagnostics ok 409 - materialized_view_owner_is(seq, user, desc) should fail ok 410 - materialized_view_owner_is(seq, user, desc) should have the proper description ok 411 - materialized_view_owner_is(seq, user, desc) should have the proper diagnostics pgtap-1.3.2/test/expected/partitions.out000066400000000000000000000202451455775703000203550ustar00rootroot00000000000000\unset ECHO 1..102 ok 1 - is_partition_of( csch, ctab, psch, ptab, desc ) should pass ok 2 - is_partition_of( csch, ctab, psch, ptab, desc ) should have the proper description ok 3 - is_partition_of( csch, ctab, psch, ptab, desc ) should have the proper diagnostics ok 4 - is_partition_of( csch, ctab, psch, ptab ) should pass ok 5 - is_partition_of( csch, ctab, psch, ptab ) should have the proper description ok 6 - is_partition_of( csch, ctab, psch, ptab ) should have the proper diagnostics ok 7 - is_partition_of( ctab, ptab, desc ) should pass ok 8 - is_partition_of( ctab, ptab, desc ) should have the proper description ok 9 - is_partition_of( ctab, ptab, desc ) should have the proper diagnostics ok 10 - is_partition_of( ctab, ptab ) should pass ok 11 - is_partition_of( ctab, ptab ) should have the proper description ok 12 - is_partition_of( ctab, ptab ) should have the proper diagnostics ok 13 - is_partition_of( csch, non-part ctab, psch, non-part ptab, desc ) should fail ok 14 - is_partition_of( csch, non-part ctab, psch, non-part ptab, desc ) should have the proper description ok 15 - is_partition_of( csch, non-part ctab, psch, non-part ptab, desc ) should have the proper diagnostics ok 16 - is_partition_of( non-part ctab, non-part ptab, desc ) should fail ok 17 - is_partition_of( non-part ctab, non-part ptab, desc ) should have the proper description ok 18 - is_partition_of( non-part ctab, non-part ptab, desc ) should have the proper diagnostics ok 19 - is_partition_of( csch, non-part ctab, psch, ptab, desc ) should fail ok 20 - is_partition_of( csch, non-part ctab, psch, ptab, desc ) should have the proper description ok 21 - is_partition_of( csch, non-part ctab, psch, ptab, desc ) should have the proper diagnostics ok 22 - is_partition_of( non-part ctab, ptab, desc ) should fail ok 23 - is_partition_of( non-part ctab, ptab, desc ) should have the proper description ok 24 - is_partition_of( non-part ctab, ptab, desc ) should have the proper diagnostics ok 25 - is_partition_of( csch, ctab, psch, non-part ptab, desc ) should fail ok 26 - is_partition_of( csch, ctab, psch, non-part ptab, desc ) should have the proper description ok 27 - is_partition_of( csch, ctab, psch, non-part ptab, desc ) should have the proper diagnostics ok 28 - is_partition_of( ctab, non-part ptab, desc ) should fail ok 29 - is_partition_of( ctab, non-part ptab, desc ) should have the proper description ok 30 - is_partition_of( ctab, non-part ptab, desc ) should have the proper diagnostics ok 31 - is_partition_of( priv csch, ctab, priv psch, ptab, desc ) should pass ok 32 - is_partition_of( priv csch, ctab, priv psch, ptab, desc ) should have the proper description ok 33 - is_partition_of( priv csch, ctab, priv psch, ptab, desc ) should have the proper diagnostics ok 34 - is_partition_of( priv ctab, priv ptab, desc ) should fail ok 35 - is_partition_of( priv ctab, priv ptab, desc ) should have the proper description ok 36 - is_partition_of( priv ctab, priv ptab, desc ) should have the proper diagnostics ok 37 - is_partition_of( priv csch, ctab, psch, ptab, desc ) should pass ok 38 - is_partition_of( priv csch, ctab, psch, ptab, desc ) should have the proper description ok 39 - is_partition_of( priv csch, ctab, psch, ptab, desc ) should have the proper diagnostics ok 40 - is_partition_of( priv ctab, ptab, desc ) should fail ok 41 - is_partition_of( priv ctab, ptab, desc ) should have the proper description ok 42 - is_partition_of( priv ctab, ptab, desc ) should have the proper diagnostics ok 43 - is_partition_of( csch, ctab, priv psch, ptab, desc ) should pass ok 44 - is_partition_of( csch, ctab, priv psch, ptab, desc ) should have the proper description ok 45 - is_partition_of( csch, ctab, priv psch, ptab, desc ) should have the proper diagnostics ok 46 - is_partition_of( ctab, priv ptab, desc ) should fail ok 47 - is_partition_of( ctab, priv ptab, desc ) should have the proper description ok 48 - is_partition_of( ctab, priv ptab, desc ) should have the proper diagnostics ok 49 - is_partition_of( csch, non-ctab, psch, non-ptab, desc ) should fail ok 50 - is_partition_of( csch, non-ctab, psch, non-ptab, desc ) should have the proper description ok 51 - is_partition_of( csch, non-ctab, psch, non-ptab, desc ) should have the proper diagnostics ok 52 - is_partition_of( non-ctab, non-ptab, desc ) should fail ok 53 - is_partition_of( non-ctab, non-ptab, desc ) should have the proper description ok 54 - is_partition_of( non-ctab, non-ptab, desc ) should have the proper diagnostics ok 55 - is_partition_of( csch, ctab, psch, non-ptab, desc ) should fail ok 56 - is_partition_of( csch, ctab, psch, non-ptab, desc ) should have the proper description ok 57 - is_partition_of( csch, ctab, psch, non-ptab, desc ) should have the proper diagnostics ok 58 - is_partition_of( ctab, non-ptab, desc ) should fail ok 59 - is_partition_of( ctab, non-ptab, desc ) should have the proper description ok 60 - is_partition_of( ctab, non-ptab, desc ) should have the proper diagnostics ok 61 - is_partition_of( csch, non-ctab, psch, ptab, desc ) should fail ok 62 - is_partition_of( csch, non-ctab, psch, ptab, desc ) should have the proper description ok 63 - is_partition_of( csch, non-ctab, psch, ptab, desc ) should have the proper diagnostics ok 64 - is_partition_of( non-ctab, ptab, desc ) should fail ok 65 - is_partition_of( non-ctab, ptab, desc ) should have the proper description ok 66 - is_partition_of( non-ctab, ptab, desc ) should have the proper diagnostics ok 67 - partitions_are( sch, tab, parts, desc ) should pass ok 68 - partitions_are( sch, tab, parts, desc ) should have the proper description ok 69 - partitions_are( sch, tab, parts, desc ) should have the proper diagnostics ok 70 - partitions_are( sch, tab, parts ) should pass ok 71 - partitions_are( sch, tab, parts ) should have the proper description ok 72 - partitions_are( sch, tab, parts ) should have the proper diagnostics ok 73 - partitions_are( tab, parts, desc ) should pass ok 74 - partitions_are( tab, parts, desc ) should have the proper description ok 75 - partitions_are( tab, parts, desc ) should have the proper diagnostics ok 76 - partitions_are( tab, parts ) should pass ok 77 - partitions_are( tab, parts ) should have the proper description ok 78 - partitions_are( tab, parts ) should have the proper diagnostics ok 79 - partitions_are( sch, tab, bad parts, desc ) should fail ok 80 - partitions_are( sch, tab, bad parts, desc ) should have the proper description ok 81 - partitions_are( sch, tab, bad parts, desc ) should have the proper diagnostics ok 82 - partitions_are( tab, bad parts, desc ) should fail ok 83 - partitions_are( tab, bad parts, desc ) should have the proper description ok 84 - partitions_are( tab, bad parts, desc ) should have the proper diagnostics ok 85 - partitions_are( hidden sch, tab, parts, desc ) should pass ok 86 - partitions_are( hidden sch, tab, parts, desc ) should have the proper description ok 87 - partitions_are( hidden sch, tab, parts, desc ) should have the proper diagnostics ok 88 - partitions_are( hidden tab, parts, desc ) should fail ok 89 - partitions_are( hidden tab, parts, desc ) should have the proper description ok 90 - partitions_are( hidden tab, parts, desc ) should have the proper diagnostics ok 91 - partitions_are( sch, non-parted tab, inherited tab, desc ) should fail ok 92 - partitions_are( sch, non-parted tab, inherited tab, desc ) should have the proper description ok 93 - partitions_are( sch, non-parted tab, inherited tab, desc ) should have the proper diagnostics ok 94 - partitions_are( non-parted tab, inherited tab, desc ) should fail ok 95 - partitions_are( non-parted tab, inherited tab, desc ) should have the proper description ok 96 - partitions_are( non-parted tab, inherited tab, desc ) should have the proper diagnostics ok 97 - partitions_are( sch, non-existent tab, parts, desc ) should fail ok 98 - partitions_are( sch, non-existent tab, parts, desc ) should have the proper description ok 99 - partitions_are( sch, non-existent tab, parts, desc ) should have the proper diagnostics ok 100 - partitions_are( non-existent tab, parts, desc ) should fail ok 101 - partitions_are( non-existent tab, parts, desc ) should have the proper description ok 102 - partitions_are( non-existent tab, parts, desc ) should have the proper diagnostics pgtap-1.3.2/test/expected/performs_ok.out000066400000000000000000000025241455775703000205070ustar00rootroot00000000000000\unset ECHO 1..24 ok 1 - simple select should pass ok 2 - simple select should have the proper description ok 3 - simple select should have the proper diagnostics ok 4 - simple select no desc should pass ok 5 - simple select no desc should have the proper description ok 6 - simple select no desc should have the proper diagnostics ok 7 - simple select numeric should pass ok 8 - simple select numeric should have the proper description ok 9 - simple select numeric should have the proper diagnostics ok 10 - simple prepare should pass ok 11 - simple prepare should have the proper description ok 12 - simple prepare should have the proper diagnostics ok 13 - simple execute should pass ok 14 - simple execute should have the proper description ok 15 - simple execute should have the proper diagnostics ok 16 - simple select fail should fail ok 17 - simple select fail should have the proper description ok 18 - simple select fail should have the proper diagnostics ok 19 - simple select no desc fail should fail ok 20 - simple select no desc fail should have the proper description ok 21 - simple select no desc fail should have the proper diagnostics ok 22 - simple select no desc numeric fail should fail ok 23 - simple select no desc numeric fail should have the proper description ok 24 - simple select no desc numeric fail should have the proper diagnostics pgtap-1.3.2/test/expected/performs_within.out000066400000000000000000000025241455775703000214000ustar00rootroot00000000000000\unset ECHO 1..24 ok 1 - simple select should pass ok 2 - simple select should have the proper description ok 3 - simple select should have the proper diagnostics ok 4 - simple select no desc should pass ok 5 - simple select no desc should have the proper description ok 6 - simple select no desc should have the proper diagnostics ok 7 - simple select numeric should pass ok 8 - simple select numeric should have the proper description ok 9 - simple select numeric should have the proper diagnostics ok 10 - simple prepare should pass ok 11 - simple prepare should have the proper description ok 12 - simple prepare should have the proper diagnostics ok 13 - simple execute should pass ok 14 - simple execute should have the proper description ok 15 - simple execute should have the proper diagnostics ok 16 - simple select fail should fail ok 17 - simple select fail should have the proper description ok 18 - simple select fail should have the proper diagnostics ok 19 - simple select no desc fail should fail ok 20 - simple select no desc fail should have the proper description ok 21 - simple select no desc fail should have the proper diagnostics ok 22 - simple select no desc numeric fail should fail ok 23 - simple select no desc numeric fail should have the proper description ok 24 - simple select no desc numeric fail should have the proper diagnostics pgtap-1.3.2/test/expected/pg73.out000066400000000000000000000012701455775703000167360ustar00rootroot00000000000000\unset ECHO 1..39 ok 1 ok 2 - true ok 3 ok 4 - NOT false ok 5 ok 6 - three ok 7 ok 8 ok 9 ok 10 - 1=2 ok 11 - now()=now() ok 12 - '1 hour'::interval, '1 hour'::interval ok 13 ok 14 - now=now date ok 15 - now!=now+1 ok 16 - now()=now() timestamp ok 17 - now()=now() date ok 18 - TRUE=TRUE ok 19 - TRUE!=FALSE ok 20 - a=a char ok 21 - a!=b char ok 22 - a=a text ok 23 - a!=b text ok 24 - 3=3 int ok 25 - 3!=4 int ok 26 - 3=3 integer ok 27 - 3!=4 integer ok 28 - 3=3 int2 ok 29 - 3!=4 int2 ok 30 - 3=3 int4 ok 31 - 3!=4 int4 ok 32 - 3=3 int8 ok 33 - 3!=4 int8 ok 34 - 3.2=3.2 float ok 35 - 3.2!=4.5 float ok 36 - 3.2=3.2 float4 ok 37 - 3.2!=4.5 float4 ok 38 - 3.2=3.2 float8 ok 39 - 3.2!=4.5 float8 pgtap-1.3.2/test/expected/pktap.out000066400000000000000000000156301455775703000173020ustar00rootroot00000000000000\unset ECHO 1..96 ok 1 - has_pk( schema, table, description ) should pass ok 2 - has_pk( schema, table, description ) should have the proper description ok 3 - has_pk( schema, table, description ) should have the proper diagnostics ok 4 - has_pk( schema, table ) should pass ok 5 - has_pk( schema, table ) should have the proper description ok 6 - has_pk( schema, table ) should have the proper diagnostics ok 7 - has_pk( hideschema, hidetable, description ) should pass ok 8 - has_pk( hideschema, hidetable, description ) should have the proper description ok 9 - has_pk( hideschema, hidetable, description ) should have the proper diagnostics ok 10 - has_pk( hideschema, hidetable ) should pass ok 11 - has_pk( hideschema, hidetable ) should have the proper description ok 12 - has_pk( hideschema, hidetable ) should have the proper diagnostics ok 13 - has_pk( table, description ) should pass ok 14 - has_pk( table, description ) should have the proper description ok 15 - has_pk( table, description ) should have the proper diagnostics ok 16 - has_pk( hidetable, description ) fail should fail ok 17 - has_pk( hidetable, description ) fail should have the proper description ok 18 - has_pk( hidetable, description ) fail should have the proper diagnostics ok 19 - has_pk( table ) should pass ok 20 - has_pk( table ) should have the proper description ok 21 - has_pk( table ) should have the proper diagnostics ok 22 - has_pk( schema, table, description ) fail should fail ok 23 - has_pk( schema, table, description ) fail should have the proper description ok 24 - has_pk( schema, table, description ) fail should have the proper diagnostics ok 25 - has_pk( table, description ) fail should fail ok 26 - has_pk( table, description ) fail should have the proper description ok 27 - has_pk( table, description ) fail should have the proper diagnostics ok 28 - hasnt_pk( schema, table, description ) should fail ok 29 - hasnt_pk( schema, table, description ) should have the proper description ok 30 - hasnt_pk( schema, table, description ) should have the proper diagnostics ok 31 - hasnt_pk( table, description ) should fail ok 32 - hasnt_pk( table, description ) should have the proper description ok 33 - hasnt_pk( table, description ) should have the proper diagnostics ok 34 - hasnt_pk( table ) should fail ok 35 - hasnt_pk( table ) should have the proper description ok 36 - hasnt_pk( table ) should have the proper diagnostics ok 37 - hasnt_pk( schema, table, description ) pass should pass ok 38 - hasnt_pk( schema, table, description ) pass should have the proper description ok 39 - hasnt_pk( schema, table, description ) pass should have the proper diagnostics ok 40 - hasnt_pk( table, description ) pass should pass ok 41 - hasnt_pk( table, description ) pass should have the proper description ok 42 - hasnt_pk( table, description ) pass should have the proper diagnostics ok 43 - col_is_pk( schema, table, column, description ) should pass ok 44 - col_is_pk( schema, table, column, description ) should have the proper description ok 45 - col_is_pk( schema, table, column, description ) should have the proper diagnostics ok 46 - col_is_pk( schema, table, column ) should pass ok 47 - col_is_pk( schema, table, column ) should have the proper description ok 48 - col_is_pk( schema, table, column ) should have the proper diagnostics ok 49 - col_is_pk( table, column, description ) should pass ok 50 - col_is_pk( table, column, description ) should have the proper description ok 51 - col_is_pk( table, column, description ) should have the proper diagnostics ok 52 - col_is_pk( table, column ) should pass ok 53 - col_is_pk( table, column ) should have the proper description ok 54 - col_is_pk( table, column ) should have the proper diagnostics ok 55 - col_is_pk( schema, table, column, description ) fail should fail ok 56 - col_is_pk( schema, table, column, description ) fail should have the proper description ok 57 - col_is_pk( schema, table, column, description ) fail should have the proper diagnostics ok 58 - col_is_pk( table, column, description ) fail should fail ok 59 - col_is_pk( table, column, description ) fail should have the proper description ok 60 - col_is_pk( table, column, description ) fail should have the proper diagnostics ok 61 - col_is_pk( schema, table, column[], description ) should pass ok 62 - col_is_pk( schema, table, column[], description ) should have the proper description ok 63 - col_is_pk( schema, table, column[], description ) should have the proper diagnostics ok 64 - col_is_pk( schema, table, column[] ) should pass ok 65 - col_is_pk( schema, table, column[] ) should have the proper description ok 66 - col_is_pk( schema, table, column[] ) should have the proper diagnostics ok 67 - col_is_pk( table, column[], description ) should pass ok 68 - col_is_pk( table, column[], description ) should have the proper description ok 69 - col_is_pk( table, column[], description ) should have the proper diagnostics ok 70 - col_is_pk( table, column[] ) should pass ok 71 - col_is_pk( table, column[] ) should have the proper description ok 72 - col_is_pk( table, column[] ) should have the proper diagnostics ok 73 - col_isnt_pk( schema, table, column, description ) should fail ok 74 - col_isnt_pk( schema, table, column, description ) should have the proper description ok 75 - col_isnt_pk( schema, table, column, description ) should have the proper diagnostics ok 76 - col_isnt_pk( table, column, description ) should fail ok 77 - col_isnt_pk( table, column, description ) should have the proper description ok 78 - col_isnt_pk( table, column, description ) should have the proper diagnostics ok 79 - col_isnt_pk( table, column ) should fail ok 80 - col_isnt_pk( table, column ) should have the proper description ok 81 - col_isnt_pk( table, column ) should have the proper diagnostics ok 82 - col_isnt_pk( schema, table, column, description ) pass should pass ok 83 - col_isnt_pk( schema, table, column, description ) pass should have the proper description ok 84 - col_isnt_pk( schema, table, column, description ) pass should have the proper diagnostics ok 85 - col_isnt_pk( table, column, description ) pass should pass ok 86 - col_isnt_pk( table, column, description ) pass should have the proper description ok 87 - col_isnt_pk( table, column, description ) pass should have the proper diagnostics ok 88 - col_isnt_pk( schema, table, column[], description ) should pass ok 89 - col_isnt_pk( schema, table, column[], description ) should have the proper description ok 90 - col_isnt_pk( schema, table, column[], description ) should have the proper diagnostics ok 91 - col_isnt_pk( table, column[], description ) should pass ok 92 - col_isnt_pk( table, column[], description ) should have the proper description ok 93 - col_isnt_pk( table, column[], description ) should have the proper diagnostics ok 94 - col_isnt_pk( table, column[] ) should pass ok 95 - col_isnt_pk( table, column[] ) should have the proper description ok 96 - col_isnt_pk( table, column[] ) should have the proper diagnostics pgtap-1.3.2/test/expected/policy.out000066400000000000000000000403711455775703000174620ustar00rootroot00000000000000\unset ECHO 1..180 ok 1 - policies_are(schema, table, policies, desc) should pass ok 2 - policies_are(schema, table, policies, desc) should have the proper description ok 3 - policies_are(schema, table, policies, desc) should have the proper diagnostics ok 4 - policies_are(schema, table, policies) should pass ok 5 - policies_are(schema, table, policies) should have the proper description ok 6 - policies_are(schema, table, policies) should have the proper diagnostics ok 7 - policies_are(schema, table, policies) + extra should fail ok 8 - policies_are(schema, table, policies) + extra should have the proper description ok 9 - policies_are(schema, table, policies) + extra should have the proper diagnostics ok 10 - policies_are(schema, table, policies) + missing should fail ok 11 - policies_are(schema, table, policies) + missing should have the proper description ok 12 - policies_are(schema, table, policies) + missing should have the proper diagnostics ok 13 - policies_are(schema, table, policies) + extra & missing should fail ok 14 - policies_are(schema, table, policies) + extra & missing should have the proper description ok 15 - policies_are(schema, table, policies) + extra & missing should have the proper diagnostics ok 16 - policies_are(table, policies, desc) should pass ok 17 - policies_are(table, policies, desc) should have the proper description ok 18 - policies_are(table, policies, desc) should have the proper diagnostics ok 19 - policies_are(table, policies) should pass ok 20 - policies_are(table, policies) should have the proper description ok 21 - policies_are(table, policies) should have the proper diagnostics ok 22 - policies_are(table, policies) + extra should fail ok 23 - policies_are(table, policies) + extra should have the proper description ok 24 - policies_are(table, policies) + extra should have the proper diagnostics ok 25 - policies_are(table, policies) + missing should fail ok 26 - policies_are(table, policies) + missing should have the proper description ok 27 - policies_are(table, policies) + missing should have the proper diagnostics ok 28 - policies_are(table, policies) + extra & missing should fail ok 29 - policies_are(table, policies) + extra & missing should have the proper description ok 30 - policies_are(table, policies) + extra & missing should have the proper diagnostics ok 31 - policy_roles_are(schema, table, policy, roles, desc) should pass ok 32 - policy_roles_are(schema, table, policy, roles, desc) should have the proper description ok 33 - policy_roles_are(schema, table, policy, roles, desc) should have the proper diagnostics ok 34 - policy_roles_are(schema, table, policy, roles) should pass ok 35 - policy_roles_are(schema, table, policy, roles) should have the proper description ok 36 - policy_roles_are(schema, table, policy, roles) should have the proper diagnostics ok 37 - policy_roles_are(schema, table, policy, roles) + extra should fail ok 38 - policy_roles_are(schema, table, policy, roles) + extra should have the proper description ok 39 - policy_roles_are(schema, table, policy, roles) + extra should have the proper diagnostics ok 40 - policy_roles_are(schema, table, policy, roles) + missing should fail ok 41 - policy_roles_are(schema, table, policy, roles) + missing should have the proper description ok 42 - policy_roles_are(schema, table, policy, roles) + missing should have the proper diagnostics ok 43 - policy_roles_are(schema, table, policy, roles) + extra & missing should fail ok 44 - policy_roles_are(schema, table, policy, roles) + extra & missing should have the proper description ok 45 - policy_roles_are(schema, table, policy, roles) + extra & missing should have the proper diagnostics ok 46 - policy_roles_are(table, policy, roles, desc) should pass ok 47 - policy_roles_are(table, policy, roles, desc) should have the proper description ok 48 - policy_roles_are(table, policy, roles, desc) should have the proper diagnostics ok 49 - policy_roles_are(table, policy, roles) should pass ok 50 - policy_roles_are(table, policy, roles) should have the proper description ok 51 - policy_roles_are(table, policy, roles) should have the proper diagnostics ok 52 - policy_roles_are(table, policy, roles) + extra should fail ok 53 - policy_roles_are(table, policy, roles) + extra should have the proper description ok 54 - policy_roles_are(table, policy, roles) + extra should have the proper diagnostics ok 55 - policy_roles_are(table, policy, roles) + missing should fail ok 56 - policy_roles_are(table, policy, roles) + missing should have the proper description ok 57 - policy_roles_are(table, policy, roles) + missing should have the proper diagnostics ok 58 - policy_roles_are(table, policy, roles) + extra & missing should fail ok 59 - policy_roles_are(table, policy, roles) + extra & missing should have the proper description ok 60 - policy_roles_are(table, policy, roles) + extra & missing should have the proper diagnostics ok 61 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should pass ok 62 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should have the proper description ok 63 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should have the proper diagnostics ok 64 - policy_cmd_is(schema, table, policy, command) for SELECT should pass ok 65 - policy_cmd_is(schema, table, policy, command) for SELECT should have the proper description ok 66 - policy_cmd_is(schema, table, policy, command) for SELECT should have the proper diagnostics ok 67 - policy_cmd_is(table, policy, command, desc) for SELECT should pass ok 68 - policy_cmd_is(table, policy, command, desc) for SELECT should have the proper description ok 69 - policy_cmd_is(table, policy, command, desc) for SELECT should have the proper diagnostics ok 70 - policy_cmd_is(table, policy, command) for SELECT should pass ok 71 - policy_cmd_is(table, policy, command) for SELECT should have the proper description ok 72 - policy_cmd_is(table, policy, command) for SELECT should have the proper diagnostics ok 73 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should fail should fail ok 74 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should fail should have the proper description ok 75 - policy_cmd_is(schema, table, policy, command, desc) for SELECT should fail should have the proper diagnostics ok 76 - policy_cmd_is(schema, table, policy, command) for SELECT should fail should fail ok 77 - policy_cmd_is(schema, table, policy, command) for SELECT should fail should have the proper description ok 78 - policy_cmd_is(schema, table, policy, command) for SELECT should fail should have the proper diagnostics ok 79 - policy_cmd_is(table, policy, command, desc) for SELECT should fail should fail ok 80 - policy_cmd_is(table, policy, command, desc) for SELECT should fail should have the proper description ok 81 - policy_cmd_is(table, policy, command, desc) for SELECT should fail should have the proper diagnostics ok 82 - policy_cmd_is(table, policy, command) for SELECT should fail should fail ok 83 - policy_cmd_is(table, policy, command) for SELECT should fail should have the proper description ok 84 - policy_cmd_is(table, policy, command) for SELECT should fail should have the proper diagnostics ok 85 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should pass ok 86 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should have the proper description ok 87 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should have the proper diagnostics ok 88 - policy_cmd_is(schema, table, policy, command) for INSERT should pass ok 89 - policy_cmd_is(schema, table, policy, command) for INSERT should have the proper description ok 90 - policy_cmd_is(schema, table, policy, command) for INSERT should have the proper diagnostics ok 91 - policy_cmd_is(table, policy, command, desc) for INSERT should pass ok 92 - policy_cmd_is(table, policy, command, desc) for INSERT should have the proper description ok 93 - policy_cmd_is(table, policy, command, desc) for INSERT should have the proper diagnostics ok 94 - policy_cmd_is(table, policy, command) for INSERT should pass ok 95 - policy_cmd_is(table, policy, command) for INSERT should have the proper description ok 96 - policy_cmd_is(table, policy, command) for INSERT should have the proper diagnostics ok 97 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should fail should fail ok 98 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should fail should have the proper description ok 99 - policy_cmd_is(schema, table, policy, command, desc) for INSERT should fail should have the proper diagnostics ok 100 - policy_cmd_is(schema, table, policy, command) for INSERT should fail should fail ok 101 - policy_cmd_is(schema, table, policy, command) for INSERT should fail should have the proper description ok 102 - policy_cmd_is(schema, table, policy, command) for INSERT should fail should have the proper diagnostics ok 103 - policy_cmd_is(table, policy, command, desc) for INSERT should fail should fail ok 104 - policy_cmd_is(table, policy, command, desc) for INSERT should fail should have the proper description ok 105 - policy_cmd_is(table, policy, command, desc) for INSERT should fail should have the proper diagnostics ok 106 - policy_cmd_is(table, policy, command) for INSERT should fail should fail ok 107 - policy_cmd_is(table, policy, command) for INSERT should fail should have the proper description ok 108 - policy_cmd_is(table, policy, command) for INSERT should fail should have the proper diagnostics ok 109 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should pass ok 110 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should have the proper description ok 111 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should have the proper diagnostics ok 112 - policy_cmd_is(schema, table, policy, command) for UPDATE should pass ok 113 - policy_cmd_is(schema, table, policy, command) for UPDATE should have the proper description ok 114 - policy_cmd_is(schema, table, policy, command) for UPDATE should have the proper diagnostics ok 115 - policy_cmd_is(table, policy, command, desc) for UPDATE should pass ok 116 - policy_cmd_is(table, policy, command, desc) for UPDATE should have the proper description ok 117 - policy_cmd_is(table, policy, command, desc) for UPDATE should have the proper diagnostics ok 118 - policy_cmd_is(table, policy, command) for UPDATE should pass ok 119 - policy_cmd_is(table, policy, command) for UPDATE should have the proper description ok 120 - policy_cmd_is(table, policy, command) for UPDATE should have the proper diagnostics ok 121 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should fail should fail ok 122 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should fail should have the proper description ok 123 - policy_cmd_is(schema, table, policy, command, desc) for UPDATE should fail should have the proper diagnostics ok 124 - policy_cmd_is(schema, table, policy, command) for UPDATE should fail should fail ok 125 - policy_cmd_is(schema, table, policy, command) for UPDATE should fail should have the proper description ok 126 - policy_cmd_is(schema, table, policy, command) for UPDATE should fail should have the proper diagnostics ok 127 - policy_cmd_is(table, policy, command, desc) for UPDATE should fail should fail ok 128 - policy_cmd_is(table, policy, command, desc) for UPDATE should fail should have the proper description ok 129 - policy_cmd_is(table, policy, command, desc) for UPDATE should fail should have the proper diagnostics ok 130 - policy_cmd_is(table, policy, command) for UPDATE should fail should fail ok 131 - policy_cmd_is(table, policy, command) for UPDATE should fail should have the proper description ok 132 - policy_cmd_is(table, policy, command) for UPDATE should fail should have the proper diagnostics ok 133 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should pass ok 134 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should have the proper description ok 135 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should have the proper diagnostics ok 136 - policy_cmd_is(schema, table, policy, command) for DELETE should pass ok 137 - policy_cmd_is(schema, table, policy, command) for DELETE should have the proper description ok 138 - policy_cmd_is(schema, table, policy, command) for DELETE should have the proper diagnostics ok 139 - policy_cmd_is(table, policy, command, desc) for DELETE should pass ok 140 - policy_cmd_is(table, policy, command, desc) for DELETE should have the proper description ok 141 - policy_cmd_is(table, policy, command, desc) for DELETE should have the proper diagnostics ok 142 - policy_cmd_is(table, policy, command) for DELETE should pass ok 143 - policy_cmd_is(table, policy, command) for DELETE should have the proper description ok 144 - policy_cmd_is(table, policy, command) for DELETE should have the proper diagnostics ok 145 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should fail should fail ok 146 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should fail should have the proper description ok 147 - policy_cmd_is(schema, table, policy, command, desc) for DELETE should fail should have the proper diagnostics ok 148 - policy_cmd_is(schema, table, policy, command) for DELETE should fail should fail ok 149 - policy_cmd_is(schema, table, policy, command) for DELETE should fail should have the proper description ok 150 - policy_cmd_is(schema, table, policy, command) for DELETE should fail should have the proper diagnostics ok 151 - policy_cmd_is(table, policy, command, desc) for DELETE should fail should fail ok 152 - policy_cmd_is(table, policy, command, desc) for DELETE should fail should have the proper description ok 153 - policy_cmd_is(table, policy, command, desc) for DELETE should fail should have the proper diagnostics ok 154 - policy_cmd_is(table, policy, command) for DELETE should fail should fail ok 155 - policy_cmd_is(table, policy, command) for DELETE should fail should have the proper description ok 156 - policy_cmd_is(table, policy, command) for DELETE should fail should have the proper diagnostics ok 157 - policy_cmd_is(schema, table, policy, command, desc) for ALL should pass ok 158 - policy_cmd_is(schema, table, policy, command, desc) for ALL should have the proper description ok 159 - policy_cmd_is(schema, table, policy, command, desc) for ALL should have the proper diagnostics ok 160 - policy_cmd_is(schema, table, policy, command) for ALL should pass ok 161 - policy_cmd_is(schema, table, policy, command) for ALL should have the proper description ok 162 - policy_cmd_is(schema, table, policy, command) for ALL should have the proper diagnostics ok 163 - policy_cmd_is(table, policy, command, desc) for ALL should pass ok 164 - policy_cmd_is(table, policy, command, desc) for ALL should have the proper description ok 165 - policy_cmd_is(table, policy, command, desc) for ALL should have the proper diagnostics ok 166 - policy_cmd_is(table, policy, command) for ALL should pass ok 167 - policy_cmd_is(table, policy, command) for ALL should have the proper description ok 168 - policy_cmd_is(table, policy, command) for ALL should have the proper diagnostics ok 169 - policy_cmd_is(schema, table, policy, command, desc) for ALL should fail should fail ok 170 - policy_cmd_is(schema, table, policy, command, desc) for ALL should fail should have the proper description ok 171 - policy_cmd_is(schema, table, policy, command, desc) for ALL should fail should have the proper diagnostics ok 172 - policy_cmd_is(schema, table, policy, command) for ALL should fail should fail ok 173 - policy_cmd_is(schema, table, policy, command) for ALL should fail should have the proper description ok 174 - policy_cmd_is(schema, table, policy, command) for ALL should fail should have the proper diagnostics ok 175 - policy_cmd_is(table, policy, command, desc) for ALL should fail should fail ok 176 - policy_cmd_is(table, policy, command, desc) for ALL should fail should have the proper description ok 177 - policy_cmd_is(table, policy, command, desc) for ALL should fail should have the proper diagnostics ok 178 - policy_cmd_is(table, policy, command) for ALL should fail should fail ok 179 - policy_cmd_is(table, policy, command) for ALL should fail should have the proper description ok 180 - policy_cmd_is(table, policy, command) for ALL should fail should have the proper diagnostics pgtap-1.3.2/test/expected/privs.out000066400000000000000000000736511455775703000173350ustar00rootroot00000000000000\unset ECHO 1..372 ok 1 - table_privs_are(sch, tab, role, privs, desc) should pass ok 2 - table_privs_are(sch, tab, role, privs, desc) should have the proper description ok 3 - table_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 4 - table_privs_are(LOL, ATable, role, privs, desc) should pass ok 5 - table_privs_are(LOL, ATable, role, privs, desc) should have the proper description ok 6 - table_privs_are(LOL, ATable, role, privs, desc) should have the proper diagnostics ok 7 - table_privs_are(sch, tab, role, privs) should pass ok 8 - table_privs_are(sch, tab, role, privs) should have the proper description ok 9 - table_privs_are(sch, tab, role, privs) should have the proper diagnostics ok 10 - table_privs_are(LOL, ATable, role, privs) should pass ok 11 - table_privs_are(LOL, ATable, role, privs) should have the proper description ok 12 - table_privs_are(LOL, ATable, role, privs) should have the proper diagnostics ok 13 - table_privs_are(tab, role, privs, desc) should pass ok 14 - table_privs_are(tab, role, privs, desc) should have the proper description ok 15 - table_privs_are(tab, role, privs, desc) should have the proper diagnostics ok 16 - table_privs_are(ATable, role, privs, desc) should pass ok 17 - table_privs_are(ATable, role, privs, desc) should have the proper description ok 18 - table_privs_are(ATable, role, privs, desc) should have the proper diagnostics ok 19 - table_privs_are(tab, role, privs) should pass ok 20 - table_privs_are(tab, role, privs) should have the proper description ok 21 - table_privs_are(tab, role, privs) should have the proper diagnostics ok 22 - table_privs_are(ATable, role, privs) should pass ok 23 - table_privs_are(ATable, role, privs) should have the proper description ok 24 - table_privs_are(ATable, role, privs) should have the proper diagnostics ok 25 - table_privs_are(sch, tab, role, some privs, desc) should fail ok 26 - table_privs_are(sch, tab, role, some privs, desc) should have the proper description ok 27 - table_privs_are(sch, tab, role, some privs, desc) should have the proper diagnostics ok 28 - table_privs_are(tab, role, some privs, desc) should fail ok 29 - table_privs_are(tab, role, some privs, desc) should have the proper description ok 30 - table_privs_are(tab, role, some privs, desc) should have the proper diagnostics ok 31 - table_privs_are(sch, tab, other, privs, desc) should fail ok 32 - table_privs_are(sch, tab, other, privs, desc) should have the proper description ok 33 - table_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 34 - table_privs_are(sch, tab, other, privs, desc) should pass ok 35 - table_privs_are(sch, tab, other, privs, desc) should have the proper description ok 36 - table_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 37 - table_privs_are(sch, tab, role, privs, desc) should fail ok 38 - table_privs_are(sch, tab, role, privs, desc) should have the proper description ok 39 - table_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 40 - table_privs_are(sch, tab, role, privs, desc) should fail ok 41 - table_privs_are(sch, tab, role, privs, desc) should have the proper description ok 42 - table_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 43 - table_privs_are(sch, tab, role, no privs) should fail ok 44 - table_privs_are(sch, tab, role, no privs) should have the proper description ok 45 - table_privs_are(sch, tab, role, no privs) should have the proper diagnostics ok 46 - table_privs_are(tab, role, no privs) should fail ok 47 - table_privs_are(tab, role, no privs) should have the proper description ok 48 - table_privs_are(tab, role, no privs) should have the proper diagnostics ok 49 - database_privs_are(db, role, privs, desc) should pass ok 50 - database_privs_are(db, role, privs, desc) should have the proper description ok 51 - database_privs_are(db, role, privs, desc) should have the proper diagnostics ok 52 - database_privs_are(db, role, privs, desc) should pass ok 53 - database_privs_are(db, role, privs, desc) should have the proper description ok 54 - database_privs_are(db, role, privs, desc) should have the proper diagnostics ok 55 - database_privs_are(non-db, role, privs, desc) should fail ok 56 - database_privs_are(non-db, role, privs, desc) should have the proper description ok 57 - database_privs_are(non-db, role, privs, desc) should have the proper diagnostics ok 58 - database_privs_are(db, non-role, privs, desc) should fail ok 59 - database_privs_are(db, non-role, privs, desc) should have the proper description ok 60 - database_privs_are(db, non-role, privs, desc) should have the proper diagnostics ok 61 - database_privs_are(db, ungranted, privs, desc) should fail ok 62 - database_privs_are(db, ungranted, privs, desc) should have the proper description ok 63 - database_privs_are(db, ungranted, privs, desc) should have the proper diagnostics ok 64 - database_privs_are(db, ungranted, privs, desc) should fail ok 65 - database_privs_are(db, ungranted, privs, desc) should have the proper description ok 66 - database_privs_are(db, ungranted, privs, desc) should have the proper diagnostics ok 67 - database_privs_are(db, non-role, no privs) should fail ok 68 - database_privs_are(db, non-role, no privs) should have the proper description ok 69 - database_privs_are(db, non-role, no privs) should have the proper diagnostics ok 70 - function_privs_are(sch, func, args, role, privs, desc) should pass ok 71 - function_privs_are(sch, func, args, role, privs, desc) should have the proper description ok 72 - function_privs_are(sch, func, args, role, privs, desc) should have the proper diagnostics ok 73 - function_privs_are(LOL, DoIt, role, privs, desc) should pass ok 74 - function_privs_are(LOL, DoIt, role, privs, desc) should have the proper description ok 75 - function_privs_are(LOL, DoIt, role, privs, desc) should have the proper diagnostics ok 76 - function_privs_are(sch, func, args, role, privs) should pass ok 77 - function_privs_are(sch, func, args, role, privs) should have the proper description ok 78 - function_privs_are(LOL, DoIt, args, role, privs) should pass ok 79 - function_privs_are(LOL, DoIt, args, role, privs) should have the proper description ok 80 - function_privs_are(func, args, role, privs, desc) should pass ok 81 - function_privs_are(func, args, role, privs, desc) should have the proper description ok 82 - function_privs_are(func, args, role, privs, desc) should have the proper diagnostics ok 83 - function_privs_are(DoIt, args, role, privs, desc) should pass ok 84 - function_privs_are(DoIt, args, role, privs, desc) should have the proper description ok 85 - function_privs_are(DoIt, args, role, privs, desc) should have the proper diagnostics ok 86 - function_privs_are(func, args, role, privs) should pass ok 87 - function_privs_are(func, args, role, privs) should have the proper description ok 88 - function_privs_are(DoIt, args, role, privs) should pass ok 89 - function_privs_are(DoIt, args, role, privs) should have the proper description ok 90 - function_privs_are(sch, non-func, args, role, privs, desc) should fail ok 91 - function_privs_are(sch, non-func, args, role, privs, desc) should have the proper description ok 92 - function_privs_are(sch, non-func, args, role, privs, desc) should have the proper diagnostics ok 93 - function_privs_are(non-func, args, role, privs, desc) should fail ok 94 - function_privs_are(non-func, args, role, privs, desc) should have the proper description ok 95 - function_privs_are(non-func, args, role, privs, desc) should have the proper diagnostics ok 96 - function_privs_are(sch, func, args, noone, privs, desc) should fail ok 97 - function_privs_are(sch, func, args, noone, privs, desc) should have the proper description ok 98 - function_privs_are(sch, func, args, noone, privs, desc) should have the proper diagnostics ok 99 - function_privs_are(func, args, noone, privs, desc) should fail ok 100 - function_privs_are(func, args, noone, privs, desc) should have the proper description ok 101 - function_privs_are(func, args, noone, privs, desc) should have the proper diagnostics ok 102 - function_privs_are(sch, func, args, other, privs, desc) should pass ok 103 - function_privs_are(sch, func, args, other, privs, desc) should have the proper description ok 104 - function_privs_are(sch, func, args, other, privs, desc) should have the proper diagnostics ok 105 - function_privs_are(func, args, other, privs, desc) should pass ok 106 - function_privs_are(func, args, other, privs, desc) should have the proper description ok 107 - function_privs_are(func, args, other, privs, desc) should have the proper diagnostics ok 108 - function_privs_are(sch, func, args, unpriv, privs, desc) should fail ok 109 - function_privs_are(sch, func, args, unpriv, privs, desc) should have the proper description ok 110 - function_privs_are(sch, func, args, unpriv, privs, desc) should have the proper diagnostics ok 111 - function_privs_are(func, args, unpriv, privs, desc) should fail ok 112 - function_privs_are(func, args, unpriv, privs, desc) should have the proper description ok 113 - function_privs_are(func, args, unpriv, privs, desc) should have the proper diagnostics ok 114 - function_privs_are(sch, func, args, unpriv, empty, desc) should pass ok 115 - function_privs_are(sch, func, args, unpriv, empty, desc) should have the proper description ok 116 - function_privs_are(sch, func, args, unpriv, empty, desc) should have the proper diagnostics ok 117 - function_privs_are(sch, func, args, unpriv, empty) should pass ok 118 - function_privs_are(sch, func, args, unpriv, empty) should have the proper description ok 119 - function_privs_are(func, args, unpriv, empty) should pass ok 120 - function_privs_are(func, args, unpriv, empty) should have the proper description ok 121 - function_privs_are(sch, func, args, unpriv, privs, desc) should fail ok 122 - function_privs_are(sch, func, args, unpriv, privs, desc) should have the proper description ok 123 - function_privs_are(sch, func, args, unpriv, privs, desc) should have the proper diagnostics ok 124 - function_privs_are(func, args, unpriv, privs, desc) should fail ok 125 - function_privs_are(func, args, unpriv, privs, desc) should have the proper description ok 126 - function_privs_are(func, args, unpriv, privs, desc) should have the proper diagnostics ok 127 - long function signature should pass ok 128 - long function signature should have the proper description ok 129 - long function signature should have the proper diagnostics ok 130 - language_privs_are(lang, role, privs, desc) should pass ok 131 - language_privs_are(lang, role, privs, desc) should have the proper description ok 132 - language_privs_are(lang, role, privs, desc) should have the proper diagnostics ok 133 - language_privs_are(lang, role, privs, desc) should pass ok 134 - language_privs_are(lang, role, privs, desc) should have the proper description ok 135 - language_privs_are(lang, role, privs, desc) should have the proper diagnostics ok 136 - language_privs_are(non-lang, role, privs, desc) should fail ok 137 - language_privs_are(non-lang, role, privs, desc) should have the proper description ok 138 - language_privs_are(non-lang, role, privs, desc) should have the proper diagnostics ok 139 - language_privs_are(lang, non-role, privs, desc) should fail ok 140 - language_privs_are(lang, non-role, privs, desc) should have the proper description ok 141 - language_privs_are(lang, non-role, privs, desc) should have the proper diagnostics ok 142 - language_privs_are(lang, ungranted, privs, desc) should fail ok 143 - language_privs_are(lang, ungranted, privs, desc) should have the proper description ok 144 - language_privs_are(lang, ungranted, privs, desc) should have the proper diagnostics ok 145 - language_privs_are(lang, role, no privs) should pass ok 146 - language_privs_are(lang, role, no privs) should have the proper description ok 147 - language_privs_are(lang, role, no privs) should have the proper diagnostics ok 148 - schema_privs_are(schema, role, privs, desc) should pass ok 149 - schema_privs_are(schema, role, privs, desc) should have the proper description ok 150 - schema_privs_are(schema, role, privs, desc) should have the proper diagnostics ok 151 - schema_privs_are(LOL, role, privs, desc) should pass ok 152 - schema_privs_are(LOL, role, privs, desc) should have the proper description ok 153 - schema_privs_are(LOL, role, privs, desc) should have the proper diagnostics ok 154 - schema_privs_are(schema, role, privs, desc) should pass ok 155 - schema_privs_are(schema, role, privs, desc) should have the proper description ok 156 - schema_privs_are(schema, role, privs, desc) should have the proper diagnostics ok 157 - schema_privs_are(LOL, role, privs, desc) should pass ok 158 - schema_privs_are(LOL, role, privs, desc) should have the proper description ok 159 - schema_privs_are(LOL, role, privs, desc) should have the proper diagnostics ok 160 - schema_privs_are(non-schema, role, privs, desc) should fail ok 161 - schema_privs_are(non-schema, role, privs, desc) should have the proper description ok 162 - schema_privs_are(non-schema, role, privs, desc) should have the proper diagnostics ok 163 - schema_privs_are(schema, non-role, privs, desc) should fail ok 164 - schema_privs_are(schema, non-role, privs, desc) should have the proper description ok 165 - schema_privs_are(schema, non-role, privs, desc) should have the proper diagnostics ok 166 - schema_privs_are(schema, ungranted, privs, desc) should fail ok 167 - schema_privs_are(schema, ungranted, privs, desc) should have the proper description ok 168 - schema_privs_are(schema, ungranted, privs, desc) should have the proper diagnostics ok 169 - schema_privs_are(schema, ungranted, privs, desc) should fail ok 170 - schema_privs_are(schema, ungranted, privs, desc) should have the proper description ok 171 - schema_privs_are(schema, ungranted, privs, desc) should have the proper diagnostics ok 172 - schema_privs_are(schema, non-role, no privs) should fail ok 173 - schema_privs_are(schema, non-role, no privs) should have the proper description ok 174 - schema_privs_are(schema, non-role, no privs) should have the proper diagnostics ok 175 - tablespace_privs_are(tablespace, role, privs, desc) should pass ok 176 - tablespace_privs_are(tablespace, role, privs, desc) should have the proper description ok 177 - tablespace_privs_are(tablespace, role, privs, desc) should have the proper diagnostics ok 178 - tablespace_privs_are(tablespace, role, privs, desc) should pass ok 179 - tablespace_privs_are(tablespace, role, privs, desc) should have the proper description ok 180 - tablespace_privs_are(tablespace, role, privs, desc) should have the proper diagnostics ok 181 - tablespace_privs_are(non-tablespace, role, privs, desc) should fail ok 182 - tablespace_privs_are(non-tablespace, role, privs, desc) should have the proper description ok 183 - tablespace_privs_are(non-tablespace, role, privs, desc) should have the proper diagnostics ok 184 - tablespace_privs_are(tablespace, non-role, privs, desc) should fail ok 185 - tablespace_privs_are(tablespace, non-role, privs, desc) should have the proper description ok 186 - tablespace_privs_are(tablespace, non-role, privs, desc) should have the proper diagnostics ok 187 - tablespace_privs_are(tablespace, ungranted, privs, desc) should fail ok 188 - tablespace_privs_are(tablespace, ungranted, privs, desc) should have the proper description ok 189 - tablespace_privs_are(tablespace, ungranted, privs, desc) should have the proper diagnostics ok 190 - tablespace_privs_are(tablespace, role, no privs) should pass ok 191 - tablespace_privs_are(tablespace, role, no privs) should have the proper description ok 192 - tablespace_privs_are(tablespace, role, no privs) should have the proper diagnostics ok 193 - sequence_privs_are(sch, seq, role, privs, desc) should pass ok 194 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper description ok 195 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper diagnostics ok 196 - sequence_privs_are(LOL, ASeq, role, privs, desc) should pass ok 197 - sequence_privs_are(LOL, ASeq, role, privs, desc) should have the proper description ok 198 - sequence_privs_are(LOL, ASeq, role, privs, desc) should have the proper diagnostics ok 199 - sequence_privs_are(sch, seq, role, privs) should pass ok 200 - sequence_privs_are(sch, seq, role, privs) should have the proper description ok 201 - sequence_privs_are(sch, seq, role, privs) should have the proper diagnostics ok 202 - sequence_privs_are(sch, seq, role, privs) should pass ok 203 - sequence_privs_are(sch, seq, role, privs) should have the proper description ok 204 - sequence_privs_are(sch, seq, role, privs) should have the proper diagnostics ok 205 - sequence_privs_are(seq, role, privs, desc) should pass ok 206 - sequence_privs_are(seq, role, privs, desc) should have the proper description ok 207 - sequence_privs_are(seq, role, privs, desc) should have the proper diagnostics ok 208 - sequence_privs_are(ASeq, role, privs, desc) should pass ok 209 - sequence_privs_are(ASeq, role, privs, desc) should have the proper description ok 210 - sequence_privs_are(ASeq, role, privs, desc) should have the proper diagnostics ok 211 - sequence_privs_are(seq, role, privs) should pass ok 212 - sequence_privs_are(seq, role, privs) should have the proper description ok 213 - sequence_privs_are(seq, role, privs) should have the proper diagnostics ok 214 - sequence_privs_are(seq, role, privs) should pass ok 215 - sequence_privs_are(seq, role, privs) should have the proper description ok 216 - sequence_privs_are(seq, role, privs) should have the proper diagnostics ok 217 - sequence_privs_are(sch, seq, role, some privs, desc) should fail ok 218 - sequence_privs_are(sch, seq, role, some privs, desc) should have the proper description ok 219 - sequence_privs_are(sch, seq, role, some privs, desc) should have the proper diagnostics ok 220 - sequence_privs_are(seq, role, some privs, desc) should fail ok 221 - sequence_privs_are(seq, role, some privs, desc) should have the proper description ok 222 - sequence_privs_are(seq, role, some privs, desc) should have the proper diagnostics ok 223 - sequence_privs_are(sch, seq, other, privs, desc) should fail ok 224 - sequence_privs_are(sch, seq, other, privs, desc) should have the proper description ok 225 - sequence_privs_are(sch, seq, other, privs, desc) should have the proper diagnostics ok 226 - sequence_privs_are(sch, seq, other, privs, desc) should pass ok 227 - sequence_privs_are(sch, seq, other, privs, desc) should have the proper description ok 228 - sequence_privs_are(sch, seq, other, privs, desc) should have the proper diagnostics ok 229 - sequence_privs_are(sch, seq, role, privs, desc) should fail ok 230 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper description ok 231 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper diagnostics ok 232 - sequence_privs_are(sch, seq, role, privs, desc) should fail ok 233 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper description ok 234 - sequence_privs_are(sch, seq, role, privs, desc) should have the proper diagnostics ok 235 - sequence_privs_are(sch, seq, role, no privs) should fail ok 236 - sequence_privs_are(sch, seq, role, no privs) should have the proper description ok 237 - sequence_privs_are(sch, seq, role, no privs) should have the proper diagnostics ok 238 - sequence_privs_are(seq, role, no privs) should fail ok 239 - sequence_privs_are(seq, role, no privs) should have the proper description ok 240 - sequence_privs_are(seq, role, no privs) should have the proper diagnostics ok 241 - any_column_privs_are(sch, tab, role, privs, desc) should pass ok 242 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper description ok 243 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 244 - any_column_privs_are(sch, tab, role, privs) should pass ok 245 - any_column_privs_are(sch, tab, role, privs) should have the proper description ok 246 - any_column_privs_are(sch, tab, role, privs) should have the proper diagnostics ok 247 - any_column_privs_are(tab, role, privs, desc) should pass ok 248 - any_column_privs_are(tab, role, privs, desc) should have the proper description ok 249 - any_column_privs_are(tab, role, privs, desc) should have the proper diagnostics ok 250 - any_column_privs_are(tab, role, privs) should pass ok 251 - any_column_privs_are(tab, role, privs) should have the proper description ok 252 - any_column_privs_are(tab, role, privs) should have the proper diagnostics ok 253 - any_column_privs_are(sch, tab, role, some privs, desc) should fail ok 254 - any_column_privs_are(sch, tab, role, some privs, desc) should have the proper description ok 255 - any_column_privs_are(sch, tab, role, some privs, desc) should have the proper diagnostics ok 256 - any_column_privs_are(tab, role, some privs, desc) should fail ok 257 - any_column_privs_are(tab, role, some privs, desc) should have the proper description ok 258 - any_column_privs_are(tab, role, some privs, desc) should have the proper diagnostics ok 259 - any_column_privs_are(sch, tab, other, privs, desc) should fail ok 260 - any_column_privs_are(sch, tab, other, privs, desc) should have the proper description ok 261 - any_column_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 262 - any_column_privs_are(sch, tab, other, privs, desc) should pass ok 263 - any_column_privs_are(sch, tab, other, privs, desc) should have the proper description ok 264 - any_column_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 265 - any_column_privs_are(sch, tab, role, privs, desc) should fail ok 266 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper description ok 267 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 268 - any_column_privs_are(sch, tab, role, privs, desc) should fail ok 269 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper description ok 270 - any_column_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 271 - any_column_privs_are(sch, tab, role, no privs) should fail ok 272 - any_column_privs_are(sch, tab, role, no privs) should have the proper description ok 273 - any_column_privs_are(sch, tab, role, no privs) should have the proper diagnostics ok 274 - any_column_privs_are(tab, role, no privs) should fail ok 275 - any_column_privs_are(tab, role, no privs) should have the proper description ok 276 - any_column_privs_are(tab, role, no privs) should have the proper diagnostics ok 277 - column_privs_are(sch, tab, col, role, privs, desc) should pass ok 278 - column_privs_are(sch, tab, col, role, privs, desc) should have the proper description ok 279 - column_privs_are(sch, tab, col, role, privs, desc) should have the proper diagnostics ok 280 - column_privs_are(LOL, ATable, AColumn, role, privs, desc) should pass ok 281 - column_privs_are(LOL, ATable, AColumn, role, privs, desc) should have the proper description ok 282 - column_privs_are(LOL, ATable, AColumn, role, privs, desc) should have the proper diagnostics ok 283 - column_privs_are(sch, tab, col, role, privs) should pass ok 284 - column_privs_are(sch, tab, col, role, privs) should have the proper description ok 285 - column_privs_are(sch, tab, col, role, privs) should have the proper diagnostics ok 286 - column_privs_are(LOL, ATable, AColumn, role, privs) should pass ok 287 - column_privs_are(LOL, ATable, AColumn, role, privs) should have the proper description ok 288 - column_privs_are(LOL, ATable, AColumn, role, privs) should have the proper diagnostics ok 289 - column_privs_are(tab, col, role, privs, desc) should pass ok 290 - column_privs_are(tab, col, role, privs, desc) should have the proper description ok 291 - column_privs_are(tab, col, role, privs, desc) should have the proper diagnostics ok 292 - column_privs_are(tab, col, role, privs, desc) should pass ok 293 - column_privs_are(tab, col, role, privs, desc) should have the proper description ok 294 - column_privs_are(tab, col, role, privs, desc) should have the proper diagnostics ok 295 - column_privs_are(tab, col, role, privs) should pass ok 296 - column_privs_are(tab, col, role, privs) should have the proper description ok 297 - column_privs_are(tab, col, role, privs) should have the proper diagnostics ok 298 - column_privs_are(tab, col, role, privs) should pass ok 299 - column_privs_are(tab, col, role, privs) should have the proper description ok 300 - column_privs_are(tab, col, role, privs) should have the proper diagnostics ok 301 - column_privs_are(sch, tab, role, some privs, desc) should fail ok 302 - column_privs_are(sch, tab, role, some privs, desc) should have the proper description ok 303 - column_privs_are(sch, tab, role, some privs, desc) should have the proper diagnostics ok 304 - column_privs_are(tab, role, some privs, desc) should fail ok 305 - column_privs_are(tab, role, some privs, desc) should have the proper description ok 306 - column_privs_are(tab, role, some privs, desc) should have the proper diagnostics ok 307 - column_privs_are(sch, tab, other, privs, desc) should fail ok 308 - column_privs_are(sch, tab, other, privs, desc) should have the proper description ok 309 - column_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 310 - column_privs_are(sch, tab, other, privs, desc) should pass ok 311 - column_privs_are(sch, tab, other, privs, desc) should have the proper description ok 312 - column_privs_are(sch, tab, other, privs, desc) should have the proper diagnostics ok 313 - column_privs_are(sch, tab, role, privs, desc) should fail ok 314 - column_privs_are(sch, tab, role, privs, desc) should have the proper description ok 315 - column_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 316 - column_privs_are(sch, tab, role, privs, desc) should fail ok 317 - column_privs_are(sch, tab, role, privs, desc) should have the proper description ok 318 - column_privs_are(sch, tab, role, privs, desc) should have the proper diagnostics ok 319 - column_privs_are(sch, tab, role, no privs) should fail ok 320 - column_privs_are(sch, tab, role, no privs) should have the proper description ok 321 - column_privs_are(sch, tab, role, no privs) should have the proper diagnostics ok 322 - column_privs_are(tab, role, no privs) should fail ok 323 - column_privs_are(tab, role, no privs) should have the proper description ok 324 - column_privs_are(tab, role, no privs) should have the proper diagnostics ok 325 - fdw_privs_are(fdw, role, privs, desc) should pass ok 326 - fdw_privs_are(fdw, role, privs, desc) should have the proper description ok 327 - fdw_privs_are(fdw, role, privs, desc) should have the proper diagnostics ok 328 - fdw_privs_are(SomeFDW, role, privs, desc) should pass ok 329 - fdw_privs_are(SomeFDW, role, privs, desc) should have the proper description ok 330 - fdw_privs_are(SomeFDW, role, privs, desc) should have the proper diagnostics ok 331 - fdw_privs_are(fdw, role, privs, desc) should pass ok 332 - fdw_privs_are(fdw, role, privs, desc) should have the proper description ok 333 - fdw_privs_are(fdw, role, privs, desc) should have the proper diagnostics ok 334 - fdw_privs_are(SomeFDW, role, privs, desc) should pass ok 335 - fdw_privs_are(SomeFDW, role, privs, desc) should have the proper description ok 336 - fdw_privs_are(SomeFDW, role, privs, desc) should have the proper diagnostics ok 337 - fdw_privs_are(non-fdw, role, privs, desc) should fail ok 338 - fdw_privs_are(non-fdw, role, privs, desc) should have the proper description ok 339 - fdw_privs_are(non-fdw, role, privs, desc) should have the proper diagnostics ok 340 - fdw_privs_are(fdw, non-role, privs, desc) should fail ok 341 - fdw_privs_are(fdw, non-role, privs, desc) should have the proper description ok 342 - fdw_privs_are(fdw, non-role, privs, desc) should have the proper diagnostics ok 343 - fdw_privs_are(fdw, ungranted, privs, desc) should fail ok 344 - fdw_privs_are(fdw, ungranted, privs, desc) should have the proper description ok 345 - fdw_privs_are(fdw, ungranted, privs, desc) should have the proper diagnostics ok 346 - fdw_privs_are(fdw, role, no privs) should pass ok 347 - fdw_privs_are(fdw, role, no privs) should have the proper description ok 348 - fdw_privs_are(fdw, role, no privs) should have the proper diagnostics ok 349 - server_privs_are(server, role, privs, desc) should pass ok 350 - server_privs_are(server, role, privs, desc) should have the proper description ok 351 - server_privs_are(server, role, privs, desc) should have the proper diagnostics ok 352 - server_privs_are(SomeServer, role, privs, desc) should pass ok 353 - server_privs_are(SomeServer, role, privs, desc) should have the proper description ok 354 - server_privs_are(SomeServer, role, privs, desc) should have the proper diagnostics ok 355 - server_privs_are(server, role, privs, desc) should pass ok 356 - server_privs_are(server, role, privs, desc) should have the proper description ok 357 - server_privs_are(server, role, privs, desc) should have the proper diagnostics ok 358 - server_privs_are(SomeServer, role, privs, desc) should pass ok 359 - server_privs_are(SomeServer, role, privs, desc) should have the proper description ok 360 - server_privs_are(SomeServer, role, privs, desc) should have the proper diagnostics ok 361 - server_privs_are(non-server, role, privs, desc) should fail ok 362 - server_privs_are(non-server, role, privs, desc) should have the proper description ok 363 - server_privs_are(non-server, role, privs, desc) should have the proper diagnostics ok 364 - server_privs_are(server, non-role, privs, desc) should fail ok 365 - server_privs_are(server, non-role, privs, desc) should have the proper description ok 366 - server_privs_are(server, non-role, privs, desc) should have the proper diagnostics ok 367 - server_privs_are(server, ungranted, privs, desc) should fail ok 368 - server_privs_are(server, ungranted, privs, desc) should have the proper description ok 369 - server_privs_are(server, ungranted, privs, desc) should have the proper diagnostics ok 370 - server_privs_are(server, role, no privs) should pass ok 371 - server_privs_are(server, role, no privs) should have the proper description ok 372 - server_privs_are(server, role, no privs) should have the proper diagnostics pgtap-1.3.2/test/expected/proctap.out000066400000000000000000000314211455775703000176270ustar00rootroot00000000000000\unset ECHO 1..192 ok 1 - is_procedure(schema, proc, noargs, desc) should pass ok 2 - is_procedure(schema, proc, noargs, desc) should have the proper description ok 3 - is_procedure(schema, proc, noargs, desc) should have the proper diagnostics ok 4 - isnt_procedure(schema, proc, noargs, desc) should fail ok 5 - isnt_procedure(schema, proc, noargs, desc) should have the proper description ok 6 - isnt_procedure(schema, proc, noargs, desc) should have the proper diagnostics ok 7 - is_procedure(schema, func, noargs, desc) should fail ok 8 - is_procedure(schema, func, noargs, desc) should have the proper description ok 9 - is_procedure(schema, func, noargs, desc) should have the proper diagnostics ok 10 - isnt_procedure(schema, func, noargs, desc) should pass ok 11 - isnt_procedure(schema, func, noargs, desc) should have the proper description ok 12 - isnt_procedure(schema, func, noargs, desc) should have the proper diagnostics ok 13 - is_procedure(schema, proc, args, desc) should pass ok 14 - is_procedure(schema, proc, args, desc) should have the proper description ok 15 - is_procedure(schema, proc, args, desc) should have the proper diagnostics ok 16 - isnt_procedure(schema, proc, args, desc) should fail ok 17 - isnt_procedure(schema, proc, args, desc) should have the proper description ok 18 - isnt_procedure(schema, proc, args, desc) should have the proper diagnostics ok 19 - is_procedure(schema, func, args, desc) should fail ok 20 - is_procedure(schema, func, args, desc) should have the proper description ok 21 - is_procedure(schema, func, args, desc) should have the proper diagnostics ok 22 - isnt_procedure(schema, func, args, desc) should pass ok 23 - isnt_procedure(schema, func, args, desc) should have the proper description ok 24 - isnt_procedure(schema, func, args, desc) should have the proper diagnostics ok 25 - is_procedure(schema, noproc, noargs, desc) should fail ok 26 - is_procedure(schema, noproc, noargs, desc) should have the proper description ok 27 - is_procedure(schema, noproc, noargs, desc) should have the proper diagnostics ok 28 - isnt_procedure(schema, noproc, noargs, desc) should fail ok 29 - isnt_procedure(schema, noproc, noargs, desc) should have the proper description ok 30 - isnt_procedure(schema, noproc, noargs, desc) should have the proper diagnostics ok 31 - is_procedure(schema, proc, noargs) should pass ok 32 - is_procedure(schema, proc, noargs) should have the proper description ok 33 - is_procedure(schema, proc, noargs) should have the proper diagnostics ok 34 - isnt_procedure(schema, proc, noargs) should fail ok 35 - isnt_procedure(schema, proc, noargs) should have the proper description ok 36 - isnt_procedure(schema, proc, noargs) should have the proper diagnostics ok 37 - is_procedure(schema, func, noargs) should fail ok 38 - is_procedure(schema, func, noargs) should have the proper description ok 39 - is_procedure(schema, func, noargs) should have the proper diagnostics ok 40 - isnt_procedure(schema, func, noargs) should pass ok 41 - isnt_procedure(schema, func, noargs) should have the proper description ok 42 - isnt_procedure(schema, func, noargs) should have the proper diagnostics ok 43 - is_procedure(schema, proc, args) should pass ok 44 - is_procedure(schema, proc, args) should have the proper description ok 45 - is_procedure(schema, proc, args) should have the proper diagnostics ok 46 - isnt_procedure(schema, proc, args) should fail ok 47 - isnt_procedure(schema, proc, args) should have the proper description ok 48 - isnt_procedure(schema, proc, args) should have the proper diagnostics ok 49 - is_procedure(schema, func, args) should fail ok 50 - is_procedure(schema, func, args) should have the proper description ok 51 - is_procedure(schema, func, args) should have the proper diagnostics ok 52 - isnt_procedure(schema, func, args) should pass ok 53 - isnt_procedure(schema, func, args) should have the proper description ok 54 - isnt_procedure(schema, func, args) should have the proper diagnostics ok 55 - is_procedure(schema, noproc, noargs) should fail ok 56 - is_procedure(schema, noproc, noargs) should have the proper description ok 57 - is_procedure(schema, noproc, noargs) should have the proper diagnostics ok 58 - isnt_procedure(schema, noproc, noargs) should fail ok 59 - isnt_procedure(schema, noproc, noargs) should have the proper description ok 60 - isnt_procedure(schema, noproc, noargs) should have the proper diagnostics ok 61 - is_procedure(schema, proc, desc) should pass ok 62 - is_procedure(schema, proc, desc) should have the proper description ok 63 - is_procedure(schema, proc, desc) should have the proper diagnostics ok 64 - isnt_procedure(schema, proc, desc) should fail ok 65 - isnt_procedure(schema, proc, desc) should have the proper description ok 66 - isnt_procedure(schema, proc, desc) should have the proper diagnostics ok 67 - is_procedure(schema, func, desc) should fail ok 68 - is_procedure(schema, func, desc) should have the proper description ok 69 - is_procedure(schema, func, desc) should have the proper diagnostics ok 70 - isnt_procedure(schema, func, desc) should pass ok 71 - isnt_procedure(schema, func, desc) should have the proper description ok 72 - isnt_procedure(schema, func, desc) should have the proper diagnostics ok 73 - is_procedure(schema, noproc, desc) should fail ok 74 - is_procedure(schema, noproc, desc) should have the proper description ok 75 - is_procedure(schema, noproc, desc) should have the proper diagnostics ok 76 - isnt_procedure(schema, noproc, desc) should fail ok 77 - isnt_procedure(schema, noproc, desc) should have the proper description ok 78 - isnt_procedure(schema, noproc, desc) should have the proper diagnostics ok 79 - is_procedure(schema, proc) should pass ok 80 - is_procedure(schema, proc) should have the proper description ok 81 - is_procedure(schema, proc) should have the proper diagnostics ok 82 - isnt_procedure(schema, proc) should fail ok 83 - isnt_procedure(schema, proc) should have the proper description ok 84 - isnt_procedure(schema, proc) should have the proper diagnostics ok 85 - is_procedure(schema, func) should fail ok 86 - is_procedure(schema, func) should have the proper description ok 87 - is_procedure(schema, func) should have the proper diagnostics ok 88 - isnt_procedure(schema, func) should pass ok 89 - isnt_procedure(schema, func) should have the proper description ok 90 - isnt_procedure(schema, func) should have the proper diagnostics ok 91 - is_procedure(schema, noproc) should fail ok 92 - is_procedure(schema, noproc) should have the proper description ok 93 - is_procedure(schema, noproc) should have the proper diagnostics ok 94 - isnt_procedure(schema, noproc) should fail ok 95 - isnt_procedure(schema, noproc) should have the proper description ok 96 - isnt_procedure(schema, noproc) should have the proper diagnostics ok 97 - is_procedure(proc, noargs, desc) should pass ok 98 - is_procedure(proc, noargs, desc) should have the proper description ok 99 - is_procedure(proc, noargs, desc) should have the proper diagnostics ok 100 - isnt_procedure(proc, noargs, desc) should fail ok 101 - isnt_procedure(proc, noargs, desc) should have the proper description ok 102 - isnt_procedure(proc, noargs, desc) should have the proper diagnostics ok 103 - is_procedure(func, noargs, desc) should fail ok 104 - is_procedure(func, noargs, desc) should have the proper description ok 105 - is_procedure(func, noargs, desc) should have the proper diagnostics ok 106 - isnt_procedure(schema, func, noargs, desc) should pass ok 107 - isnt_procedure(schema, func, noargs, desc) should have the proper description ok 108 - isnt_procedure(schema, func, noargs, desc) should have the proper diagnostics ok 109 - is_procedure(proc, args, desc) should pass ok 110 - is_procedure(proc, args, desc) should have the proper description ok 111 - is_procedure(proc, args, desc) should have the proper diagnostics ok 112 - isnt_procedure(proc, args, desc) should fail ok 113 - isnt_procedure(proc, args, desc) should have the proper description ok 114 - isnt_procedure(proc, args, desc) should have the proper diagnostics ok 115 - is_procedure(unc, args, desc) should fail ok 116 - is_procedure(unc, args, desc) should have the proper description ok 117 - is_procedure(unc, args, desc) should have the proper diagnostics ok 118 - isnt_procedure(func, args, desc) should pass ok 119 - isnt_procedure(func, args, desc) should have the proper description ok 120 - isnt_procedure(func, args, desc) should have the proper diagnostics ok 121 - is_procedure(noproc, noargs, desc) should fail ok 122 - is_procedure(noproc, noargs, desc) should have the proper description ok 123 - is_procedure(noproc, noargs, desc) should have the proper diagnostics ok 124 - isnt_procedure(noproc, noargs, desc) should fail ok 125 - isnt_procedure(noproc, noargs, desc) should have the proper description ok 126 - isnt_procedure(noproc, noargs, desc) should have the proper diagnostics ok 127 - is_procedure(proc, noargs) should pass ok 128 - is_procedure(proc, noargs) should have the proper description ok 129 - is_procedure(proc, noargs) should have the proper diagnostics ok 130 - isnt_procedure(proc, noargs) should fail ok 131 - isnt_procedure(proc, noargs) should have the proper description ok 132 - isnt_procedure(proc, noargs) should have the proper diagnostics ok 133 - is_procedure(func, noargs) should fail ok 134 - is_procedure(func, noargs) should have the proper description ok 135 - is_procedure(func, noargs) should have the proper diagnostics ok 136 - isnt_procedure(schema, func, noargs) should pass ok 137 - isnt_procedure(schema, func, noargs) should have the proper description ok 138 - isnt_procedure(schema, func, noargs) should have the proper diagnostics ok 139 - is_procedure(proc, args) should pass ok 140 - is_procedure(proc, args) should have the proper description ok 141 - is_procedure(proc, args) should have the proper diagnostics ok 142 - isnt_procedure(proc, args) should fail ok 143 - isnt_procedure(proc, args) should have the proper description ok 144 - isnt_procedure(proc, args) should have the proper diagnostics ok 145 - is_procedure(unc, args) should fail ok 146 - is_procedure(unc, args) should have the proper description ok 147 - is_procedure(unc, args) should have the proper diagnostics ok 148 - isnt_procedure(func, args) should pass ok 149 - isnt_procedure(func, args) should have the proper description ok 150 - isnt_procedure(func, args) should have the proper diagnostics ok 151 - is_procedure(noproc, noargs) should fail ok 152 - is_procedure(noproc, noargs) should have the proper description ok 153 - is_procedure(noproc, noargs) should have the proper diagnostics ok 154 - isnt_procedure(noproc, noargs) should fail ok 155 - isnt_procedure(noproc, noargs) should have the proper description ok 156 - isnt_procedure(noproc, noargs) should have the proper diagnostics ok 157 - is_procedure(proc, desc) should pass ok 158 - is_procedure(proc, desc) should have the proper description ok 159 - is_procedure(proc, desc) should have the proper diagnostics ok 160 - isnt_procedure(proc, desc) should fail ok 161 - isnt_procedure(proc, desc) should have the proper description ok 162 - isnt_procedure(proc, desc) should have the proper diagnostics ok 163 - is_procedure(func, desc) should fail ok 164 - is_procedure(func, desc) should have the proper description ok 165 - is_procedure(func, desc) should have the proper diagnostics ok 166 - isnt_procedure(func, desc) should pass ok 167 - isnt_procedure(func, desc) should have the proper description ok 168 - isnt_procedure(func, desc) should have the proper diagnostics ok 169 - is_procedure(noproc, desc) should fail ok 170 - is_procedure(noproc, desc) should have the proper description ok 171 - is_procedure(noproc, desc) should have the proper diagnostics ok 172 - isnt_procedure(noproc, desc) should fail ok 173 - isnt_procedure(noproc, desc) should have the proper description ok 174 - isnt_procedure(noproc, desc) should have the proper diagnostics ok 175 - is_procedure(proc) should pass ok 176 - is_procedure(proc) should have the proper description ok 177 - is_procedure(proc) should have the proper diagnostics ok 178 - isnt_procedure(proc) should fail ok 179 - isnt_procedure(proc) should have the proper description ok 180 - isnt_procedure(proc) should have the proper diagnostics ok 181 - is_procedure(func) should fail ok 182 - is_procedure(func) should have the proper description ok 183 - is_procedure(func) should have the proper diagnostics ok 184 - isnt_procedure(func) should pass ok 185 - isnt_procedure(func) should have the proper description ok 186 - isnt_procedure(func) should have the proper diagnostics ok 187 - is_procedure(noproc) should fail ok 188 - is_procedure(noproc) should have the proper description ok 189 - is_procedure(noproc) should have the proper diagnostics ok 190 - isnt_procedure(noproc) should fail ok 191 - isnt_procedure(noproc) should have the proper description ok 192 - isnt_procedure(noproc) should have the proper diagnostics pgtap-1.3.2/test/expected/resultset.out000066400000000000000000001076231455775703000202210ustar00rootroot00000000000000\unset ECHO 1..545 ok 1 - Should create temp table with simple query ok 2 - Table __foonames__ should exist ok 3 - Should create a temp table for a prepared statement ok 4 - Table __somenames__ should exist ok 5 - Should create a temp table for a prepared statement with space ok 6 - Table __somenames__ should exist ok 7 - Table __spacenames__ should exist ok 8 - set_eq(prepared, prepared, desc) should pass ok 9 - set_eq(prepared, prepared, desc) should have the proper description ok 10 - set_eq(prepared, prepared, desc) should have the proper diagnostics ok 11 - set_eq(prepared, prepared) should pass ok 12 - set_eq(prepared, prepared) should have the proper description ok 13 - set_eq(prepared, prepared) should have the proper diagnostics ok 14 - set_eq(execute, execute, desc) should pass ok 15 - set_eq(execute, execute, desc) should have the proper description ok 16 - set_eq(execute, execute, desc) should have the proper diagnostics ok 17 - set_eq(select, select) should pass ok 18 - set_eq(select, select) should have the proper description ok 19 - set_eq(select, select) should have the proper diagnostics ok 20 - set_eq(values, dupe values) should pass ok 21 - set_eq(values, dupe values) should have the proper description ok 22 - set_eq(values, dupe values) should have the proper diagnostics ok 23 - set_eq(prepared, select) fail extra should fail ok 24 - set_eq(prepared, select) fail extra should have the proper description ok 25 - set_eq(prepared, select) fail extra should have the proper diagnostics ok 26 - set_eq(prepared, select) fail extras should fail ok 27 - set_eq(prepared, select) fail extras should have the proper description ok 28 - set_eq(prepared, select) fail extras should have the proper diagnostics ok 29 - set_eq(select, prepared) fail missing should fail ok 30 - set_eq(select, prepared) fail missing should have the proper description ok 31 - set_eq(select, prepared) fail missing should have the proper diagnostics ok 32 - set_eq(select, prepared) fail missings should fail ok 33 - set_eq(select, prepared) fail missings should have the proper description ok 34 - set_eq(select, prepared) fail missings should have the proper diagnostics ok 35 - set_eq(select, select) fail extra & missing should fail ok 36 - set_eq(select, select) fail extra & missing should have the proper description ok 37 - set_eq(select, select) fail extra & missing should have the proper diagnostics ok 38 - set_eq(select, select) fail extras & missings should fail ok 39 - set_eq(select, select) fail extras & missings should have the proper description ok 40 - set_eq(select, select) fail extras & missings should have the proper diagnostics ok 41 - set_eq(values, values) fail mismatch should fail ok 42 - set_eq(values, values) fail mismatch should have the proper description ok 43 - set_eq(values, values) fail mismatch should have the proper diagnostics ok 44 - set_eq(values, values) fail column count should fail ok 45 - set_eq(values, values) fail column count should have the proper description ok 46 - set_eq(values, values) fail column count should have the proper diagnostics ok 47 - set_eq(sql, sql) fail type schema visibility should fail ok 48 - set_eq(sql, sql) fail type schema visibility should have the proper description ok 49 - set_eq(sql, sql) fail type schema visibility should have the proper diagnostics ok 50 - bag_eq(prepared, prepared, desc) should pass ok 51 - bag_eq(prepared, prepared, desc) should have the proper description ok 52 - bag_eq(prepared, prepared, desc) should have the proper diagnostics ok 53 - bag_eq(prepared, prepared) should pass ok 54 - bag_eq(prepared, prepared) should have the proper description ok 55 - bag_eq(prepared, prepared) should have the proper diagnostics ok 56 - bag_eq(execute, execute) should pass ok 57 - bag_eq(execute, execute) should have the proper description ok 58 - bag_eq(execute, execute) should have the proper diagnostics ok 59 - bag_eq(select, select) should pass ok 60 - bag_eq(select, select) should have the proper description ok 61 - bag_eq(select, select) should have the proper diagnostics ok 62 - bag_eq(dupe values, dupe values) should pass ok 63 - bag_eq(dupe values, dupe values) should have the proper description ok 64 - bag_eq(dupe values, dupe values) should have the proper diagnostics ok 65 - bag_eq(prepared, select) fail extra should fail ok 66 - bag_eq(prepared, select) fail extra should have the proper description ok 67 - bag_eq(prepared, select) fail extra should have the proper diagnostics ok 68 - bag_eq(prepared, select) fail extras should fail ok 69 - bag_eq(prepared, select) fail extras should have the proper description ok 70 - bag_eq(prepared, select) fail extras should have the proper diagnostics ok 71 - bag_eq(select, prepared) fail missing should fail ok 72 - bag_eq(select, prepared) fail missing should have the proper description ok 73 - bag_eq(select, prepared) fail missing should have the proper diagnostics ok 74 - bag_eq(select, prepared) fail missings should fail ok 75 - bag_eq(select, prepared) fail missings should have the proper description ok 76 - bag_eq(select, prepared) fail missings should have the proper diagnostics ok 77 - bag_eq(select, select) fail extra & missing should fail ok 78 - bag_eq(select, select) fail extra & missing should have the proper description ok 79 - bag_eq(select, select) fail extra & missing should have the proper diagnostics ok 80 - bag_eq(select, select) fail extras & missings should fail ok 81 - bag_eq(select, select) fail extras & missings should have the proper description ok 82 - bag_eq(select, select) fail extras & missings should have the proper diagnostics ok 83 - bag_eq(values, values) fail mismatch should fail ok 84 - bag_eq(values, values) fail mismatch should have the proper description ok 85 - bag_eq(values, values) fail mismatch should have the proper diagnostics ok 86 - bag_eq(values, values) fail column count should fail ok 87 - bag_eq(values, values) fail column count should have the proper description ok 88 - bag_eq(values, values) fail column count should have the proper diagnostics ok 89 - bag_eq(values, values) fail missing dupe should fail ok 90 - bag_eq(values, values) fail missing dupe should have the proper description ok 91 - bag_eq(values, values) fail missing dupe should have the proper diagnostics ok 92 - set_ne(prepared, select, desc) should pass ok 93 - set_ne(prepared, select, desc) should have the proper description ok 94 - set_ne(prepared, select, desc) should have the proper diagnostics ok 95 - set_ne(prepared, select) should pass ok 96 - set_ne(prepared, select) should have the proper description ok 97 - set_ne(prepared, select) should have the proper diagnostics ok 98 - set_ne(prepared, prepared) fail should fail ok 99 - set_ne(prepared, prepared) fail should have the proper description ok 100 - set_ne(prepared, prepared) fail should have the proper diagnostics ok 101 - set_ne fail with column mismatch should fail ok 102 - set_ne fail with column mismatch should have the proper description ok 103 - set_ne fail with column mismatch should have the proper diagnostics ok 104 - set_ne fail with different col counts should fail ok 105 - set_ne fail with different col counts should have the proper description ok 106 - set_ne fail with different col counts should have the proper diagnostics ok 107 - set_ne fail with dupe should fail ok 108 - set_ne fail with dupe should have the proper description ok 109 - set_ne fail with dupe should have the proper diagnostics ok 110 - bag_ne(prepared, select, desc) should pass ok 111 - bag_ne(prepared, select, desc) should have the proper description ok 112 - bag_ne(prepared, select, desc) should have the proper diagnostics ok 113 - bag_ne(prepared, select) should pass ok 114 - bag_ne(prepared, select) should have the proper description ok 115 - bag_ne(prepared, select) should have the proper diagnostics ok 116 - bag_ne(prepared, prepared) fail should fail ok 117 - bag_ne(prepared, prepared) fail should have the proper description ok 118 - bag_ne(prepared, prepared) fail should have the proper diagnostics ok 119 - bag_ne fail with column mismatch should fail ok 120 - bag_ne fail with column mismatch should have the proper description ok 121 - bag_ne fail with column mismatch should have the proper diagnostics ok 122 - set_ne pass with dupe should pass ok 123 - set_ne pass with dupe should have the proper description ok 124 - set_ne pass with dupe should have the proper diagnostics ok 125 - bag_ne fail with column mismatch should fail ok 126 - bag_ne fail with column mismatch should have the proper description ok 127 - bag_ne fail with column mismatch should have the proper diagnostics ok 128 - bag_ne fail with different col counts should fail ok 129 - bag_ne fail with different col counts should have the proper description ok 130 - bag_ne fail with different col counts should have the proper diagnostics ok 131 - results_eq(prepared, prepared, desc) should pass ok 132 - results_eq(prepared, prepared, desc) should have the proper description ok 133 - results_eq(prepared, prepared, desc) should have the proper diagnostics ok 134 - results_eq(prepared, prepared) should pass ok 135 - results_eq(prepared, prepared) should have the proper description ok 136 - results_eq(prepared, prepared) should have the proper diagnostics ok 137 - results_eq(execute, execute) should pass ok 138 - results_eq(execute, execute) should have the proper description ok 139 - results_eq(execute, execute) should have the proper diagnostics ok 140 - results_eq(select, select) should pass ok 141 - results_eq(select, select) should have the proper description ok 142 - results_eq(select, select) should have the proper diagnostics ok 143 - results_eq(dupe values, dupe values) should pass ok 144 - results_eq(dupe values, dupe values) should have the proper description ok 145 - results_eq(dupe values, dupe values) should have the proper diagnostics ok 146 - results_eq(values with null, values with null) should pass ok 147 - results_eq(values with null, values with null) should have the proper description ok 148 - results_eq(values with null, values with null) should have the proper diagnostics ok 149 - results_eq(nulls, nulls) should pass ok 150 - results_eq(nulls, nulls) should have the proper description ok 151 - results_eq(nulls, nulls) should have the proper diagnostics ok 152 - results_eq(nulls, nulls) fail should fail ok 153 - results_eq(nulls, nulls) fail should have the proper description ok 154 - results_eq(nulls, nulls) fail should have the proper diagnostics ok 155 - results_eq(prepared, select) fail should fail ok 156 - results_eq(prepared, select) fail should have the proper description ok 157 - results_eq(prepared, select) fail should have the proper diagnostics ok 158 - results_eq(select, prepared) fail missing last row should fail ok 159 - results_eq(select, prepared) fail missing last row should have the proper description ok 160 - results_eq(select, prepared) fail missing last row should have the proper diagnostics ok 161 - results_eq(prepared, select) fail missing first row should fail ok 162 - results_eq(prepared, select) fail missing first row should have the proper description ok 163 - results_eq(prepared, select) fail missing first row should have the proper diagnostics ok 164 - results_eq(values dupe, values) should fail ok 165 - results_eq(values dupe, values) should have the proper description ok 166 - results_eq(values dupe, values) should have the proper diagnostics ok 167 - results_eq(values null, values) should fail ok 168 - results_eq(values null, values) should have the proper description ok 169 - results_eq(values null, values) should have the proper diagnostics ok 170 - results_eq(values, values) mismatch should fail ok 171 - results_eq(values, values) mismatch should have the proper description ok 172 - results_eq(values, values) mismatch should have the proper diagnostics ok 173 - results_eq(values, values) subtle mismatch should fail ok 174 - results_eq(values, values) subtle mismatch should have the proper description ok 175 - results_eq(values, values) subtle mismatch should have the proper diagnostics ok 176 - results_eq(values, values) integer type mismatch should fail ok 177 - results_eq(values, values) integer type mismatch should have the proper description ok 178 - results_eq(values, values) integer type mismatch should have the proper diagnostics ok 179 - results_eq(values, values) fail column count should fail ok 180 - results_eq(values, values) fail column count should have the proper description ok 181 - results_eq(values, values) fail column count should have the proper diagnostics ok 182 - results_eq(cursor, cursor) should pass ok 183 - results_eq(cursor, cursor) should have the proper description ok 184 - results_eq(cursor, cursor) should have the proper diagnostics ok 185 - results_eq(cursor, prepared) should pass ok 186 - results_eq(cursor, prepared) should have the proper description ok 187 - results_eq(cursor, prepared) should have the proper diagnostics ok 188 - results_eq(prepared, cursor) should pass ok 189 - results_eq(prepared, cursor) should have the proper description ok 190 - results_eq(prepared, cursor) should have the proper diagnostics ok 191 - results_eq(cursor, sql) should pass ok 192 - results_eq(cursor, sql) should have the proper description ok 193 - results_eq(cursor, sql) should have the proper diagnostics ok 194 - results_eq(sql, cursor) should pass ok 195 - results_eq(sql, cursor) should have the proper description ok 196 - results_eq(sql, cursor) should have the proper diagnostics ok 197 - set_has( prepared, prepared, description ) should pass ok 198 - set_has( prepared, prepared, description ) should have the proper description ok 199 - set_has( prepared, prepared, description ) should have the proper diagnostics ok 200 - set_has( prepared, subprepared ) should pass ok 201 - set_has( prepared, subprepared ) should have the proper description ok 202 - set_has( prepared, subprepared ) should have the proper diagnostics ok 203 - set_has( execute, execute ) should pass ok 204 - set_has( execute, execute ) should have the proper description ok 205 - set_has( execute, execute ) should have the proper diagnostics ok 206 - set_has( select, select ) should pass ok 207 - set_has( select, select ) should have the proper description ok 208 - set_has( select, select ) should have the proper diagnostics ok 209 - set_has( prepared, empty ) should pass ok 210 - set_has( prepared, empty ) should have the proper description ok 211 - set_has( prepared, empty ) should have the proper diagnostics ok 212 - set_has( prepared, dupes ) should pass ok 213 - set_has( prepared, dupes ) should have the proper description ok 214 - set_has( prepared, dupes ) should have the proper diagnostics ok 215 - set_has( dupes, values ) should pass ok 216 - set_has( dupes, values ) should have the proper description ok 217 - set_has( dupes, values ) should have the proper diagnostics ok 218 - set_has( missing1, expect ) should fail ok 219 - set_has( missing1, expect ) should have the proper description ok 220 - set_has( missing1, expect ) should have the proper diagnostics ok 221 - set_has(missing2, expect ) should fail ok 222 - set_has(missing2, expect ) should have the proper description ok 223 - set_has(missing2, expect ) should have the proper diagnostics ok 224 - set_has((int,text), (text,int)) should fail ok 225 - set_has((int,text), (text,int)) should have the proper description ok 226 - set_has((int,text), (text,int)) should have the proper diagnostics ok 227 - set_has((int), (text,int)) should fail ok 228 - set_has((int), (text,int)) should have the proper description ok 229 - set_has((int), (text,int)) should have the proper diagnostics ok 230 - bag_has( prepared, prepared, description ) should pass ok 231 - bag_has( prepared, prepared, description ) should have the proper description ok 232 - bag_has( prepared, prepared, description ) should have the proper diagnostics ok 233 - bag_has( prepared, subprepared ) should pass ok 234 - bag_has( prepared, subprepared ) should have the proper description ok 235 - bag_has( prepared, subprepared ) should have the proper diagnostics ok 236 - bag_has( execute, execute ) should pass ok 237 - bag_has( execute, execute ) should have the proper description ok 238 - bag_has( execute, execute ) should have the proper diagnostics ok 239 - bag_has( select, select ) should pass ok 240 - bag_has( select, select ) should have the proper description ok 241 - bag_has( select, select ) should have the proper diagnostics ok 242 - bag_has( prepared, empty ) should pass ok 243 - bag_has( prepared, empty ) should have the proper description ok 244 - bag_has( prepared, empty ) should have the proper diagnostics ok 245 - bag_has( prepared, dupes ) should fail ok 246 - bag_has( prepared, dupes ) should have the proper description ok 247 - bag_has( prepared, dupes ) should have the proper diagnostics ok 248 - bag_has( dupes, values ) should pass ok 249 - bag_has( dupes, values ) should have the proper description ok 250 - bag_has( dupes, values ) should have the proper diagnostics ok 251 - bag_has( missing1, expect ) should fail ok 252 - bag_has( missing1, expect ) should have the proper description ok 253 - bag_has( missing1, expect ) should have the proper diagnostics ok 254 - bag_has(missing2, expect ) should fail ok 255 - bag_has(missing2, expect ) should have the proper description ok 256 - bag_has(missing2, expect ) should have the proper diagnostics ok 257 - bag_has((int,text), (text,int)) should fail ok 258 - bag_has((int,text), (text,int)) should have the proper description ok 259 - bag_has((int,text), (text,int)) should have the proper diagnostics ok 260 - bag_has((int), (text,int)) should fail ok 261 - bag_has((int), (text,int)) should have the proper description ok 262 - bag_has((int), (text,int)) should have the proper diagnostics ok 263 - set_hasnt( prepared, prepared, description ) should pass ok 264 - set_hasnt( prepared, prepared, description ) should have the proper description ok 265 - set_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 266 - set_hasnt( prepared, prepared, description ) should pass ok 267 - set_hasnt( prepared, prepared, description ) should have the proper description ok 268 - set_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 269 - set_hasnt( execute, execute ) should pass ok 270 - set_hasnt( execute, execute ) should have the proper description ok 271 - set_hasnt( execute, execute ) should have the proper diagnostics ok 272 - set_hasnt( select, select ) should pass ok 273 - set_hasnt( select, select ) should have the proper description ok 274 - set_hasnt( select, select ) should have the proper diagnostics ok 275 - set_hasnt( prepared, empty ) should pass ok 276 - set_hasnt( prepared, empty ) should have the proper description ok 277 - set_hasnt( prepared, empty ) should have the proper diagnostics ok 278 - set_hasnt( prepared, dupes ) should pass ok 279 - set_hasnt( prepared, dupes ) should have the proper description ok 280 - set_hasnt( prepared, dupes ) should have the proper diagnostics ok 281 - set_hasnt( prepared, value ) should fail ok 282 - set_hasnt( prepared, value ) should have the proper description ok 283 - set_hasnt( prepared, value ) should have the proper diagnostics ok 284 - set_hasnt( prepared, values ) should fail ok 285 - set_hasnt( prepared, values ) should have the proper description ok 286 - set_hasnt( prepared, values ) should have the proper diagnostics ok 287 - set_hasnt((int,text), (text,int)) should fail ok 288 - set_hasnt((int,text), (text,int)) should have the proper description ok 289 - set_hasnt((int,text), (text,int)) should have the proper diagnostics ok 290 - set_hasnt((int), (text,int)) should fail ok 291 - set_hasnt((int), (text,int)) should have the proper description ok 292 - set_hasnt((int), (text,int)) should have the proper diagnostics ok 293 - bag_hasnt( prepared, prepared, description ) should pass ok 294 - bag_hasnt( prepared, prepared, description ) should have the proper description ok 295 - bag_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 296 - bag_hasnt( prepared, prepared, description ) should pass ok 297 - bag_hasnt( prepared, prepared, description ) should have the proper description ok 298 - bag_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 299 - bag_hasnt( execute, execute ) should pass ok 300 - bag_hasnt( execute, execute ) should have the proper description ok 301 - bag_hasnt( execute, execute ) should have the proper diagnostics ok 302 - bag_hasnt( select, select ) should pass ok 303 - bag_hasnt( select, select ) should have the proper description ok 304 - bag_hasnt( select, select ) should have the proper diagnostics ok 305 - bag_hasnt( prepared, empty ) should pass ok 306 - bag_hasnt( prepared, empty ) should have the proper description ok 307 - bag_hasnt( prepared, empty ) should have the proper diagnostics ok 308 - bag_hasnt( prepared, value ) should fail ok 309 - bag_hasnt( prepared, value ) should have the proper description ok 310 - bag_hasnt( prepared, value ) should have the proper diagnostics ok 311 - bag_hasnt( prepared, values ) should fail ok 312 - bag_hasnt( prepared, values ) should have the proper description ok 313 - bag_hasnt( prepared, values ) should have the proper diagnostics ok 314 - bag_hasnt((int,text), (text,int)) should fail ok 315 - bag_hasnt((int,text), (text,int)) should have the proper description ok 316 - bag_hasnt((int,text), (text,int)) should have the proper diagnostics ok 317 - bag_hasnt((int), (text,int)) should fail ok 318 - bag_hasnt((int), (text,int)) should have the proper description ok 319 - bag_hasnt((int), (text,int)) should have the proper diagnostics ok 320 - bag_hasnt( dupes, dupes ) should fail ok 321 - bag_hasnt( dupes, dupes ) should have the proper description ok 322 - bag_hasnt( dupes, dupes ) should have the proper diagnostics ok 323 - bag_hasnt( value, dupes ) should fail ok 324 - bag_hasnt( value, dupes ) should have the proper description ok 325 - bag_hasnt( value, dupes ) should have the proper diagnostics ok 326 - set_eq(sql, array, desc) should pass ok 327 - set_eq(sql, array, desc) should have the proper description ok 328 - set_eq(sql, array, desc) should have the proper diagnostics ok 329 - set_eq(sql, array) should pass ok 330 - set_eq(sql, array) should have the proper description ok 331 - set_eq(sql, array) should have the proper diagnostics ok 332 - set_eq(sql, dupe array) should pass ok 333 - set_eq(sql, dupe array) should have the proper description ok 334 - set_eq(sql, dupe array) should have the proper diagnostics ok 335 - set_eq(sql, array) extra record should fail ok 336 - set_eq(sql, array) extra record should have the proper description ok 337 - set_eq(sql, array) extra record should have the proper diagnostics ok 338 - set_eq(sql, array) missing record should fail ok 339 - set_eq(sql, array) missing record should have the proper description ok 340 - set_eq(sql, array) missing record should have the proper diagnostics ok 341 - set_eq(sql, array) incompatible types should fail ok 342 - set_eq(sql, array) incompatible types should have the proper description ok 343 - set_eq(sql, array) incompatible types should have the proper diagnostics ok 344 - set_eq(sql, array) incompatible types should fail ok 345 - set_eq(sql, array) incompatible types should have the proper description ok 346 - set_eq(sql, array) incompatible types should have the proper diagnostics ok 347 - bag_eq(sql, array, desc) should pass ok 348 - bag_eq(sql, array, desc) should have the proper description ok 349 - bag_eq(sql, array, desc) should have the proper diagnostics ok 350 - bag_eq(sql, array) should pass ok 351 - bag_eq(sql, array) should have the proper description ok 352 - bag_eq(sql, array) should have the proper diagnostics ok 353 - bag_eq(sql, dupe array) fail should fail ok 354 - bag_eq(sql, dupe array) fail should have the proper description ok 355 - bag_eq(sql, dupe array) fail should have the proper diagnostics ok 356 - bag_eq(sql, array) extra record should fail ok 357 - bag_eq(sql, array) extra record should have the proper description ok 358 - bag_eq(sql, array) extra record should have the proper diagnostics ok 359 - bag_eq(sql, array) missing record should fail ok 360 - bag_eq(sql, array) missing record should have the proper description ok 361 - bag_eq(sql, array) missing record should have the proper diagnostics ok 362 - bag_eq(sql, array) incompatible types should fail ok 363 - bag_eq(sql, array) incompatible types should have the proper description ok 364 - bag_eq(sql, array) incompatible types should have the proper diagnostics ok 365 - bag_eq(sql, array) incompatible types should fail ok 366 - bag_eq(sql, array) incompatible types should have the proper description ok 367 - bag_eq(sql, array) incompatible types should have the proper diagnostics ok 368 - set_ne(sql, array, desc) should pass ok 369 - set_ne(sql, array, desc) should have the proper description ok 370 - set_ne(sql, array, desc) should have the proper diagnostics ok 371 - set_ne(sql, array) should pass ok 372 - set_ne(sql, array) should have the proper description ok 373 - set_ne(sql, array) should have the proper diagnostics ok 374 - set_ne(sql, array) fail should fail ok 375 - set_ne(sql, array) fail should have the proper description ok 376 - set_ne(sql, array) fail should have the proper diagnostics ok 377 - set_ne(sql, dupes array) fail should fail ok 378 - set_ne(sql, dupes array) fail should have the proper description ok 379 - set_ne(sql, dupes array) fail should have the proper diagnostics ok 380 - set_ne(sql, array) incompatible types should fail ok 381 - set_ne(sql, array) incompatible types should have the proper description ok 382 - set_ne(sql, array) incompatible types should have the proper diagnostics ok 383 - set_ne(sql, array) incompatible types should fail ok 384 - set_ne(sql, array) incompatible types should have the proper description ok 385 - set_ne(sql, array) incompatible types should have the proper diagnostics ok 386 - bag_ne(sql, array, desc) should pass ok 387 - bag_ne(sql, array, desc) should have the proper description ok 388 - bag_ne(sql, array, desc) should have the proper diagnostics ok 389 - bag_ne(sql, array) should pass ok 390 - bag_ne(sql, array) should have the proper description ok 391 - bag_ne(sql, array) should have the proper diagnostics ok 392 - bag_ne(sql, array) fail should fail ok 393 - bag_ne(sql, array) fail should have the proper description ok 394 - bag_ne(sql, array) fail should have the proper diagnostics ok 395 - bag_ne(sql, dupes array) should pass ok 396 - bag_ne(sql, dupes array) should have the proper description ok 397 - bag_ne(sql, dupes array) should have the proper diagnostics ok 398 - bag_ne(sql, array) incompatible types should fail ok 399 - bag_ne(sql, array) incompatible types should have the proper description ok 400 - bag_ne(sql, array) incompatible types should have the proper diagnostics ok 401 - bag_ne(sql, array) incompatible types should fail ok 402 - bag_ne(sql, array) incompatible types should have the proper description ok 403 - bag_ne(sql, array) incompatible types should have the proper diagnostics ok 404 - results_eq(prepared, array, desc) should pass ok 405 - results_eq(prepared, array, desc) should have the proper description ok 406 - results_eq(prepared, array, desc) should have the proper diagnostics ok 407 - results_eq(prepared, array) should pass ok 408 - results_eq(prepared, array) should have the proper description ok 409 - results_eq(prepared, array) should have the proper diagnostics ok 410 - results_eq(sql, array, desc) should pass ok 411 - results_eq(sql, array, desc) should have the proper description ok 412 - results_eq(sql, array, desc) should have the proper diagnostics ok 413 - results_eq(sql, array, desc) should pass ok 414 - results_eq(sql, array, desc) should have the proper description ok 415 - results_eq(sql, array, desc) should have the proper diagnostics ok 416 - results_eq(prepared, array) extra record should fail ok 417 - results_eq(prepared, array) extra record should have the proper description ok 418 - results_eq(prepared, array) extra record should have the proper diagnostics ok 419 - results_eq(select, array) missing record should fail ok 420 - results_eq(select, array) missing record should have the proper description ok 421 - results_eq(select, array) missing record should have the proper diagnostics ok 422 - results_ne(prepared, prepared, desc) should pass ok 423 - results_ne(prepared, prepared, desc) should have the proper description ok 424 - results_ne(prepared, prepared, desc) should have the proper diagnostics ok 425 - results_ne(prepared, prepared) should pass ok 426 - results_ne(prepared, prepared) should have the proper description ok 427 - results_ne(prepared, prepared) should have the proper diagnostics ok 428 - results_ne(execute, execute) should pass ok 429 - results_ne(execute, execute) should have the proper description ok 430 - results_ne(execute, execute) should have the proper diagnostics ok 431 - results_ne(select, select) should pass ok 432 - results_ne(select, select) should have the proper description ok 433 - results_ne(select, select) should have the proper diagnostics ok 434 - results_ne(dupe values, dupe values) should pass ok 435 - results_ne(dupe values, dupe values) should have the proper description ok 436 - results_ne(dupe values, dupe values) should have the proper diagnostics ok 437 - results_ne(values with null, values with null) should pass ok 438 - results_ne(values with null, values with null) should have the proper description ok 439 - results_ne(values with null, values with null) should have the proper diagnostics ok 440 - results_ne(nulls, nulls) should pass ok 441 - results_ne(nulls, nulls) should have the proper description ok 442 - results_ne(nulls, nulls) should have the proper diagnostics ok 443 - results_ne(prepared, select) fail should fail ok 444 - results_ne(prepared, select) fail should have the proper description ok 445 - results_ne(prepared, select) fail should have the proper diagnostics ok 446 - results_ne(select, prepared) missing last row should pass ok 447 - results_ne(select, prepared) missing last row should have the proper description ok 448 - results_ne(select, prepared) missing last row should have the proper diagnostics ok 449 - results_ne(prepared, select) missing first row should pass ok 450 - results_ne(prepared, select) missing first row should have the proper description ok 451 - results_ne(prepared, select) missing first row should have the proper diagnostics ok 452 - results_ne(values dupe, values) should pass ok 453 - results_ne(values dupe, values) should have the proper description ok 454 - results_ne(values dupe, values) should have the proper diagnostics ok 455 - results_ne(values null, values) should pass ok 456 - results_ne(values null, values) should have the proper description ok 457 - results_ne(values null, values) should have the proper diagnostics ok 458 - results_ne(values, values) mismatch should fail ok 459 - results_ne(values, values) mismatch should have the proper description ok 460 - results_ne(values, values) mismatch should have the proper diagnostics ok 461 - results_ne(values, values) subtle mismatch should fail ok 462 - results_ne(values, values) subtle mismatch should have the proper description ok 463 - results_ne(values, values) subtle mismatch should have the proper diagnostics ok 464 - results_ne(values, values) fail column count should fail ok 465 - results_ne(values, values) fail column count should have the proper description ok 466 - results_ne(values, values) fail column count should have the proper diagnostics ok 467 - results_ne(cursor, cursor) should fail ok 468 - results_ne(cursor, cursor) should have the proper description ok 469 - results_ne(cursor, cursor) should have the proper diagnostics ok 470 - results_ne(cursor, prepared) should fail ok 471 - results_ne(cursor, prepared) should have the proper description ok 472 - results_ne(cursor, prepared) should have the proper diagnostics ok 473 - results_ne(prepared, cursor) should fail ok 474 - results_ne(prepared, cursor) should have the proper description ok 475 - results_ne(prepared, cursor) should have the proper diagnostics ok 476 - results_ne(cursor, sql) should pass ok 477 - results_ne(cursor, sql) should have the proper description ok 478 - results_ne(cursor, sql) should have the proper diagnostics ok 479 - results_ne(sql, cursor) should fail ok 480 - results_ne(sql, cursor) should have the proper description ok 481 - results_ne(sql, cursor) should have the proper diagnostics ok 482 - is_empty(sql, desc) should pass ok 483 - is_empty(sql, desc) should have the proper description ok 484 - is_empty(sql, desc) should have the proper diagnostics ok 485 - is_empty(sql) should pass ok 486 - is_empty(sql) should have the proper description ok 487 - is_empty(sql) should have the proper diagnostics ok 488 - is_empty(prepared, desc) should pass ok 489 - is_empty(prepared, desc) should have the proper description ok 490 - is_empty(prepared, desc) should have the proper diagnostics ok 491 - is_empty(prepared) should pass ok 492 - is_empty(prepared) should have the proper description ok 493 - is_empty(prepared) should have the proper diagnostics ok 494 - is_empty(prepared, desc) fail should fail ok 495 - is_empty(prepared, desc) fail should have the proper description ok 496 - is_empty(prepared, desc) fail should have the proper diagnostics ok 497 - is_empty(prepared) fail should fail ok 498 - is_empty(prepared) fail should have the proper description ok 499 - is_empty(prepared) fail should have the proper diagnostics ok 500 - isnt_empty(sql, desc) should pass ok 501 - isnt_empty(sql, desc) should have the proper description ok 502 - isnt_empty(sql, desc) should have the proper diagnostics ok 503 - isnt_empty(sql, desc) should fail ok 504 - isnt_empty(sql, desc) should have the proper description ok 505 - isnt_empty(sql, desc) should have the proper diagnostics ok 506 - isnt_empty(sql) should fail ok 507 - isnt_empty(sql) should have the proper description ok 508 - isnt_empty(sql) should have the proper diagnostics ok 509 - isnt_empty(sql) should pass ok 510 - isnt_empty(sql) should have the proper description ok 511 - isnt_empty(sql) should have the proper diagnostics ok 512 - isnt_empty(prepared, desc) should pass ok 513 - isnt_empty(prepared, desc) should have the proper description ok 514 - isnt_empty(prepared, desc) should have the proper diagnostics ok 515 - isnt_empty(prepared, desc) should fail ok 516 - isnt_empty(prepared, desc) should have the proper description ok 517 - isnt_empty(prepared, desc) should have the proper diagnostics ok 518 - isnt_empty(prepared) should pass ok 519 - isnt_empty(prepared) should have the proper description ok 520 - isnt_empty(prepared) should have the proper diagnostics ok 521 - isnt_empty(prepared) should fail ok 522 - isnt_empty(prepared) should have the proper description ok 523 - isnt_empty(prepared) should have the proper diagnostics ok 524 - row_eq(prepared, record, desc) should pass ok 525 - row_eq(prepared, record, desc) should have the proper description ok 526 - row_eq(prepared, record, desc) should have the proper diagnostics ok 527 - row_eq(sql, record, desc) should pass ok 528 - row_eq(sql, record, desc) should have the proper description ok 529 - row_eq(sql, record, desc) should have the proper diagnostics ok 530 - row_eq(prepared, record, desc) should pass ok 531 - row_eq(prepared, record, desc) should have the proper description ok 532 - row_eq(prepared, record, desc) should have the proper diagnostics ok 533 - row_eq(prepared, record, desc) should fail ok 534 - row_eq(prepared, record, desc) should have the proper description ok 535 - row_eq(prepared, record, desc) should have the proper diagnostics ok 536 - row_eq(prepared, sometype, desc) should pass ok 537 - row_eq(prepared, sometype, desc) should have the proper description ok 538 - row_eq(prepared, sometype, desc) should have the proper diagnostics ok 539 - row_eq(sqlrow, sometype, desc) should pass ok 540 - row_eq(sqlrow, sometype, desc) should have the proper description ok 541 - row_eq(sqlrow, sometype, desc) should have the proper diagnostics ok 542 - threw 0A000 ok 543 - row_eq(qry, record) should pass ok 544 - row_eq(qry, record) should have the proper description ok 545 - row_eq(qry, record) should have the proper diagnostics pgtap-1.3.2/test/expected/roletap.out000066400000000000000000000047201455775703000176270ustar00rootroot00000000000000\unset ECHO 1..39 ok 1 - has_role(current role) should pass ok 2 - has_role(current role) should have the proper description ok 3 - has_role(current role) should have the proper diagnostics ok 4 - has_role(current role, desc) should pass ok 5 - has_role(current role, desc) should have the proper description ok 6 - has_role(current role, desc) should have the proper diagnostics ok 7 - has_role(nonexistent role) should fail ok 8 - has_role(nonexistent role) should have the proper description ok 9 - has_role(nonexistent role) should have the proper diagnostics ok 10 - has_role(nonexistent role, desc) should fail ok 11 - has_role(nonexistent role, desc) should have the proper description ok 12 - has_role(nonexistent role, desc) should have the proper diagnostics ok 13 - hasnt_role(current role) should fail ok 14 - hasnt_role(current role) should have the proper description ok 15 - hasnt_role(current role) should have the proper diagnostics ok 16 - hasnt_role(current role, desc) should fail ok 17 - hasnt_role(current role, desc) should have the proper description ok 18 - hasnt_role(current role, desc) should have the proper diagnostics ok 19 - hasnt_role(nonexistent role) should pass ok 20 - hasnt_role(nonexistent role) should have the proper description ok 21 - hasnt_role(nonexistent role) should have the proper diagnostics ok 22 - hasnt_role(nonexistent role, desc) should pass ok 23 - hasnt_role(nonexistent role, desc) should have the proper description ok 24 - hasnt_role(nonexistent role, desc) should have the proper diagnostics ok 25 - roles_are(roles, desc) should pass ok 26 - roles_are(roles, desc) should have the proper description ok 27 - roles_are(roles, desc) should have the proper diagnostics ok 28 - roles_are(roles) should pass ok 29 - roles_are(roles) should have the proper description ok 30 - roles_are(roles) should have the proper diagnostics ok 31 - roles_are(roles, desc) missing should fail ok 32 - roles_are(roles, desc) missing should have the proper description ok 33 - roles_are(roles, desc) missing should have the proper diagnostics ok 34 - roles_are(roles, desc) extras should fail ok 35 - roles_are(roles, desc) extras should have the proper description ok 36 - roles_are(roles, desc) extras should have the proper diagnostics ok 37 - roles_are(roles, desc) missing and extras should fail ok 38 - roles_are(roles, desc) missing and extras should have the proper description ok 39 - roles_are(roles, desc) missing and extras should have the proper diagnostics pgtap-1.3.2/test/expected/ruletap.out000066400000000000000000000233151455775703000176360ustar00rootroot00000000000000\unset ECHO 1..132 ok 1 - has_rule(schema, table, rule, desc) should pass ok 2 - has_rule(schema, table, rule, desc) should have the proper description ok 3 - has_rule(schema, table, rule, desc) should have the proper diagnostics ok 4 - has_rule(schema, table, rule) should pass ok 5 - has_rule(schema, table, rule) should have the proper description ok 6 - has_rule(schema, table, rule) should have the proper diagnostics ok 7 - has_rule(schema, table, rule, desc) fail should fail ok 8 - has_rule(schema, table, rule, desc) fail should have the proper description ok 9 - has_rule(schema, table, rule, desc) fail should have the proper diagnostics ok 10 - has_rule(table, rule, desc) should pass ok 11 - has_rule(table, rule, desc) should have the proper description ok 12 - has_rule(table, rule, desc) should have the proper diagnostics ok 13 - has_rule(table, rule) should pass ok 14 - has_rule(table, rule) should have the proper description ok 15 - has_rule(table, rule) should have the proper diagnostics ok 16 - has_rule(table, rule, desc) fail should fail ok 17 - has_rule(table, rule, desc) fail should have the proper description ok 18 - has_rule(table, rule, desc) fail should have the proper diagnostics ok 19 - hasnt_rule(schema, table, rule, desc) should fail ok 20 - hasnt_rule(schema, table, rule, desc) should have the proper description ok 21 - hasnt_rule(schema, table, rule, desc) should have the proper diagnostics ok 22 - hasnt_rule(schema, table, rule) should fail ok 23 - hasnt_rule(schema, table, rule) should have the proper description ok 24 - hasnt_rule(schema, table, rule) should have the proper diagnostics ok 25 - hasnt_rule(schema, table, rule, desc) fail should pass ok 26 - hasnt_rule(schema, table, rule, desc) fail should have the proper description ok 27 - hasnt_rule(schema, table, rule, desc) fail should have the proper diagnostics ok 28 - hasnt_rule(table, rule, desc) should fail ok 29 - hasnt_rule(table, rule, desc) should have the proper description ok 30 - hasnt_rule(table, rule, desc) should have the proper diagnostics ok 31 - hasnt_rule(table, rule) should fail ok 32 - hasnt_rule(table, rule) should have the proper description ok 33 - hasnt_rule(table, rule) should have the proper diagnostics ok 34 - hasnt_rule(table, rule, desc) fail should pass ok 35 - hasnt_rule(table, rule, desc) fail should have the proper description ok 36 - hasnt_rule(table, rule, desc) fail should have the proper diagnostics ok 37 - rule_is_instead(schema, table, rule, desc) should pass ok 38 - rule_is_instead(schema, table, rule, desc) should have the proper description ok 39 - rule_is_instead(schema, table, rule, desc) should have the proper diagnostics ok 40 - rule_is_instead(schema, table, rule) should pass ok 41 - rule_is_instead(schema, table, rule) should have the proper description ok 42 - rule_is_instead(schema, table, rule) should have the proper diagnostics ok 43 - rule_is_instead(schema, table, nothing rule, desc) should fail ok 44 - rule_is_instead(schema, table, nothing rule, desc) should have the proper description ok 45 - rule_is_instead(schema, table, nothing rule, desc) should have the proper diagnostics ok 46 - rule_is_instead(schema, table, also rule, desc) should fail ok 47 - rule_is_instead(schema, table, also rule, desc) should have the proper description ok 48 - rule_is_instead(schema, table, also rule, desc) should have the proper diagnostics ok 49 - rule_is_instead(table, rule, desc) should pass ok 50 - rule_is_instead(table, rule, desc) should have the proper description ok 51 - rule_is_instead(table, rule, desc) should have the proper diagnostics ok 52 - rule_is_instead(table, rule) should pass ok 53 - rule_is_instead(table, rule) should have the proper description ok 54 - rule_is_instead(table, rule) should have the proper diagnostics ok 55 - rule_is_instead(table, nothing rule, desc) should fail ok 56 - rule_is_instead(table, nothing rule, desc) should have the proper description ok 57 - rule_is_instead(table, nothing rule, desc) should have the proper diagnostics ok 58 - rule_is_instead(table, also rule, desc) should fail ok 59 - rule_is_instead(table, also rule, desc) should have the proper description ok 60 - rule_is_instead(table, also rule, desc) should have the proper diagnostics ok 61 - rule_is_instead(schema, table, non-existent rule, desc) should fail ok 62 - rule_is_instead(schema, table, non-existent rule, desc) should have the proper description ok 63 - rule_is_instead(schema, table, non-existent rule, desc) should have the proper diagnostics ok 64 - rule_is_instead(table, non-existent rule, desc) should fail ok 65 - rule_is_instead(table, non-existent rule, desc) should have the proper description ok 66 - rule_is_instead(table, non-existent rule, desc) should have the proper diagnostics ok 67 - rule_is_on(schema, table, rule, insert, desc) should pass ok 68 - rule_is_on(schema, table, rule, insert, desc) should have the proper description ok 69 - rule_is_on(schema, table, rule, insert, desc) should have the proper diagnostics ok 70 - rule_is_on(schema, table, rule, update, desc) should pass ok 71 - rule_is_on(schema, table, rule, update, desc) should have the proper description ok 72 - rule_is_on(schema, table, rule, update, desc) should have the proper diagnostics ok 73 - rule_is_on(schema, table, rule, insert, desc) should pass ok 74 - rule_is_on(schema, table, rule, insert, desc) should have the proper description ok 75 - rule_is_on(schema, table, rule, insert, desc) should have the proper diagnostics ok 76 - rule_is_on(schema, table, rule, delete, desc) should pass ok 77 - rule_is_on(schema, table, rule, delete, desc) should have the proper description ok 78 - rule_is_on(schema, table, rule, delete, desc) should have the proper diagnostics ok 79 - rule_is_on(schema, table, dupe rule, insert, desc) should pass ok 80 - rule_is_on(schema, table, dupe rule, insert, desc) should have the proper description ok 81 - rule_is_on(schema, table, dupe rule, insert, desc) should have the proper diagnostics ok 82 - rule_is_on(schema, table, rule, INSERT, desc) should pass ok 83 - rule_is_on(schema, table, rule, INSERT, desc) should have the proper description ok 84 - rule_is_on(schema, table, rule, INSERT, desc) should have the proper diagnostics ok 85 - rule_is_on(schema, table, rule, i, desc) should pass ok 86 - rule_is_on(schema, table, rule, i, desc) should have the proper description ok 87 - rule_is_on(schema, table, rule, i, desc) should have the proper diagnostics ok 88 - rule_is_on(schema, table, rule, indigo, desc) should pass ok 89 - rule_is_on(schema, table, rule, indigo, desc) should have the proper description ok 90 - rule_is_on(schema, table, rule, indigo, desc) should have the proper diagnostics ok 91 - rule_is_on(schema, table, rule, i, desc) should pass ok 92 - rule_is_on(schema, table, rule, i, desc) should have the proper description ok 93 - rule_is_on(schema, table, rule, i, desc) should have the proper diagnostics ok 94 - rule_is_on(schema, table, rule, u, desc) fail should fail ok 95 - rule_is_on(schema, table, rule, u, desc) fail should have the proper description ok 96 - rule_is_on(schema, table, rule, u, desc) fail should have the proper diagnostics ok 97 - rule_is_on(schema, table, invalid rule, u, desc) should fail ok 98 - rule_is_on(schema, table, invalid rule, u, desc) should have the proper description ok 99 - rule_is_on(schema, table, invalid rule, u, desc) should have the proper diagnostics ok 100 - rule_is_on(table, rule, insert, desc) should pass ok 101 - rule_is_on(table, rule, insert, desc) should have the proper description ok 102 - rule_is_on(table, rule, insert, desc) should have the proper diagnostics ok 103 - rule_is_on(table, rule, update, desc) should pass ok 104 - rule_is_on(table, rule, update, desc) should have the proper description ok 105 - rule_is_on(table, rule, update, desc) should have the proper diagnostics ok 106 - rule_is_on(table, rule, insert, desc) should pass ok 107 - rule_is_on(table, rule, insert, desc) should have the proper description ok 108 - rule_is_on(table, rule, insert, desc) should have the proper diagnostics ok 109 - rule_is_on(table, rule, delete, desc) should pass ok 110 - rule_is_on(table, rule, delete, desc) should have the proper description ok 111 - rule_is_on(table, rule, delete, desc) should have the proper diagnostics ok 112 - rule_is_on(table, dupe rule, insert, desc) should pass ok 113 - rule_is_on(table, dupe rule, insert, desc) should have the proper description ok 114 - rule_is_on(table, dupe rule, insert, desc) should have the proper diagnostics ok 115 - rule_is_on(table, rule, INSERT, desc) should pass ok 116 - rule_is_on(table, rule, INSERT, desc) should have the proper description ok 117 - rule_is_on(table, rule, INSERT, desc) should have the proper diagnostics ok 118 - rule_is_on(table, rule, i, desc) should pass ok 119 - rule_is_on(table, rule, i, desc) should have the proper description ok 120 - rule_is_on(table, rule, i, desc) should have the proper diagnostics ok 121 - rule_is_on(table, rule, indigo, desc) should pass ok 122 - rule_is_on(table, rule, indigo, desc) should have the proper description ok 123 - rule_is_on(table, rule, indigo, desc) should have the proper diagnostics ok 124 - rule_is_on(table, rule, i, desc) should pass ok 125 - rule_is_on(table, rule, i, desc) should have the proper description ok 126 - rule_is_on(table, rule, i, desc) should have the proper diagnostics ok 127 - rule_is_on(table, rule, u, desc) fail should fail ok 128 - rule_is_on(table, rule, u, desc) fail should have the proper description ok 129 - rule_is_on(table, rule, u, desc) fail should have the proper diagnostics ok 130 - rule_is_on(table, invalid rule, u, desc) should fail ok 131 - rule_is_on(table, invalid rule, u, desc) should have the proper description ok 132 - rule_is_on(table, invalid rule, u, desc) should have the proper diagnostics pgtap-1.3.2/test/expected/runjusttests.out000066400000000000000000000035421455775703000207570ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # PL/pgSQL function __die() line 3 at RAISE # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 43 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_1.out000066400000000000000000000034601455775703000211760ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 43 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_2.out000066400000000000000000000032121455775703000211720ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 43 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_3.out000066400000000000000000000032121455775703000211730ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 34 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_4.out000066400000000000000000000023431455775703000212000ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_5.out000066400000000000000000000034461455775703000212060ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 43 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runjusttests_6.out000066400000000000000000000023301455775703000211760ustar00rootroot00000000000000\unset ECHO # Subtest: whatever."test ident"() ok 1 - ident ok 2 - ident 2 1..2 ok 1 - whatever."test ident" # Subtest: whatever.testnada() 1..0 # No tests run! not ok 2 - whatever.testnada # Failed test 2: "whatever.testnada" # Subtest: whatever.testplpgsql() ok 1 - plpgsql simple ok 2 - plpgsql simple 2 ok 3 - Should be a 1 in the test table 1..3 ok 3 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() # Test died: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. not ok 4 - whatever.testplpgsqldie # Failed test 4: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - simple pass ok 2 - another simple pass 1..2 ok 5 - whatever.testthis # Subtest: whatever.testy() ok 1 - pass not ok 2 - this test intentionally fails # Failed test 2: "this test intentionally fails" 1..2 # Looks like you failed 1 test of 2 not ok 6 - whatever.testy # Failed test 6: "whatever.testy" # Subtest: whatever.testz() ok 1 - Late test should find nothing in the test table 1..1 ok 7 - whatever.testz 1..7 # Looks like you failed 3 tests of 7 pgtap-1.3.2/test/expected/runnotests.out000066400000000000000000000002631455775703000204030ustar00rootroot00000000000000\unset ECHO # Subtest: whatever.testthis() 1..0 # No tests run! not ok 1 - whatever.testthis # Failed test 1: "whatever.testthis" 1..1 # Looks like you failed 1 test of 1 pgtap-1.3.2/test/expected/runtests.out000066400000000000000000000140441455775703000200500ustar00rootroot00000000000000\unset ECHO ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # PL/pgSQL function __die() line 3 at RAISE # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # PL/pgSQL function __die() line 3 at RAISE # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 pgtap-1.3.2/test/expected/runtests_1.out000066400000000000000000000136541455775703000202760ustar00rootroot00000000000000\unset ECHO ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 pgtap-1.3.2/test/expected/runtests_2.out000066400000000000000000000137001455775703000202670ustar00rootroot00000000000000\unset ECHO ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # SCHEMA: SCHEMA # TABLE: TABLE # COLUMN: COLUMN # CONSTRAINT: CONSTRAINT # TYPE: TYPE # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 23 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 pgtap-1.3.2/test/expected/runtests_3.out000066400000000000000000000131641455775703000202740ustar00rootroot00000000000000\unset ECHO ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 34 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero # CONTEXT: # SQL function "testdividebyzero" during startup # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. # DETAIL: DETAIL # CONTEXT: # SQL statement "SELECT __die();" # PL/pgSQL function whatever.testplpgsqldie() line 34 at EXECUTE statement # PL/pgSQL function _runner(text[],text[],text[],text[],text[]) line 62 at FOR over EXECUTE statement # SQL function "runtests" statement 1 not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 pgtap-1.3.2/test/expected/runtests_4.out000066400000000000000000000104361455775703000202740ustar00rootroot00000000000000\unset ECHO ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 ok 1 - starting up ok 2 - starting up some more # Subtest: whatever."test ident"() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - ident ok 5 - ident 2 ok 6 - teardown ok 7 - teardown more 1..7 ok 3 - whatever."test ident" # Subtest: whatever.testdividebyzero() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: 22012: division by zero not ok 4 - whatever.testdividebyzero # Failed test 4: "whatever.testdividebyzero" # Subtest: whatever.testplpgsql() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - plpgsql simple ok 5 - plpgsql simple 2 ok 6 - Should be a 1 in the test table ok 7 - teardown ok 8 - teardown more 1..8 ok 5 - whatever.testplpgsql # Subtest: whatever.testplpgsqldie() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more # Test died: P0001: This test should die, but not halt execution. # Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself. not ok 6 - whatever.testplpgsqldie # Failed test 6: "whatever.testplpgsqldie" # Subtest: whatever.testthis() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - simple pass ok 5 - another simple pass ok 6 - teardown ok 7 - teardown more 1..7 ok 7 - whatever.testthis # Subtest: whatever.testy() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more not ok 4 - this test intentionally fails # Failed test 4: "this test intentionally fails" ok 5 - teardown ok 6 - teardown more 1..6 # Looks like you failed 1 test of 6 not ok 8 - whatever.testy # Failed test 8: "whatever.testy" # Subtest: whatever.testz() ok 1 - setup ok 2 - Should be nothing in the test table ok 3 - setup more ok 4 - Late test should find nothing in the test table ok 5 - teardown ok 6 - teardown more 1..6 ok 9 - whatever.testz ok 10 - shutting down ok 11 - shutting down more 1..11 # Looks like you failed 3 tests of 11 pgtap-1.3.2/test/expected/throwtap.out000066400000000000000000000141011455775703000200230ustar00rootroot00000000000000\unset ECHO 1..97 ok 1 - four-argument form should pass ok 2 - four-argument form should have the proper description ok 3 - four-argument form should have the proper diagnostics ok 4 - three-argument errcode should pass ok 5 - three-argument errcode should have the proper description ok 6 - three-argument errcode should have the proper diagnostics ok 7 - two-argument errcode should pass ok 8 - two-argument errcode should have the proper description ok 9 - three argument errmsg should pass ok 10 - three argument errmsg should have the proper description ok 11 - three argument errmsg should have the proper diagnostics ok 12 - two-argument errmsg should pass ok 13 - two-argument errmsg should have the proper description ok 14 - two-argument errmsg should have the proper diagnostics ok 15 - single-argument form should pass ok 16 - single-argument form should have the proper description ok 17 - single-argument form should have the proper diagnostics ok 18 - prepared statement & errcode should pass ok 19 - prepared statement & errcode should have the proper description ok 20 - execute & errcode should pass ok 21 - execute & errcode should have the proper description ok 22 - invalid errcode should fail ok 23 - invalid errcode should have the proper description ok 24 - invalid errcode should have the proper diagnostics ok 25 - throws_ok(1/0, NULL) should work ok 26 - throws_ok diagnostics should fail ok 27 - throws_ok diagnostics should have the proper description ok 28 - throws_ok diagnostics should have the proper diagnostics ok 29 - lives_ok() should work ok 30 - lives_ok(prepared) should pass ok 31 - lives_ok(prepared) should have the proper description ok 32 - lives_ok(execute) should pass ok 33 - lives_ok(execute) should have the proper description ok 34 - lives_ok failure diagnostics should fail ok 35 - lives_ok failure diagnostics should have the proper description ok 36 - lives_ok failure diagnostics should have the proper diagnostics ok 37 - throws_like(sql, pattern, desc) should pass ok 38 - throws_like(sql, pattern, desc) should have the proper description ok 39 - throws_like(sql, pattern, desc) should have the proper diagnostics ok 40 - throws_like(sql, pattern) should pass ok 41 - throws_like(sql, pattern) should have the proper description ok 42 - throws_like(sql, pattern) should have the proper diagnostics ok 43 - throws_like(sql, pattern, desc) fail should fail ok 44 - throws_like(sql, pattern, desc) fail should have the proper description ok 45 - throws_like(sql, pattern, desc) fail should have the proper diagnostics ok 46 - throws_like(valid sql, pattern, desc) should fail ok 47 - throws_like(valid sql, pattern, desc) should have the proper description ok 48 - throws_like(valid sql, pattern, desc) should have the proper diagnostics ok 49 - throws_ilike(sql, pattern, desc) should pass ok 50 - throws_ilike(sql, pattern, desc) should have the proper description ok 51 - throws_ilike(sql, pattern, desc) should have the proper diagnostics ok 52 - throws_ilike(sql, pattern) should pass ok 53 - throws_ilike(sql, pattern) should have the proper description ok 54 - throws_ilike(sql, pattern) should have the proper diagnostics ok 55 - throws_ilike(sql, pattern, desc) fail should fail ok 56 - throws_ilike(sql, pattern, desc) fail should have the proper description ok 57 - throws_ilike(sql, pattern, desc) fail should have the proper diagnostics ok 58 - throws_ilike(valid sql, pattern, desc) should fail ok 59 - throws_ilike(valid sql, pattern, desc) should have the proper description ok 60 - throws_ilike(valid sql, pattern, desc) should have the proper diagnostics ok 61 - throws_matching(sql, regex, desc) should pass ok 62 - throws_matching(sql, regex, desc) should have the proper description ok 63 - throws_matching(sql, regex, desc) should have the proper diagnostics ok 64 - throws_matching(sql, regex, desc) should pass ok 65 - throws_matching(sql, regex, desc) should have the proper description ok 66 - throws_matching(sql, regex, desc) should have the proper diagnostics ok 67 - throws_matching(sql, regex, desc) should fail ok 68 - throws_matching(sql, regex, desc) should have the proper description ok 69 - throws_matching(sql, regex, desc) should have the proper diagnostics ok 70 - throws_matching(valid sql, regex, desc) should fail ok 71 - throws_matching(valid sql, regex, desc) should have the proper description ok 72 - throws_matching(valid sql, regex, desc) should have the proper diagnostics ok 73 - throws_imatching(sql, regex, desc) should pass ok 74 - throws_imatching(sql, regex, desc) should have the proper description ok 75 - throws_imatching(sql, regex, desc) should have the proper diagnostics ok 76 - throws_imatching(sql, regex, desc) should pass ok 77 - throws_imatching(sql, regex, desc) should have the proper description ok 78 - throws_imatching(sql, regex, desc) should have the proper diagnostics ok 79 - throws_imatching(sql, regex, desc) should fail ok 80 - throws_imatching(sql, regex, desc) should have the proper description ok 81 - throws_imatching(sql, regex, desc) should have the proper diagnostics ok 82 - throws_imatching(valid sql, regex, desc) should fail ok 83 - throws_imatching(valid sql, regex, desc) should have the proper description ok 84 - throws_imatching(valid sql, regex, desc) should have the proper diagnostics ok 85 - Create check_assert function ok 86 - throws_ok catches assert should pass ok 87 - throws_ok catches assert should have the proper description ok 88 - throws_ok catches assert should have the proper diagnostics ok 89 - throws_ok does not accept passing assert should fail ok 90 - throws_ok does not accept passing assert should have the proper description ok 91 - throws_ok does not accept passing assert should have the proper diagnostics ok 92 - lives_ok calling check_assert(true) should pass ok 93 - lives_ok calling check_assert(true) should have the proper description ok 94 - lives_ok calling check_assert(true) should have the proper diagnostics ok 95 - lives_ok with check_assert(false) should fail ok 96 - lives_ok with check_assert(false) should have the proper description ok 97 - lives_ok with check_assert(false) should have the proper diagnostics pgtap-1.3.2/test/expected/todotap.out000066400000000000000000000024641455775703000176360ustar00rootroot00000000000000\unset ECHO 1..36 ok 1 - todo fail ok 2 - todo pass ok 3 - TODO tests should display properly ok 4 - todo fail ok 5 - Single default todo test should display properly ok 6 - todo fail ok 7 - todo pass ok 8 - TODO tests should display properly ok 9 - simple skip should pass ok 10 - simple skip should have the proper description ok 11 - simple skip should have the proper diagnostics ok 12 - skip with num should pass ok 13 - skip with num should have the proper description ok 14 - skip with num should have the proper diagnostics ok 15 - Skip multiple ok 16 - Skip multiple ok 17 - Skip multiple ok 18 - We should get the proper output for multiple skips ok 19 - inverted skip should pass ok 20 - inverted skip should have the proper description ok 21 - inverted skip should have the proper diagnostics ok 22 - num only should pass ok 23 - num only should have the proper description ok 24 - num only should have the proper diagnostics ok 25 - todo fail ok 26 - todo fail ok 27 - todo fail ok 28 - Nested todos should work properly ok 29 - todo fail ok 30 - todo fail ok 31 - todo fail ok 32 - todo_start() and todo_end() should work properly with in_todo() ok 33 - todo fail ok 34 - todo pass ok 35 - Should be able to revers the arguments to todo() ok 36 - Should get an exception when todo_end() is called without todo_start() pgtap-1.3.2/test/expected/trigger.out000066400000000000000000000137051455775703000176270ustar00rootroot00000000000000\unset ECHO 1..84 ok 1 - has_trigger(schema, table, trigger, desc) should pass ok 2 - has_trigger(schema, table, trigger, desc) should have the proper description ok 3 - has_trigger(schema, table, trigger, desc) should have the proper diagnostics ok 4 - has_trigger(schema, table, trigger) should pass ok 5 - has_trigger(schema, table, trigger) should have the proper description ok 6 - has_trigger(schema, table, trigger) should have the proper diagnostics ok 7 - has_trigger(table, trigger, desc) should pass ok 8 - has_trigger(table, trigger, desc) should have the proper description ok 9 - has_trigger(table, trigger, desc) should have the proper diagnostics ok 10 - has_trigger(table, trigger) should pass ok 11 - has_trigger(table, trigger) should have the proper description ok 12 - has_trigger(table, trigger) should have the proper diagnostics ok 13 - has_trigger(schema, table, nonexistent, desc) should fail ok 14 - has_trigger(schema, table, nonexistent, desc) should have the proper description ok 15 - has_trigger(schema, table, nonexistent, desc) should have the proper diagnostics ok 16 - has_trigger(table, nonexistent) no schema fail should fail ok 17 - has_trigger(table, nonexistent) no schema fail should have the proper description ok 18 - has_trigger(table, nonexistent) no schema fail should have the proper diagnostics ok 19 - hasnt_trigger(schema, table, trigger, desc) should fail ok 20 - hasnt_trigger(schema, table, trigger, desc) should have the proper description ok 21 - hasnt_trigger(schema, table, trigger, desc) should have the proper diagnostics ok 22 - hasnt_trigger(schema, table, trigger) should fail ok 23 - hasnt_trigger(schema, table, trigger) should have the proper description ok 24 - hasnt_trigger(schema, table, trigger) should have the proper diagnostics ok 25 - hasnt_trigger(table, trigger, desc) should fail ok 26 - hasnt_trigger(table, trigger, desc) should have the proper description ok 27 - hasnt_trigger(table, trigger, desc) should have the proper diagnostics ok 28 - hasnt_trigger(table, trigger) should fail ok 29 - hasnt_trigger(table, trigger) should have the proper description ok 30 - hasnt_trigger(table, trigger) should have the proper diagnostics ok 31 - hasnt_trigger(schema, table, nonexistent, desc) should pass ok 32 - hasnt_trigger(schema, table, nonexistent, desc) should have the proper description ok 33 - hasnt_trigger(schema, table, nonexistent, desc) should have the proper diagnostics ok 34 - hasnt_trigger(table, nonexistent) no schema fail should pass ok 35 - hasnt_trigger(table, nonexistent) no schema fail should have the proper description ok 36 - hasnt_trigger(table, nonexistent) no schema fail should have the proper diagnostics ok 37 - trigger_is() should pass ok 38 - trigger_is() should have the proper description ok 39 - trigger_is() should have the proper diagnostics ok 40 - trigger_is() no desc should pass ok 41 - trigger_is() no desc should have the proper description ok 42 - trigger_is() no desc should have the proper diagnostics ok 43 - trigger_is() no schema should pass ok 44 - trigger_is() no schema should have the proper description ok 45 - trigger_is() no schema should have the proper diagnostics ok 46 - trigger_is() no schema or desc should pass ok 47 - trigger_is() no schema or desc should have the proper description ok 48 - trigger_is() no schema or desc should have the proper diagnostics ok 49 - trigger_is() fail should fail ok 50 - trigger_is() fail should have the proper description ok 51 - trigger_is() fail should have the proper diagnostics ok 52 - trigger_is() no schema fail should fail ok 53 - trigger_is() no schema fail should have the proper description ok 54 - trigger_is() no schema fail should have the proper diagnostics ok 55 - triggers_are(schema, table, triggers, desc) should pass ok 56 - triggers_are(schema, table, triggers, desc) should have the proper description ok 57 - triggers_are(schema, table, triggers, desc) should have the proper diagnostics ok 58 - triggers_are(schema, table, triggers) should pass ok 59 - triggers_are(schema, table, triggers) should have the proper description ok 60 - triggers_are(schema, table, triggers) should have the proper diagnostics ok 61 - triggers_are(schema, table, triggers) + extra should fail ok 62 - triggers_are(schema, table, triggers) + extra should have the proper description ok 63 - triggers_are(schema, table, triggers) + extra should have the proper diagnostics ok 64 - triggers_are(schema, table, triggers) + missing should fail ok 65 - triggers_are(schema, table, triggers) + missing should have the proper description ok 66 - triggers_are(schema, table, triggers) + missing should have the proper diagnostics ok 67 - triggers_are(schema, table, triggers) + extra & missing should fail ok 68 - triggers_are(schema, table, triggers) + extra & missing should have the proper description ok 69 - triggers_are(schema, table, triggers) + extra & missing should have the proper diagnostics ok 70 - triggers_are(table, triggers, desc) should pass ok 71 - triggers_are(table, triggers, desc) should have the proper description ok 72 - triggers_are(table, triggers, desc) should have the proper diagnostics ok 73 - triggers_are(table, triggers) should pass ok 74 - triggers_are(table, triggers) should have the proper description ok 75 - triggers_are(table, triggers) should have the proper diagnostics ok 76 - triggers_are(table, triggers) + extra should fail ok 77 - triggers_are(table, triggers) + extra should have the proper description ok 78 - triggers_are(table, triggers) + extra should have the proper diagnostics ok 79 - triggers_are(table, triggers) + missing should fail ok 80 - triggers_are(table, triggers) + missing should have the proper description ok 81 - triggers_are(table, triggers) + missing should have the proper diagnostics ok 82 - triggers_are(table, triggers) + extra & missing should fail ok 83 - triggers_are(table, triggers) + extra & missing should have the proper description ok 84 - triggers_are(table, triggers) + extra & missing should have the proper diagnostics pgtap-1.3.2/test/expected/unique.out000066400000000000000000000101201455775703000174560ustar00rootroot00000000000000\unset ECHO 1..54 ok 1 - has_unique( schema, table, description ) should pass ok 2 - has_unique( schema, table, description ) should have the proper description ok 3 - has_unique( schema, table, description ) should have the proper diagnostics ok 4 - has_unique( table, description ) should pass ok 5 - has_unique( table, description ) should have the proper description ok 6 - has_unique( table, description ) should have the proper diagnostics ok 7 - has_unique( table ) should pass ok 8 - has_unique( table ) should have the proper description ok 9 - has_unique( table ) should have the proper diagnostics ok 10 - has_unique( schema, table, description ) fail should fail ok 11 - has_unique( schema, table, description ) fail should have the proper description ok 12 - has_unique( schema, table, description ) fail should have the proper diagnostics ok 13 - has_unique( table, description ) fail should fail ok 14 - has_unique( table, description ) fail should have the proper description ok 15 - has_unique( table, description ) fail should have the proper diagnostics ok 16 - col_is_unique( schema, table, column, description ) should pass ok 17 - col_is_unique( schema, table, column, description ) should have the proper description ok 18 - col_is_unique( schema, table, column, description ) should have the proper diagnostics ok 19 - col_is_unique( schema, table, columns, description ) should pass ok 20 - col_is_unique( schema, table, columns, description ) should have the proper description ok 21 - col_is_unique( schema, table, columns, description ) should have the proper diagnostics ok 22 - col_is_unique( table, column, description ) should pass ok 23 - col_is_unique( table, column, description ) should have the proper description ok 24 - col_is_unique( table, column, description ) should have the proper diagnostics ok 25 - col_is_unique( table, columns, description ) should pass ok 26 - col_is_unique( table, columns, description ) should have the proper description ok 27 - col_is_unique( table, columns, description ) should have the proper diagnostics ok 28 - col_is_unique( schema, table, column ) should pass ok 29 - col_is_unique( schema, table, column ) should have the proper description ok 30 - col_is_unique( schema, table, column ) should have the proper diagnostics ok 31 - col_is_unique( schema, table, columns ) should pass ok 32 - col_is_unique( schema, table, columns ) should have the proper description ok 33 - col_is_unique( schema, table, columns ) should have the proper diagnostics ok 34 - col_is_unique( table, column ) should pass ok 35 - col_is_unique( table, column ) should have the proper description ok 36 - col_is_unique( table, column ) should have the proper diagnostics ok 37 - col_is_unique( table, columns ) should pass ok 38 - col_is_unique( table, columns ) should have the proper description ok 39 - col_is_unique( table, columns ) should have the proper diagnostics ok 40 - col_is_unique( schema, table, column, description ) fail should fail ok 41 - col_is_unique( schema, table, column, description ) fail should have the proper description ok 42 - col_is_unique( schema, table, column, description ) fail should have the proper diagnostics ok 43 - col_is_unique( table, column, description ) fail should fail ok 44 - col_is_unique( table, column, description ) fail should have the proper description ok 45 - col_is_unique( table, column, description ) fail should have the proper diagnostics ok 46 - col_is_unique( schema, table, column[], description ) should pass ok 47 - col_is_unique( schema, table, column[], description ) should have the proper description ok 48 - col_is_unique( schema, table, column[], description ) should have the proper diagnostics ok 49 - col_is_unique( table, column[], description ) should pass ok 50 - col_is_unique( table, column[], description ) should have the proper description ok 51 - col_is_unique( table, column[], description ) should have the proper diagnostics ok 52 - col_is_unique( table, column[] ) should pass ok 53 - col_is_unique( table, column[] ) should have the proper description ok 54 - col_is_unique( table, column[] ) should have the proper diagnostics pgtap-1.3.2/test/expected/update.out000066400000000000000000000001401455775703000174330ustar00rootroot00000000000000\unset ECHO 1..2 ok 1 - Old version of pgtap correctly installed ok 2 - pgtap correctly updated pgtap-1.3.2/test/expected/usergroup.out000066400000000000000000000137611455775703000202210ustar00rootroot00000000000000\unset ECHO 1..90 ok 1 - has_user(current user) should pass ok 2 - has_user(current user) should have the proper description ok 3 - has_user(current user) should have the proper diagnostics ok 4 - has_user(current user, desc) should pass ok 5 - has_user(current user, desc) should have the proper description ok 6 - has_user(current user, desc) should have the proper diagnostics ok 7 - has_user(nonexistent user) should fail ok 8 - has_user(nonexistent user) should have the proper description ok 9 - has_user(nonexistent user) should have the proper diagnostics ok 10 - has_user(nonexistent user, desc) should fail ok 11 - has_user(nonexistent user, desc) should have the proper description ok 12 - has_user(nonexistent user, desc) should have the proper diagnostics ok 13 - hasnt_user(current user) should fail ok 14 - hasnt_user(current user) should have the proper description ok 15 - hasnt_user(current user) should have the proper diagnostics ok 16 - hasnt_user(current user, desc) should fail ok 17 - hasnt_user(current user, desc) should have the proper description ok 18 - hasnt_user(current user, desc) should have the proper diagnostics ok 19 - hasnt_user(nonexistent user) should pass ok 20 - hasnt_user(nonexistent user) should have the proper description ok 21 - hasnt_user(nonexistent user) should have the proper diagnostics ok 22 - hasnt_user(nonexistent user, desc) should pass ok 23 - hasnt_user(nonexistent user, desc) should have the proper description ok 24 - hasnt_user(nonexistent user, desc) should have the proper diagnostics ok 25 - is_superuser(nonexistent user, desc) should fail ok 26 - is_superuser(nonexistent user, desc) should have the proper description ok 27 - is_superuser(nonexistent user, desc) should have the proper diagnostics ok 28 - is_superuser(nonexistent user) should fail ok 29 - is_superuser(nonexistent user) should have the proper description ok 30 - is_superuser(nonexistent user) should have the proper diagnostics ok 31 - isnt_superuser(nonexistent user, desc) should fail ok 32 - isnt_superuser(nonexistent user, desc) should have the proper description ok 33 - isnt_superuser(nonexistent user, desc) should have the proper diagnostics ok 34 - isnt_superuser(nonexistent user) should fail ok 35 - isnt_superuser(nonexistent user) should have the proper description ok 36 - isnt_superuser(nonexistent user) should have the proper diagnostics ok 37 - is_superuser( current user ) should pass ok 38 - is_superuser( current user ) should have the proper description ok 39 - is_superuser( current user ) should have the proper diagnostics ok 40 - is_superuser( current user, desc ) should pass ok 41 - is_superuser( current user, desc ) should have the proper description ok 42 - is_superuser( current user, desc ) should have the proper diagnostics ok 43 - has_group(group) should pass ok 44 - has_group(group) should have the proper description ok 45 - has_group(group) should have the proper diagnostics ok 46 - has_group(group, desc) should pass ok 47 - has_group(group, desc) should have the proper description ok 48 - has_group(group, desc) should have the proper diagnostics ok 49 - has_group(nonexistent group) should fail ok 50 - has_group(nonexistent group) should have the proper description ok 51 - has_group(nonexistent group) should have the proper diagnostics ok 52 - has_group(nonexistent group, desc) should fail ok 53 - has_group(nonexistent group, desc) should have the proper description ok 54 - has_group(nonexistent group, desc) should have the proper diagnostics ok 55 - hasnt_group(group) should fail ok 56 - hasnt_group(group) should have the proper description ok 57 - hasnt_group(group) should have the proper diagnostics ok 58 - hasnt_group(group, desc) should fail ok 59 - hasnt_group(group, desc) should have the proper description ok 60 - hasnt_group(group, desc) should have the proper diagnostics ok 61 - hasnt_group(nonexistent group) should pass ok 62 - hasnt_group(nonexistent group) should have the proper description ok 63 - hasnt_group(nonexistent group) should have the proper diagnostics ok 64 - hasnt_group(nonexistent group, desc) should pass ok 65 - hasnt_group(nonexistent group, desc) should have the proper description ok 66 - hasnt_group(nonexistent group, desc) should have the proper diagnostics ok 67 - isnt_member_of(meanies, [current_user], desc) should pass ok 68 - isnt_member_of(meanies, [current_user], desc) should have the proper description ok 69 - isnt_member_of(meanies, [current_user], desc) should have the proper diagnostics ok 70 - isnt_member_of(meanies, [current_user]) should pass ok 71 - isnt_member_of(meanies, [current_user]) should have the proper description ok 72 - isnt_member_of(meanies, [current_user]) should have the proper diagnostics ok 73 - isnt_member_of(meanies, current_user, desc) should pass ok 74 - isnt_member_of(meanies, current_user, desc) should have the proper description ok 75 - isnt_member_of(meanies, current_user, desc) should have the proper diagnostics ok 76 - isnt_member_of(meanies, current_user) should pass ok 77 - isnt_member_of(meanies, current_user) should have the proper description ok 78 - isnt_member_of(meanies, current_user) should have the proper diagnostics ok 79 - is_member_of(meanies, [current_user], desc) should pass ok 80 - is_member_of(meanies, [current_user], desc) should have the proper description ok 81 - is_member_of(meanies, [current_user], desc) should have the proper diagnostics ok 82 - is_member_of(meanies, [current_user]) should pass ok 83 - is_member_of(meanies, [current_user]) should have the proper description ok 84 - is_member_of(meanies, [current_user]) should have the proper diagnostics ok 85 - is_member_of(meanies, current_user, desc) should pass ok 86 - is_member_of(meanies, current_user, desc) should have the proper description ok 87 - is_member_of(meanies, current_user, desc) should have the proper diagnostics ok 88 - is_member_of(meanies, current_user) should pass ok 89 - is_member_of(meanies, current_user) should have the proper description ok 90 - is_member_of(meanies, current_user) should have the proper diagnostics pgtap-1.3.2/test/expected/util.out000066400000000000000000000012431455775703000171330ustar00rootroot00000000000000\unset ECHO 1..14 ok 1 - pg_type(int) should work ok 2 - pg_type(numeric) should work ok 3 - pg_type(text) should work ok 4 - pg_version() should return text ok 5 - pg_version() should return same as "server_version" setting ok 6 - pg_version() should work ok 7 - pg_version_num() should return same as "server_version_num" setting ok 8 - pg_version_num() should return integer ok 9 - pg_version_num() should be correct ok 10 - os_name() should output something like an OS name ok 11 - findfincs() should return distinct values ok 12 - pgtap_version() should work ok 13 - collect_tap(text[]) should simply collect tap ok 14 - variadic collect_tap() should simply collect tap pgtap-1.3.2/test/expected/valueset.out000066400000000000000000000571501455775703000200160ustar00rootroot00000000000000\unset ECHO 1..349 ok 1 - Should create a temp table for a prepared statement with space and values ok 2 - Table __spacenames__ should exist ok 3 - Should create a temp table for a values statement ok 4 - Table __somevals__ should exist ok 5 - set_eq(prepared, prepared, desc) should pass ok 6 - set_eq(prepared, prepared, desc) should have the proper description ok 7 - set_eq(prepared, prepared, desc) should have the proper diagnostics ok 8 - set_eq(prepared, prepared) should pass ok 9 - set_eq(prepared, prepared) should have the proper description ok 10 - set_eq(prepared, prepared) should have the proper diagnostics ok 11 - set_eq(execute, execute, desc) should pass ok 12 - set_eq(execute, execute, desc) should have the proper description ok 13 - set_eq(execute, execute, desc) should have the proper diagnostics ok 14 - set_eq(values, dupe values) should pass ok 15 - set_eq(values, dupe values) should have the proper description ok 16 - set_eq(values, dupe values) should have the proper diagnostics ok 17 - set_eq(select, prepared) fail missing should fail ok 18 - set_eq(select, prepared) fail missing should have the proper description ok 19 - set_eq(select, prepared) fail missing should have the proper diagnostics ok 20 - set_eq(select, prepared) fail missings should fail ok 21 - set_eq(select, prepared) fail missings should have the proper description ok 22 - set_eq(select, prepared) fail missings should have the proper diagnostics ok 23 - set_eq(values, values) fail mismatch should fail ok 24 - set_eq(values, values) fail mismatch should have the proper description ok 25 - set_eq(values, values) fail mismatch should have the proper diagnostics ok 26 - set_eq(values, values) fail column count should fail ok 27 - set_eq(values, values) fail column count should have the proper description ok 28 - set_eq(values, values) fail column count should have the proper diagnostics ok 29 - bag_eq(prepared, prepared, desc) should pass ok 30 - bag_eq(prepared, prepared, desc) should have the proper description ok 31 - bag_eq(prepared, prepared, desc) should have the proper diagnostics ok 32 - bag_eq(prepared, prepared) should pass ok 33 - bag_eq(prepared, prepared) should have the proper description ok 34 - bag_eq(prepared, prepared) should have the proper diagnostics ok 35 - bag_eq(execute, execute) should pass ok 36 - bag_eq(execute, execute) should have the proper description ok 37 - bag_eq(execute, execute) should have the proper diagnostics ok 38 - bag_eq(dupe values, dupe values) should pass ok 39 - bag_eq(dupe values, dupe values) should have the proper description ok 40 - bag_eq(dupe values, dupe values) should have the proper diagnostics ok 41 - bag_eq(select, prepared) fail missing should fail ok 42 - bag_eq(select, prepared) fail missing should have the proper description ok 43 - bag_eq(select, prepared) fail missing should have the proper diagnostics ok 44 - bag_eq(select, prepared) fail missings should fail ok 45 - bag_eq(select, prepared) fail missings should have the proper description ok 46 - bag_eq(select, prepared) fail missings should have the proper diagnostics ok 47 - bag_eq(values, values) fail mismatch should fail ok 48 - bag_eq(values, values) fail mismatch should have the proper description ok 49 - bag_eq(values, values) fail mismatch should have the proper diagnostics ok 50 - bag_eq(values, values) fail column count should fail ok 51 - bag_eq(values, values) fail column count should have the proper description ok 52 - bag_eq(values, values) fail column count should have the proper diagnostics ok 53 - bag_eq(values, values) fail missing dupe should fail ok 54 - bag_eq(values, values) fail missing dupe should have the proper description ok 55 - bag_eq(values, values) fail missing dupe should have the proper diagnostics ok 56 - set_ne(prepared, prepared) fail should fail ok 57 - set_ne(prepared, prepared) fail should have the proper description ok 58 - set_ne(prepared, prepared) fail should have the proper diagnostics ok 59 - set_ne fail with column mismatch should fail ok 60 - set_ne fail with column mismatch should have the proper description ok 61 - set_ne fail with column mismatch should have the proper diagnostics ok 62 - set_ne fail with different col counts should fail ok 63 - set_ne fail with different col counts should have the proper description ok 64 - set_ne fail with different col counts should have the proper diagnostics ok 65 - set_ne fail with dupe should fail ok 66 - set_ne fail with dupe should have the proper description ok 67 - set_ne fail with dupe should have the proper diagnostics ok 68 - bag_ne(prepared, prepared) fail should fail ok 69 - bag_ne(prepared, prepared) fail should have the proper description ok 70 - bag_ne(prepared, prepared) fail should have the proper diagnostics ok 71 - bag_ne fail with column mismatch should fail ok 72 - bag_ne fail with column mismatch should have the proper description ok 73 - bag_ne fail with column mismatch should have the proper diagnostics ok 74 - set_ne pass with dupe should pass ok 75 - set_ne pass with dupe should have the proper description ok 76 - set_ne pass with dupe should have the proper diagnostics ok 77 - bag_ne fail with column mismatch should fail ok 78 - bag_ne fail with column mismatch should have the proper description ok 79 - bag_ne fail with column mismatch should have the proper diagnostics ok 80 - bag_ne fail with different col counts should fail ok 81 - bag_ne fail with different col counts should have the proper description ok 82 - bag_ne fail with different col counts should have the proper diagnostics ok 83 - results_eq(prepared, prepared, desc) should pass ok 84 - results_eq(prepared, prepared, desc) should have the proper description ok 85 - results_eq(prepared, prepared, desc) should have the proper diagnostics ok 86 - results_eq(prepared, prepared) should pass ok 87 - results_eq(prepared, prepared) should have the proper description ok 88 - results_eq(prepared, prepared) should have the proper diagnostics ok 89 - results_eq(execute, execute) should pass ok 90 - results_eq(execute, execute) should have the proper description ok 91 - results_eq(execute, execute) should have the proper diagnostics ok 92 - results_eq(dupe values, dupe values) should pass ok 93 - results_eq(dupe values, dupe values) should have the proper description ok 94 - results_eq(dupe values, dupe values) should have the proper diagnostics ok 95 - results_eq(values with null, values with null) should pass ok 96 - results_eq(values with null, values with null) should have the proper description ok 97 - results_eq(values with null, values with null) should have the proper diagnostics ok 98 - results_eq(nulls, nulls) should pass ok 99 - results_eq(nulls, nulls) should have the proper description ok 100 - results_eq(nulls, nulls) should have the proper diagnostics ok 101 - results_eq(nulls, nulls) fail should fail ok 102 - results_eq(nulls, nulls) fail should have the proper description ok 103 - results_eq(nulls, nulls) fail should have the proper diagnostics ok 104 - results_eq(select, prepared) fail missing last row should fail ok 105 - results_eq(select, prepared) fail missing last row should have the proper description ok 106 - results_eq(select, prepared) fail missing last row should have the proper diagnostics ok 107 - results_eq(prepared, select) fail missing first row should fail ok 108 - results_eq(prepared, select) fail missing first row should have the proper description ok 109 - results_eq(prepared, select) fail missing first row should have the proper diagnostics ok 110 - results_eq(values dupe, values) should fail ok 111 - results_eq(values dupe, values) should have the proper description ok 112 - results_eq(values dupe, values) should have the proper diagnostics ok 113 - results_eq(values null, values) should fail ok 114 - results_eq(values null, values) should have the proper description ok 115 - results_eq(values null, values) should have the proper diagnostics ok 116 - results_eq(values, values) mismatch should fail ok 117 - results_eq(values, values) mismatch should have the proper description ok 118 - results_eq(values, values) mismatch should have the proper diagnostics ok 119 - results_eq(values, values) subtle mismatch should fail ok 120 - results_eq(values, values) subtle mismatch should have the proper description ok 121 - results_eq(values, values) subtle mismatch should have the proper diagnostics ok 122 - results_eq(values, values) fail column count should fail ok 123 - results_eq(values, values) fail column count should have the proper description ok 124 - results_eq(values, values) fail column count should have the proper diagnostics ok 125 - results_eq(cursor, prepared) should pass ok 126 - results_eq(cursor, prepared) should have the proper description ok 127 - results_eq(cursor, prepared) should have the proper diagnostics ok 128 - results_eq(prepared, cursor) should pass ok 129 - results_eq(prepared, cursor) should have the proper description ok 130 - results_eq(prepared, cursor) should have the proper diagnostics ok 131 - set_has( prepared, prepared, description ) should pass ok 132 - set_has( prepared, prepared, description ) should have the proper description ok 133 - set_has( prepared, prepared, description ) should have the proper diagnostics ok 134 - set_has( prepared, subprepared ) should pass ok 135 - set_has( prepared, subprepared ) should have the proper description ok 136 - set_has( prepared, subprepared ) should have the proper diagnostics ok 137 - set_has( execute, execute ) should pass ok 138 - set_has( execute, execute ) should have the proper description ok 139 - set_has( execute, execute ) should have the proper diagnostics ok 140 - set_has( prepared, dupes ) should pass ok 141 - set_has( prepared, dupes ) should have the proper description ok 142 - set_has( prepared, dupes ) should have the proper diagnostics ok 143 - set_has( dupes, values ) should pass ok 144 - set_has( dupes, values ) should have the proper description ok 145 - set_has( dupes, values ) should have the proper diagnostics ok 146 - set_has( missing1, expect ) should fail ok 147 - set_has( missing1, expect ) should have the proper description ok 148 - set_has( missing1, expect ) should have the proper diagnostics ok 149 - set_has(missing2, expect ) should fail ok 150 - set_has(missing2, expect ) should have the proper description ok 151 - set_has(missing2, expect ) should have the proper diagnostics ok 152 - set_has((int,text), (text,int)) should fail ok 153 - set_has((int,text), (text,int)) should have the proper description ok 154 - set_has((int,text), (text,int)) should have the proper diagnostics ok 155 - set_has((int), (text,int)) should fail ok 156 - set_has((int), (text,int)) should have the proper description ok 157 - set_has((int), (text,int)) should have the proper diagnostics ok 158 - bag_has( prepared, prepared, description ) should pass ok 159 - bag_has( prepared, prepared, description ) should have the proper description ok 160 - bag_has( prepared, prepared, description ) should have the proper diagnostics ok 161 - bag_has( prepared, subprepared ) should pass ok 162 - bag_has( prepared, subprepared ) should have the proper description ok 163 - bag_has( prepared, subprepared ) should have the proper diagnostics ok 164 - bag_has( execute, execute ) should pass ok 165 - bag_has( execute, execute ) should have the proper description ok 166 - bag_has( execute, execute ) should have the proper diagnostics ok 167 - bag_has( prepared, dupes ) should fail ok 168 - bag_has( prepared, dupes ) should have the proper description ok 169 - bag_has( prepared, dupes ) should have the proper diagnostics ok 170 - bag_has( dupes, values ) should pass ok 171 - bag_has( dupes, values ) should have the proper description ok 172 - bag_has( dupes, values ) should have the proper diagnostics ok 173 - bag_has( missing1, expect ) should fail ok 174 - bag_has( missing1, expect ) should have the proper description ok 175 - bag_has( missing1, expect ) should have the proper diagnostics ok 176 - bag_has(missing2, expect ) should fail ok 177 - bag_has(missing2, expect ) should have the proper description ok 178 - bag_has(missing2, expect ) should have the proper diagnostics ok 179 - bag_has((int,text), (text,int)) should fail ok 180 - bag_has((int,text), (text,int)) should have the proper description ok 181 - bag_has((int,text), (text,int)) should have the proper diagnostics ok 182 - bag_has((int), (text,int)) should fail ok 183 - bag_has((int), (text,int)) should have the proper description ok 184 - bag_has((int), (text,int)) should have the proper diagnostics ok 185 - set_hasnt( prepared, prepared, description ) should pass ok 186 - set_hasnt( prepared, prepared, description ) should have the proper description ok 187 - set_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 188 - set_hasnt( prepared, prepared, description ) should pass ok 189 - set_hasnt( prepared, prepared, description ) should have the proper description ok 190 - set_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 191 - set_hasnt( execute, execute ) should pass ok 192 - set_hasnt( execute, execute ) should have the proper description ok 193 - set_hasnt( execute, execute ) should have the proper diagnostics ok 194 - set_hasnt( prepared, dupes ) should pass ok 195 - set_hasnt( prepared, dupes ) should have the proper description ok 196 - set_hasnt( prepared, dupes ) should have the proper diagnostics ok 197 - set_hasnt( prepared, value ) should fail ok 198 - set_hasnt( prepared, value ) should have the proper description ok 199 - set_hasnt( prepared, value ) should have the proper diagnostics ok 200 - set_hasnt( prepared, values ) should fail ok 201 - set_hasnt( prepared, values ) should have the proper description ok 202 - set_hasnt( prepared, values ) should have the proper diagnostics ok 203 - set_hasnt((int,text), (text,int)) should fail ok 204 - set_hasnt((int,text), (text,int)) should have the proper description ok 205 - set_hasnt((int,text), (text,int)) should have the proper diagnostics ok 206 - set_hasnt((int), (text,int)) should fail ok 207 - set_hasnt((int), (text,int)) should have the proper description ok 208 - set_hasnt((int), (text,int)) should have the proper diagnostics ok 209 - bag_hasnt( prepared, prepared, description ) should pass ok 210 - bag_hasnt( prepared, prepared, description ) should have the proper description ok 211 - bag_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 212 - bag_hasnt( prepared, prepared, description ) should pass ok 213 - bag_hasnt( prepared, prepared, description ) should have the proper description ok 214 - bag_hasnt( prepared, prepared, description ) should have the proper diagnostics ok 215 - bag_hasnt( execute, execute ) should pass ok 216 - bag_hasnt( execute, execute ) should have the proper description ok 217 - bag_hasnt( execute, execute ) should have the proper diagnostics ok 218 - bag_hasnt( prepared, value ) should fail ok 219 - bag_hasnt( prepared, value ) should have the proper description ok 220 - bag_hasnt( prepared, value ) should have the proper diagnostics ok 221 - bag_hasnt( prepared, values ) should fail ok 222 - bag_hasnt( prepared, values ) should have the proper description ok 223 - bag_hasnt( prepared, values ) should have the proper diagnostics ok 224 - bag_hasnt((int,text), (text,int)) should fail ok 225 - bag_hasnt((int,text), (text,int)) should have the proper description ok 226 - bag_hasnt((int,text), (text,int)) should have the proper diagnostics ok 227 - bag_hasnt((int), (text,int)) should fail ok 228 - bag_hasnt((int), (text,int)) should have the proper description ok 229 - bag_hasnt((int), (text,int)) should have the proper diagnostics ok 230 - bag_hasnt( dupes, dupes ) should fail ok 231 - bag_hasnt( dupes, dupes ) should have the proper description ok 232 - bag_hasnt( dupes, dupes ) should have the proper diagnostics ok 233 - bag_hasnt( value, dupes ) should fail ok 234 - bag_hasnt( value, dupes ) should have the proper description ok 235 - bag_hasnt( value, dupes ) should have the proper diagnostics ok 236 - set_eq(prepared, array, desc) should pass ok 237 - set_eq(prepared, array, desc) should have the proper description ok 238 - set_eq(prepared, array, desc) should have the proper diagnostics ok 239 - set_eq(prepared, array) should pass ok 240 - set_eq(prepared, array) should have the proper description ok 241 - set_eq(prepared, array) should have the proper diagnostics ok 242 - set_eq(prepared, dupe array) should pass ok 243 - set_eq(prepared, dupe array) should have the proper description ok 244 - set_eq(prepared, dupe array) should have the proper diagnostics ok 245 - set_eq(prepared, array) extra record should fail ok 246 - set_eq(prepared, array) extra record should have the proper description ok 247 - set_eq(prepared, array) extra record should have the proper diagnostics ok 248 - set_eq(prepared, array) missing record should fail ok 249 - set_eq(prepared, array) missing record should have the proper description ok 250 - set_eq(prepared, array) missing record should have the proper diagnostics ok 251 - set_eq(sql, array) incompatible types should fail ok 252 - set_eq(sql, array) incompatible types should have the proper description ok 253 - set_eq(sql, array) incompatible types should have the proper diagnostics ok 254 - bag_eq(prepared, array, desc) should pass ok 255 - bag_eq(prepared, array, desc) should have the proper description ok 256 - bag_eq(prepared, array, desc) should have the proper diagnostics ok 257 - bag_eq(prepared, array) should pass ok 258 - bag_eq(prepared, array) should have the proper description ok 259 - bag_eq(prepared, array) should have the proper diagnostics ok 260 - bag_eq(prepared, dupe array) fail should fail ok 261 - bag_eq(prepared, dupe array) fail should have the proper description ok 262 - bag_eq(prepared, dupe array) fail should have the proper diagnostics ok 263 - bag_eq(prepared, array) extra record should fail ok 264 - bag_eq(prepared, array) extra record should have the proper description ok 265 - bag_eq(prepared, array) extra record should have the proper diagnostics ok 266 - bag_eq(prepared, array) missing record should fail ok 267 - bag_eq(prepared, array) missing record should have the proper description ok 268 - bag_eq(prepared, array) missing record should have the proper diagnostics ok 269 - bag_eq(prepared, array) incompatible types should fail ok 270 - bag_eq(prepared, array) incompatible types should have the proper description ok 271 - bag_eq(prepared, array) incompatible types should have the proper diagnostics ok 272 - set_ne(prepared, array, desc) should pass ok 273 - set_ne(prepared, array, desc) should have the proper description ok 274 - set_ne(prepared, array, desc) should have the proper diagnostics ok 275 - set_ne(prepared, array) should pass ok 276 - set_ne(prepared, array) should have the proper description ok 277 - set_ne(prepared, array) should have the proper diagnostics ok 278 - set_ne(prepared, array) fail should fail ok 279 - set_ne(prepared, array) fail should have the proper description ok 280 - set_ne(prepared, array) fail should have the proper diagnostics ok 281 - set_ne(prepared, dupes array) fail should fail ok 282 - set_ne(prepared, dupes array) fail should have the proper description ok 283 - set_ne(prepared, dupes array) fail should have the proper diagnostics ok 284 - set_ne(sql, array) incompatible types should fail ok 285 - set_ne(sql, array) incompatible types should have the proper description ok 286 - set_ne(sql, array) incompatible types should have the proper diagnostics ok 287 - bag_ne(prepared, array, desc) should pass ok 288 - bag_ne(prepared, array, desc) should have the proper description ok 289 - bag_ne(prepared, array, desc) should have the proper diagnostics ok 290 - bag_ne(prepared, array) should pass ok 291 - bag_ne(prepared, array) should have the proper description ok 292 - bag_ne(prepared, array) should have the proper diagnostics ok 293 - bag_ne(prepared, array) fail should fail ok 294 - bag_ne(prepared, array) fail should have the proper description ok 295 - bag_ne(prepared, array) fail should have the proper diagnostics ok 296 - bag_ne(prepared, dupes array) should pass ok 297 - bag_ne(prepared, dupes array) should have the proper description ok 298 - bag_ne(prepared, dupes array) should have the proper diagnostics ok 299 - bag_ne(prepared, array) incompatible types should fail ok 300 - bag_ne(prepared, array) incompatible types should have the proper description ok 301 - bag_ne(prepared, array) incompatible types should have the proper diagnostics ok 302 - results_eq(prepared, array, desc) should pass ok 303 - results_eq(prepared, array, desc) should have the proper description ok 304 - results_eq(prepared, array, desc) should have the proper diagnostics ok 305 - results_eq(prepared, array) should pass ok 306 - results_eq(prepared, array) should have the proper description ok 307 - results_eq(prepared, array) should have the proper diagnostics ok 308 - results_eq(prepared, array) extra record should fail ok 309 - results_eq(prepared, array) extra record should have the proper description ok 310 - results_eq(prepared, array) extra record should have the proper diagnostics ok 311 - results_ne(prepared, prepared, desc) should pass ok 312 - results_ne(prepared, prepared, desc) should have the proper description ok 313 - results_ne(prepared, prepared, desc) should have the proper diagnostics ok 314 - results_ne(prepared, prepared) should pass ok 315 - results_ne(prepared, prepared) should have the proper description ok 316 - results_ne(prepared, prepared) should have the proper diagnostics ok 317 - results_ne(execute, execute) should pass ok 318 - results_ne(execute, execute) should have the proper description ok 319 - results_ne(execute, execute) should have the proper diagnostics ok 320 - results_ne(dupe values, dupe values) should pass ok 321 - results_ne(dupe values, dupe values) should have the proper description ok 322 - results_ne(dupe values, dupe values) should have the proper diagnostics ok 323 - results_ne(values with null, values with null) should pass ok 324 - results_ne(values with null, values with null) should have the proper description ok 325 - results_ne(values with null, values with null) should have the proper diagnostics ok 326 - results_ne(nulls, nulls) should pass ok 327 - results_ne(nulls, nulls) should have the proper description ok 328 - results_ne(nulls, nulls) should have the proper diagnostics ok 329 - results_ne(values dupe, values) should pass ok 330 - results_ne(values dupe, values) should have the proper description ok 331 - results_ne(values dupe, values) should have the proper diagnostics ok 332 - results_ne(values null, values) should pass ok 333 - results_ne(values null, values) should have the proper description ok 334 - results_ne(values null, values) should have the proper diagnostics ok 335 - results_ne(values, values) mismatch should fail ok 336 - results_ne(values, values) mismatch should have the proper description ok 337 - results_ne(values, values) mismatch should have the proper diagnostics ok 338 - results_ne(values, values) subtle mismatch should fail ok 339 - results_ne(values, values) subtle mismatch should have the proper description ok 340 - results_ne(values, values) subtle mismatch should have the proper diagnostics ok 341 - results_ne(values, values) fail column count should fail ok 342 - results_ne(values, values) fail column count should have the proper description ok 343 - results_ne(values, values) fail column count should have the proper diagnostics ok 344 - results_ne(cursor, prepared) should fail ok 345 - results_ne(cursor, prepared) should have the proper description ok 346 - results_ne(cursor, prepared) should have the proper diagnostics ok 347 - results_ne(prepared, cursor) should fail ok 348 - results_ne(prepared, cursor) should have the proper description ok 349 - results_ne(prepared, cursor) should have the proper diagnostics pgtap-1.3.2/test/psql.sql000066400000000000000000000003341455775703000153240ustar00rootroot00000000000000\set QUIET 1 -- -- Tests for pgTAP. -- -- -- Format the output for nice TAP. \pset format unaligned \pset tuples_only true \pset pager -- Revert all changes on failure. \set ON_ERROR_ROLLBACK 1 \set ON_ERROR_STOP true pgtap-1.3.2/test/run000077500000000000000000000002051455775703000143530ustar00rootroot00000000000000#!/usr/bin/env sh set -e -u -o pipefail make install psql -Ec 'DROP EXTENSION IF EXISTS pgtap; CREATE EXTENSION pgtap;' make test pgtap-1.3.2/test/schedule/000077500000000000000000000000001455775703000154205ustar00rootroot00000000000000pgtap-1.3.2/test/schedule/build.sql000066400000000000000000000003031455775703000172340ustar00rootroot00000000000000\unset ECHO \i test/psql.sql /* * Presumably no one is installing this way anymore, but this is a nice way to * pick up any syntax errors during install. */ BEGIN; \i sql/pgtap.sql ROLLBACK; pgtap-1.3.2/test/schedule/create.sql000066400000000000000000000000651455775703000174050ustar00rootroot00000000000000\unset ECHO \i test/psql.sql CREATE EXTENSION pgtap; pgtap-1.3.2/test/schedule/main.sch000066400000000000000000000000311455775703000170350ustar00rootroot00000000000000test: build test: create pgtap-1.3.2/test/schedule/update.sch000066400000000000000000000000151455775703000173750ustar00rootroot00000000000000test: update pgtap-1.3.2/test/schedule/update.sql000066400000000000000000000006541455775703000174300ustar00rootroot00000000000000\unset ECHO \i test/psql.sql CREATE EXTENSION pgtap VERSION :'old_ver'; SELECT plan(2); SELECT is( (SELECT extversion FROM pg_extension WHERE extname = 'pgtap') , :'old_ver' , 'Old version of pgtap correctly installed' ); ALTER EXTENSION pgtap UPDATE TO :'new_ver'; SELECT is( (SELECT extversion FROM pg_extension WHERE extname = 'pgtap') , :'new_ver' , 'pgtap correctly updated' ); SELECT finish(); pgtap-1.3.2/test/setup.sql000066400000000000000000000000551455775703000155050ustar00rootroot00000000000000\i test/psql.sql BEGIN; -- \i sql/pgtap.sql pgtap-1.3.2/test/sql/000077500000000000000000000000001455775703000144235ustar00rootroot00000000000000pgtap-1.3.2/test/sql/aretap.sql000066400000000000000000001516061455775703000164310ustar00rootroot00000000000000\unset ECHO \i test/setup.sql -- \i sql/pgtap.sql SELECT plan(459); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.fou( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), "myInt" NUMERIC(8) ); -- Create a partition. CREATE FUNCTION mkpart() RETURNS SETOF TEXT AS $$ BEGIN IF pg_version_num() >= 100000 THEN EXECUTE $E$ CREATE TABLE public.foo (dt DATE NOT NULL) PARTITION BY RANGE (dt); $E$; ELSE EXECUTE $E$ CREATE TABLE public.foo (dt DATE NOT NULL); $E$; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM mkpart(); CREATE RULE ins_me AS ON INSERT TO public.fou DO NOTHING; CREATE RULE upd_me AS ON UPDATE TO public.fou DO NOTHING; CREATE INDEX idx_fou_id ON public.fou(id); CREATE INDEX idx_fou_name ON public.fou(name); CREATE VIEW public.voo AS SELECT * FROM foo; CREATE VIEW public.vou AS SELECT * FROM fou; CREATE SEQUENCE public.someseq; CREATE SEQUENCE public.sumeseq; CREATE SCHEMA someschema; CREATE FUNCTION someschema.yip() returns boolean as 'SELECT TRUE' language SQL; CREATE FUNCTION someschema.yap() returns boolean as 'SELECT TRUE' language SQL; CREATE DOMAIN public.goofy AS text CHECK ( TRUE ); CREATE DOMAIN public."myDomain" AS text CHECK ( TRUE ); CREATE OR REPLACE FUNCTION public.goofy_cmp(goofy,goofy) RETURNS INTEGER AS $$ SELECT CASE WHEN $1 = $2 THEN 0 WHEN $1 > $2 THEN 1 ELSE -1 END; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION public.goofy_eq (goofy, goofy) RETURNS boolean AS $$ SELECT $1 = $2; $$ LANGUAGE SQL IMMUTABLE STRICT; CREATE SCHEMA disney; CREATE OPERATOR disney.= ( PROCEDURE = goofy_eq, LEFTARG = goofy, RIGHTARG = goofy); CREATE OPERATOR = ( PROCEDURE = goofy_eq, LEFTARG = goofy, RIGHTARG = goofy); CREATE OPERATOR CLASS public.goofy_ops DEFAULT FOR TYPE goofy USING BTREE AS OPERATOR 1 disney.=, FUNCTION 1 goofy_cmp(goofy,goofy) ; CREATE TYPE someschema.sometype AS ( id INT, name TEXT ); CREATE TYPE someschema."myType" AS ( id INT, foo INT ); -- Create a procedure. DO $$ BEGIN IF pg_version_num() >= 110000 THEN EXECUTE 'CREATE PROCEDURE someschema.someproc(int) LANGUAGE SQL AS '''''; ELSE CREATE FUNCTION someschema.someproc(int) RETURNS void AS '' LANGUAGE SQL; END IF; END; $$; RESET client_min_messages; /****************************************************************************/ -- Test tablespaces_are(). CREATE FUNCTION ___myts(ex text) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT spcname FROM pg_catalog.pg_tablespace WHERE spcname <> $1 ); $$ LANGUAGE SQL; SELECT * FROM check_test( tablespaces_are( ___myts(''), 'whatever' ), true, 'tablespaces_are(tablespaces, desc)', 'whatever', '' ); SELECT * FROM check_test( tablespaces_are( ___myts('') ), true, 'tablespaces_are(tablespaces)', 'There should be the correct tablespaces', '' ); SELECT * FROM check_test( tablespaces_are( array_append(___myts(''), '__booya__'), 'whatever' ), false, 'tablespaces_are(tablespaces, desc) missing', 'whatever', ' Missing tablespaces: __booya__' ); SELECT * FROM check_test( tablespaces_are( ___myts('pg_default'), 'whatever' ), false, 'tablespaces_are(tablespaces, desc) extra', 'whatever', ' Extra tablespaces: pg_default' ); SELECT * FROM check_test( tablespaces_are( array_append(___myts('pg_default'), '__booya__'), 'whatever' ), false, 'tablespaces_are(tablespaces, desc) extras and missing', 'whatever', ' Extra tablespaces: pg_default Missing tablespaces: __booya__' ); /****************************************************************************/ -- Test schemas_are(). CREATE FUNCTION ___mysch(ex text) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT nspname FROM pg_catalog.pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname <> 'information_schema' AND nspname <> $1 ); $$ LANGUAGE SQL; SELECT * FROM check_test( schemas_are( ___mysch(''), 'whatever' ), true, 'schemas_are(schemas, desc)', 'whatever', '' ); SELECT * FROM check_test( schemas_are( ___mysch('') ), true, 'schemas_are(schemas)', 'There should be the correct schemas', '' ); SELECT * FROM check_test( schemas_are( array_append(___mysch(''), '__howdy__'), 'whatever' ), false, 'schemas_are(schemas, desc) missing', 'whatever', ' Missing schemas: __howdy__' ); SELECT * FROM check_test( schemas_are( ___mysch('someschema'), 'whatever' ), false, 'schemas_are(schemas, desc) extras', 'whatever', ' Extra schemas: someschema' ); SELECT * FROM check_test( schemas_are( array_append(___mysch('someschema'), '__howdy__'), 'whatever' ), false, 'schemas_are(schemas, desc) missing and extras', 'whatever', ' Extra schemas: someschema Missing schemas: __howdy__' ); /****************************************************************************/ -- Test tables_are(). SELECT * FROM check_test( tables_are( 'public', ARRAY['fou', 'foo'], 'whatever' ), true, 'tables_are(schema, tables, desc)', 'whatever', '' ); SELECT * FROM check_test( tables_are( 'public', ARRAY['fou', 'foo'] ), true, 'tables_are(schema, tables)', 'Schema public should have the correct tables', '' ); SELECT * FROM check_test( tables_are( ARRAY['fou', 'foo'] ), true, 'tables_are(tables)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables', '' ); SELECT * FROM check_test( tables_are( ARRAY['fou', 'foo'], 'whatever' ), true, 'tables_are(tables, desc)', 'whatever', '' ); SELECT * FROM check_test( tables_are( 'public', ARRAY['fou', 'foo', 'bar'] ), false, 'tables_are(schema, tables) missing', 'Schema public should have the correct tables', ' Missing tables: bar' ); SELECT * FROM check_test( tables_are( ARRAY['fou', 'foo', 'bar'] ), false, 'tables_are(tables) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables', ' Missing tables: bar' ); SELECT * FROM check_test( tables_are( 'public', ARRAY['fou'] ), false, 'tables_are(schema, tables) extra', 'Schema public should have the correct tables', ' Extra tables: foo' ); SELECT * FROM check_test( tables_are( ARRAY['fou'] ), false, 'tables_are(tables) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables', ' Extra tables: foo' ); SELECT * FROM check_test( tables_are( 'public', ARRAY['bar', 'baz'] ), false, 'tables_are(schema, tables) extra and missing', 'Schema public should have the correct tables', ' Extra tables: fo[ou] fo[ou] Missing tables: ba[rz] ba[rz]', true ); SELECT * FROM check_test( tables_are( ARRAY['bar', 'baz'] ), false, 'tables_are(tables) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct tables', ' Extra tables:' || ' fo[ou] fo[ou] Missing tables:' || ' ba[rz] ba[rz]', true ); /****************************************************************************/ -- Test views_are(). SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo'], 'whatever' ), true, 'views_are(schema, views, desc)', 'whatever', '' ); SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo'] ), true, 'views_are(schema, views)', 'Schema public should have the correct views', '' ); SELECT * FROM check_test( views_are( ARRAY['vou', 'voo'] ), true, 'views_are(views)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', '' ); SELECT * FROM check_test( views_are( ARRAY['vou', 'voo'], 'whatever' ), true, 'views_are(views, desc)', 'whatever', '' ); SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo', 'bar'] ), false, 'views_are(schema, views) missing', 'Schema public should have the correct views', ' Missing views: bar' ); SELECT * FROM check_test( views_are( ARRAY['vou', 'voo', 'bar'] ), false, 'views_are(views) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Missing views: bar' ); SELECT * FROM check_test( views_are( 'public', ARRAY['vou'] ), false, 'views_are(schema, views) extra', 'Schema public should have the correct views', ' Extra views: voo' ); SELECT * FROM check_test( views_are( ARRAY['vou'] ), false, 'views_are(views) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Extra views: voo' ); SELECT * FROM check_test( views_are( 'public', ARRAY['bar', 'baz'] ), false, 'views_are(schema, views) extra and missing', 'Schema public should have the correct views', ' Extra views: vo[ou] vo[ou] Missing views: ba[rz] ba[rz]', true ); SELECT * FROM check_test( views_are( ARRAY['bar', 'baz'] ), false, 'views_are(views) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Extra views:' || ' vo[ou] vo[ou] Missing views:' || ' ba[rz] ba[rz]', true ); /****************************************************************************/ -- Test sequences_are(). SELECT * FROM check_test( sequences_are( 'public', ARRAY['sumeseq', 'someseq'], 'whatever' ), true, 'sequences_are(schema, sequences, desc)', 'whatever', '' ); SELECT * FROM check_test( sequences_are( 'public', ARRAY['sumeseq', 'someseq'] ), true, 'sequences_are(schema, sequences)', 'Schema public should have the correct sequences', '' ); SELECT * FROM check_test( sequences_are( ARRAY['sumeseq', 'someseq'] ), true, 'sequences_are(sequences)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct sequences', '' ); SELECT * FROM check_test( sequences_are( ARRAY['sumeseq', 'someseq'], 'whatever' ), true, 'sequences_are(sequences, desc)', 'whatever', '' ); SELECT * FROM check_test( sequences_are( 'public', ARRAY['sumeseq', 'someseq', 'bar'] ), false, 'sequences_are(schema, sequences) missing', 'Schema public should have the correct sequences', ' Missing sequences: bar' ); SELECT * FROM check_test( sequences_are( ARRAY['sumeseq', 'someseq', 'bar'] ), false, 'sequences_are(sequences) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct sequences', ' Missing sequences: bar' ); SELECT * FROM check_test( sequences_are( 'public', ARRAY['sumeseq'] ), false, 'sequences_are(schema, sequences) extra', 'Schema public should have the correct sequences', ' Extra sequences: someseq' ); SELECT * FROM check_test( sequences_are( ARRAY['sumeseq'] ), false, 'sequences_are(sequences) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct sequences', ' Extra sequences: someseq' ); SELECT * FROM check_test( sequences_are( 'public', ARRAY['bar', 'baz'] ), false, 'sequences_are(schema, sequences) extra and missing', 'Schema public should have the correct sequences', ' Extra sequences: s[ou]meseq s[ou]meseq Missing sequences: ba[rz] ba[rz]', true ); SELECT * FROM check_test( sequences_are( ARRAY['bar', 'baz'] ), false, 'sequences_are(sequences) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct sequences', ' Extra sequences:' || ' s[ou]meseq s[ou]meseq Missing sequences:' || ' ba[rz] ba[rz]', true ); /****************************************************************************/ -- Test functions_are(). SELECT * FROM check_test( functions_are( 'someschema', ARRAY['yip', 'yap', 'someproc'], 'whatever' ), true, 'functions_are(schema, functions, desc)', 'whatever', '' ); SELECT * FROM check_test( functions_are( 'someschema', ARRAY['yip', 'yap', 'someproc'] ), true, 'functions_are(schema, functions)', 'Schema someschema should have the correct functions' '' ); SELECT * FROM check_test( functions_are( 'someschema', ARRAY['yip', 'yap', 'someproc', 'yop'], 'whatever' ), false, 'functions_are(schema, functions, desc) + missing', 'whatever', ' Missing functions: yop' ); SELECT * FROM check_test( functions_are( 'someschema', ARRAY['yip', 'someproc'], 'whatever' ), false, 'functions_are(schema, functions, desc) + extra', 'whatever', ' Extra functions: yap' ); SELECT * FROM check_test( functions_are( 'someschema', ARRAY['yap', 'yop', 'someproc'], 'whatever' ), false, 'functions_are(schema, functions, desc) + extra & missing', 'whatever', ' Extra functions: yip Missing functions: yop' ); CREATE FUNCTION ___myfunk(ex text) RETURNS NAME[] AS $$ SELECT ARRAY( SELECT p.proname FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_proc p ON n.oid = p.pronamespace WHERE pg_catalog.pg_function_is_visible(p.oid) AND n.nspname NOT IN ('pg_catalog', 'information_schema') AND p.proname <> $1 ); $$ LANGUAGE SQL; SELECT * FROM check_test( functions_are( ___myfunk(''), 'whatever' ), true, 'functions_are(functions, desc)', 'whatever', '' ); SELECT * FROM check_test( functions_are( ___myfunk('') ), true, 'functions_are(functions)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct functions', '' ); SELECT * FROM check_test( functions_are( array_append(___myfunk(''), '__booyah__'), 'whatever' ), false, 'functions_are(functions, desc) + missing', 'whatever', ' Missing functions: __booyah__' ); SELECT * FROM check_test( functions_are( ___myfunk('check_test'), 'whatever' ), false, 'functions_are(functions, desc) + extra', 'whatever', ' Extra functions: check_test' ); SELECT * FROM check_test( functions_are( array_append(___myfunk('check_test'), '__booyah__'), 'whatever' ), false, 'functions_are(functions, desc) + extra & missing', 'whatever', ' Extra functions: check_test Missing functions: __booyah__' ); /****************************************************************************/ -- Test indexes_are(). SELECT * FROM check_test( indexes_are( 'public', 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey'], 'whatever' ), true, 'indexes_are(schema, table, indexes, desc)', 'whatever', '' ); SELECT * FROM check_test( indexes_are( 'public', 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey'] ), true, 'indexes_are(schema, table, indexes)', 'Table public.fou should have the correct indexes', '' ); SELECT * FROM check_test( indexes_are( 'public', 'fou', ARRAY['idx_fou_id', 'idx_fou_name'] ), false, 'indexes_are(schema, table, indexes) + extra', 'Table public.fou should have the correct indexes', ' Extra indexes: fou_pkey' ); SELECT * FROM check_test( indexes_are( 'public', 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey', 'howdy'] ), false, 'indexes_are(schema, table, indexes) + missing', 'Table public.fou should have the correct indexes', ' Missing indexes: howdy' ); SELECT * FROM check_test( indexes_are( 'public', 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'howdy'] ), false, 'indexes_are(schema, table, indexes) + extra & missing', 'Table public.fou should have the correct indexes', ' Extra indexes: fou_pkey Missing indexes: howdy' ); SELECT * FROM check_test( indexes_are( 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey'], 'whatever' ), true, 'indexes_are(table, indexes, desc)', 'whatever', '' ); SELECT * FROM check_test( indexes_are( 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey'] ), true, 'indexes_are(table, indexes)', 'Table fou should have the correct indexes', '' ); SELECT * FROM check_test( indexes_are( 'fou', ARRAY['idx_fou_id', 'idx_fou_name'] ), false, 'indexes_are(table, indexes) + extra', 'Table fou should have the correct indexes', ' Extra indexes: fou_pkey' ); SELECT * FROM check_test( indexes_are( 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'fou_pkey', 'howdy'] ), false, 'indexes_are(table, indexes) + missing', 'Table fou should have the correct indexes', ' Missing indexes: howdy' ); SELECT * FROM check_test( indexes_are( 'fou', ARRAY['idx_fou_id', 'idx_fou_name', 'howdy'] ), false, 'indexes_are(table, indexes) + extra & missing', 'Table fou should have the correct indexes', ' Extra indexes: fou_pkey Missing indexes: howdy' ); /****************************************************************************/ -- Test users_are(). CREATE FUNCTION ___myusers(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT usename FROM pg_catalog.pg_user WHERE usename <> $1 ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( users_are( ___myusers(''), 'whatever' ), true, 'users_are(users, desc)', 'whatever', '' ); SELECT * FROM check_test( users_are( ___myusers('') ), true, 'users_are(users)', 'There should be the correct users', '' ); SELECT * FROM check_test( users_are( array_append(___myusers(''), '__howdy__'), 'whatever' ), false, 'users_are(users, desc) missing', 'whatever', ' Missing users: __howdy__' ); SELECT * FROM check_test( users_are( ___myusers(current_user), 'whatever' ), false, 'users_are(users, desc) extras', 'whatever', ' Extra users: ' || quote_ident(current_user) ); SELECT * FROM check_test( users_are( array_append(___myusers(current_user), '__howdy__'), 'whatever' ), false, 'users_are(users, desc) missing and extras', 'whatever', ' Extra users: ' || quote_ident(current_user) || ' Missing users: __howdy__' ); /****************************************************************************/ -- Test groups_are(). CREATE GROUP meanies; CREATE FUNCTION ___mygroups(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT groname FROM pg_catalog.pg_group WHERE groname <> $1 ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( groups_are( ___mygroups(''), 'whatever' ), true, 'groups_are(groups, desc)', 'whatever', '' ); SELECT * FROM check_test( groups_are( ___mygroups('') ), true, 'groups_are(groups)', 'There should be the correct groups', '' ); SELECT * FROM check_test( groups_are( array_append(___mygroups(''), '__howdy__'), 'whatever' ), false, 'groups_are(groups, desc) missing', 'whatever', ' Missing groups: __howdy__' ); SELECT * FROM check_test( groups_are( ___mygroups('meanies'), 'whatever' ), false, 'groups_are(groups, desc) extras', 'whatever', ' Extra groups: meanies' ); SELECT * FROM check_test( groups_are( array_append(___mygroups('meanies'), '__howdy__'), 'whatever' ), false, 'groups_are(groups, desc) missing and extras', 'whatever', ' Extra groups: meanies Missing groups: __howdy__' ); /****************************************************************************/ -- Test languages_are(). CREATE FUNCTION ___mylangs(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT lanname FROM pg_catalog.pg_language WHERE lanispl AND lanname <> $1 ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( languages_are( ___mylangs(''), 'whatever' ), true, 'languages_are(languages, desc)', 'whatever', '' ); SELECT * FROM check_test( languages_are( ___mylangs('') ), true, 'languages_are(languages)', 'There should be the correct procedural languages', '' ); SELECT * FROM check_test( languages_are( array_append(___mylangs(''), 'plomgwtf'), 'whatever' ), false, 'languages_are(languages, desc) missing', 'whatever', ' Missing languages: plomgwtf' ); SELECT * FROM check_test( languages_are( ___mylangs('plpgsql'), 'whatever' ), false, 'languages_are(languages, desc) extras', 'whatever', ' Extra languages: plpgsql' ); SELECT * FROM check_test( languages_are( array_append(___mylangs('plpgsql'), 'plomgwtf'), 'whatever' ), false, 'languages_are(languages, desc) missing and extras', 'whatever', ' Extra languages: plpgsql Missing languages: plomgwtf' ); /****************************************************************************/ -- Test opclasses_are(). SELECT * FROM check_test( opclasses_are( 'public', ARRAY['goofy_ops'], 'whatever' ), true, 'opclasses_are(schema, opclasses, desc)', 'whatever', '' ); SELECT * FROM check_test( opclasses_are( 'public', ARRAY['goofy_ops'] ), true, 'opclasses_are(schema, opclasses)', 'Schema public should have the correct operator classes' '' ); SELECT * FROM check_test( opclasses_are( 'public', ARRAY['goofy_ops', 'yops'], 'whatever' ), false, 'opclasses_are(schema, opclasses, desc) + missing', 'whatever', ' Missing operator classes: yops' ); SELECT * FROM check_test( opclasses_are( 'public', '{}'::name[], 'whatever' ), false, 'opclasses_are(schema, opclasses, desc) + extra', 'whatever', ' Extra operator classes: goofy_ops' ); SELECT * FROM check_test( opclasses_are( 'public', ARRAY['yops'], 'whatever' ), false, 'opclasses_are(schema, opclasses, desc) + extra & missing', 'whatever', ' Extra operator classes: goofy_ops Missing operator classes: yops' ); CREATE FUNCTION ___myopc(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT oc.opcname FROM pg_catalog.pg_opclass oc JOIN pg_catalog.pg_namespace n ON oc.opcnamespace = n.oid WHERE n.nspname <> 'pg_catalog' AND oc.opcname <> $1 AND pg_catalog.pg_opclass_is_visible(oc.oid) ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( opclasses_are( ___myopc('') ), true, 'opclasses_are(opclasses)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct operator classes', '' ); SELECT * FROM check_test( opclasses_are( array_append(___myopc(''), 'sillyops'), 'whatever' ), false, 'opclasses_are(opclasses, desc) + missing', 'whatever', ' Missing operator classes: sillyops' ); SELECT * FROM check_test( opclasses_are( ___myopc('goofy_ops'), 'whatever' ), false, 'opclasses_are(opclasses, desc) + extra', 'whatever', ' Extra operator classes: goofy_ops' ); SELECT * FROM check_test( opclasses_are( array_append(___myopc('goofy_ops'), 'sillyops'), 'whatever' ), false, 'opclasses_are(opclasses, desc) + extra & missing', 'whatever', ' Extra operator classes: goofy_ops Missing operator classes: sillyops' ); /****************************************************************************/ -- Test rules_are(). SELECT * FROM check_test( rules_are( 'public', 'fou', ARRAY['ins_me', 'upd_me'], 'whatever' ), true, 'rules_are(schema, table, rules, desc)', 'whatever', '' ); SELECT * FROM check_test( rules_are( 'public', 'fou', ARRAY['ins_me', 'upd_me'] ), true, 'rules_are(schema, table, rules)', 'Relation public.fou should have the correct rules', '' ); SELECT * FROM check_test( rules_are( 'public', 'fou', ARRAY['ins_me'] ), false, 'rules_are(schema, table, rules) + extra', 'Relation public.fou should have the correct rules', ' Extra rules: upd_me' ); SELECT * FROM check_test( rules_are( 'public', 'fou', ARRAY['ins_me', 'upd_me', 'del_me'] ), false, 'rules_are(schema, table, rules) + missing', 'Relation public.fou should have the correct rules', ' Missing rules: del_me' ); SELECT * FROM check_test( rules_are( 'public', 'fou', ARRAY['ins_me', 'del_me'] ), false, 'rules_are(schema, table, rules) + extra & missing', 'Relation public.fou should have the correct rules', ' Extra rules: upd_me Missing rules: del_me' ); SELECT * FROM check_test( rules_are( 'fou', ARRAY['ins_me', 'upd_me'], 'whatever' ), true, 'rules_are(table, rules, desc)', 'whatever', '' ); SELECT * FROM check_test( rules_are( 'fou', ARRAY['ins_me', 'upd_me'] ), true, 'rules_are(table, rules)', 'Relation fou should have the correct rules', '' ); SELECT * FROM check_test( rules_are( 'fou', ARRAY['ins_me'] ), false, 'rules_are(table, rules) + extra', 'Relation fou should have the correct rules', ' Extra rules: upd_me' ); SELECT * FROM check_test( rules_are( 'fou', ARRAY['ins_me', 'upd_me', 'del_me'] ), false, 'rules_are(table, rules) + missing', 'Relation fou should have the correct rules', ' Missing rules: del_me' ); SELECT * FROM check_test( rules_are( 'fou', ARRAY['ins_me', 'del_me'] ), false, 'rules_are(table, rules) + extra & missing', 'Relation fou should have the correct rules', ' Extra rules: upd_me Missing rules: del_me' ); /****************************************************************************/ -- Test types_are(). SELECT * FROM check_test( types_are( 'someschema', ARRAY['sometype', 'myType'], 'whatever' ), true, 'types_are(schema, types, desc)', 'whatever', '' ); SELECT * FROM check_test( types_are( 'someschema', ARRAY['sometype', 'myType'] ), true, 'types_are(schema, types)', 'Schema someschema should have the correct types' '' ); SELECT * FROM check_test( types_are( 'someschema', ARRAY['sometype', 'myType', 'typo'], 'whatever' ), false, 'types_are(schema, types, desc) + missing', 'whatever', ' Missing types: typo' ); SELECT * FROM check_test( types_are( 'someschema', ARRAY['myType'], 'whatever' ), false, 'types_are(schema, types, desc) + extra', 'whatever', ' Extra types: sometype' ); SELECT * FROM check_test( types_are( 'someschema', ARRAY['typo', 'myType'], 'whatever' ), false, 'types_are(schema, types, desc) + extra & missing', 'whatever', ' Extra types: sometype Missing types: typo' ); CREATE FUNCTION ___mytype(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname NOT IN('pg_catalog', 'information_schema') AND t.typname <> $1 AND pg_catalog.pg_type_is_visible(t.oid) ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( types_are( ___mytype('') ), true, 'types_are(types)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct types', '' ); SELECT * FROM check_test( types_are( array_append(___mytype(''), 'silltypo'), 'whatever' ), false, 'types_are(types, desc) + missing', 'whatever', ' Missing types: silltypo' ); SELECT * FROM check_test( types_are( ___mytype('goofy'), 'whatever' ), false, 'types_are(types, desc) + extra', 'whatever', ' Extra types: goofy' ); SELECT * FROM check_test( types_are( array_append(___mytype('goofy'), 'silltypo'), 'whatever' ), false, 'types_are(types, desc) + extra & missing', 'whatever', ' Extra types: goofy Missing types: silltypo' ); /****************************************************************************/ -- Test domains_are(). SELECT * FROM check_test( domains_are( 'public', ARRAY['goofy', 'myDomain'], 'whatever' ), true, 'domains_are(schema, domains, desc)', 'whatever', '' ); SELECT * FROM check_test( domains_are( 'public', ARRAY['goofy', 'myDomain'] ), true, 'domains_are(schema, domains)', 'Schema public should have the correct domains', '' ); SELECT * FROM check_test( domains_are( 'public', ARRAY['freddy', 'myDomain'], 'whatever' ), false, 'domains_are(schema, domains, desc) fail', 'whatever', ' Extra types: goofy Missing types: freddy' ); SELECT * FROM check_test( domains_are( 'public', ARRAY['freddy', 'myDomain'] ), false, 'domains_are(schema, domains) fail', 'Schema public should have the correct domains', ' Extra types: goofy Missing types: freddy' ); CREATE FUNCTION ___mydo(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem) AND n.nspname NOT IN('pg_catalog', 'information_schema') AND t.typname <> $1 AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = 'd' ), '{}'::name[]); $$ LANGUAGE SQL; SELECT * FROM check_test( domains_are( ___mydo(''), 'whatever' ), true, 'domains_are(domains, desc)', 'whatever', '' ); SELECT * FROM check_test( domains_are( ___mydo('') ), true, 'domains_are(domains)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct domains', '' ); SELECT * FROM check_test( domains_are( array_append(___mydo('goofy'), 'fredy'), 'whatever' ), false, 'domains_are(domains, desc) fail', 'whatever', ' Extra types: goofy Missing types: fredy' ); SELECT * FROM check_test( domains_are( array_append(___mydo('goofy'), 'fredy') ), false, 'domains_are(domains) fail', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct domains', ' Extra types: goofy Missing types: fredy' ); /****************************************************************************/ -- Test casts_are(). CREATE OR REPLACE FUNCTION ___mycasts(ex text) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT pg_catalog.format_type(castsource, NULL) || ' AS ' || pg_catalog.format_type(casttarget, NULL) FROM pg_catalog.pg_cast WHERE castsource::regtype::text <> $1 ); $$ LANGUAGE SQL; SELECT * FROM check_test( casts_are( ___mycasts(''), 'whatever' ), true, 'casts_are(casts, desc)', 'whatever', '' ); SELECT * FROM check_test( casts_are( ___mycasts('') ), true, 'casts_are(casts)', 'There should be the correct casts', '' ); SELECT * FROM check_test( casts_are( array_append(___mycasts(''), '__booya__ AS integer'), 'whatever' ), false, 'casts_are(casts, desc) missing', 'whatever', ' Missing casts: __booya__ AS integer' ); SELECT * FROM check_test( casts_are( ___mycasts('lseg'), 'whatever' ), false, 'casts_are(casts, desc) extra', 'whatever', ' Extra casts: lseg AS point' ); SELECT * FROM check_test( casts_are( array_append(___mycasts('lseg'), '__booya__ AS integer'), 'whatever' ), false, 'casts_are(casts, desc) extras and missing', 'whatever', ' Extra casts: lseg AS point Missing casts: __booya__ AS integer' ); /****************************************************************************/ -- Test operators_are(). --SET search_path = disney,public,pg_catalog; SELECT * FROM check_test( operators_are( 'disney', ARRAY['=(goofy,goofy) RETURNS boolean'], 'whatever' ), true, 'operators_are(schema, operators, desc)', 'whatever', '' ); SELECT * FROM check_test( operators_are( 'disney', ARRAY['=(goofy,goofy) RETURNS boolean'] ), true, 'operators_are(schema, operators)', 'Schema disney should have the correct operators', '' ); SELECT * FROM check_test( operators_are( 'disney', ARRAY['+(freddy,freddy) RETURNS barnie'], 'whatever' ), false, 'operators_are(schema, operators, desc) fail', 'whatever', ' Extra operators: =(goofy,goofy) RETURNS boolean Missing operators: +(freddy,freddy) RETURNS barnie' ); SELECT * FROM check_test( operators_are( 'disney', ARRAY['+(freddy,freddy) RETURNS barnie'] ), false, 'operators_are(schema, operators) fail', 'Schema disney should have the correct operators', ' Extra operators: =(goofy,goofy) RETURNS boolean Missing operators: +(freddy,freddy) RETURNS barnie' ); CREATE OR REPLACE FUNCTION ___myops(ex text) RETURNS TEXT[] AS $$ SELECT ARRAY( SELECT textin(regoperatorout(o.oid::regoperator)) || ' RETURNS ' || o.oprresult::regtype::text FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON o.oprnamespace = n.oid WHERE pg_catalog.pg_operator_is_visible(o.oid) AND o.oprleft::regtype::text <> $1 AND n.nspname NOT IN ('pg_catalog', 'information_schema') ); $$ LANGUAGE SQL; SELECT * FROM check_test( operators_are( array_append( ___myops(''), '=(goofy,goofy) RETURNS boolean' ), 'whatever' ), true, 'operators_are(operators, desc)', 'whatever', '' ); SELECT * FROM check_test( operators_are( array_append( ___myops(''), '=(goofy,goofy) RETURNS boolean' ) ), true, 'operators_are(operators)', 'There should be the correct operators', '' ); SELECT * FROM check_test( operators_are( array_append( ___myops('goofy'), '+(freddy,freddy) RETURNS barnie' ), 'whatever' ), false, 'operators_are(operators, desc) fail', 'whatever', ' Extra operators: =(goofy,goofy) RETURNS boolean Missing operators: +(freddy,freddy) RETURNS barnie' ); SELECT * FROM check_test( operators_are( array_append( ___myops('goofy'), '+(freddy,freddy) RETURNS barnie' ) ), false, 'operators_are(operators) fail', 'There should be the correct operators', ' Extra operators: =(goofy,goofy) RETURNS boolean Missing operators: +(freddy,freddy) RETURNS barnie' ); /****************************************************************************/ -- Test columns_are(). SELECT * FROM check_test( columns_are( 'public', 'fou', ARRAY['id', 'name', 'numb', 'myInt'], 'whatever' ), true, 'columns_are(schema, table, columns, desc)', 'whatever', '' ); SELECT * FROM check_test( columns_are( 'public', 'fou', ARRAY['id', 'name', 'numb', 'myInt'] ), true, 'columns_are(schema, table, columns)', 'Table public.fou should have the correct columns', '' ); SELECT * FROM check_test( columns_are( 'public', 'fou', ARRAY['id', 'name', 'numb'] ), false, 'columns_are(schema, table, columns) + extra', 'Table public.fou should have the correct columns', ' Extra columns: "myInt"' ); SELECT * FROM check_test( columns_are( 'public', 'fou', ARRAY['id', 'name', 'numb', 'myInt', 'howdy'] ), false, 'columns_are(schema, table, columns) + missing', 'Table public.fou should have the correct columns', ' Missing columns: howdy' ); SELECT * FROM check_test( columns_are( 'public', 'fou', ARRAY['id', 'name', 'numb', 'howdy'] ), false, 'columns_are(schema, table, columns) + extra & missing', 'Table public.fou should have the correct columns', ' Extra columns: "myInt" Missing columns: howdy' ); SELECT * FROM check_test( columns_are( 'fou', ARRAY['id', 'name', 'numb', 'myInt'], 'whatever' ), true, 'columns_are(table, columns, desc)', 'whatever', '' ); SELECT * FROM check_test( columns_are( 'fou', ARRAY['id', 'name', 'numb', 'myInt'] ), true, 'columns_are(table, columns)', 'Table fou should have the correct columns', '' ); SELECT * FROM check_test( columns_are( 'fou', ARRAY['id', 'name', 'numb'] ), false, 'columns_are(table, columns) + extra', 'Table fou should have the correct columns', ' Extra columns: "myInt"' ); SELECT * FROM check_test( columns_are( 'fou', ARRAY['id', 'name', 'numb', 'myInt', 'howdy'] ), false, 'columns_are(table, columns) + missing', 'Table fou should have the correct columns', ' Missing columns: howdy' ); SELECT * FROM check_test( columns_are( 'fou', ARRAY['id', 'name', 'numb', 'howdy'] ), false, 'columns_are(table, columns) + extra & missing', 'Table fou should have the correct columns', ' Extra columns: "myInt" Missing columns: howdy' ); /****************************************************************************/ -- Test materialized_views_are(). CREATE FUNCTION test_materialized_views_are() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 90300 THEN EXECUTE $E$ CREATE MATERIALIZED VIEW public.moo AS SELECT * FROM foo; CREATE MATERIALIZED VIEW public.mou AS SELECT * FROM fou; $E$; FOR tap IN SELECT * FROM check_test( materialized_views_are( 'public', ARRAY['mou', 'moo'], 'whatever' ), true, 'materialized_views_are(schema, materialized_views, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( 'public', ARRAY['mou', 'moo'] ), true, 'materialized_views_are(schema, materialized_views)', 'Schema public should have the correct materialized views', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( ARRAY['mou', 'moo'] ), true, 'materialized_views_are(views)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( ARRAY['mou', 'moo'], 'whatever' ), true, 'materialized_views_are(views, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( 'public', ARRAY['mou', 'moo', 'bar'] ), false, 'materialized_views_are(schema, materialized_views) missing', 'Schema public should have the correct materialized views', ' Missing Materialized views: bar' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( ARRAY['mou', 'moo', 'bar'] ), false, 'materialized_views_are(materialized_views) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views', ' Missing Materialized views: bar' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( 'public', ARRAY['mou'] ), false, 'materialized_views_are(schema, materialized_views) extra', 'Schema public should have the correct materialized views', ' Extra Materialized views: moo' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( ARRAY['mou'] ), false, 'materialized_views_are(materialized_views) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views', ' Extra Materialized views: moo' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( 'public', ARRAY['bar', 'baz'] ), false, 'materialized_views_are(schema, materialized_views) extra and missing', 'Schema public should have the correct materialized views', ' Extra Materialized views: mo[ou] mo[ou] Missing Materialized views: ba[rz] ba[rz]', true ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_views_are( ARRAY['bar', 'baz'] ), false, 'materialized_views_are(materialized_views) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct materialized views', ' Extra Materialized views:' || ' mo[ou] mo[ou] Missing Materialized views:' || ' ba[rz] ba[rz]', true ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with views_are FOR tap IN SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo'], 'whatever' ), true, 'materialized_views_are(schema, materialized_views, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo'] ), true, 'materialized_views_are(schema, materialized_views)', 'Schema public should have the correct views', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( ARRAY['vou', 'voo'] ), true, 'materialized_views_are(views)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( ARRAY['vou', 'voo'], 'whatever' ), true, 'materialized_views_are(views, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( 'public', ARRAY['vou', 'voo', 'bar'] ), false, 'materialized_views_are(schema, materialized_views) missing', 'Schema public should have the correct views', ' Missing views: bar' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( ARRAY['vou', 'voo', 'bar'] ), false, 'materialized_views_are(materialized_views) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Missing views: bar' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( 'public', ARRAY['vou'] ), false, 'materialized_views_are(schema, materialized_views) extra', 'Schema public should have the correct views', ' Extra views: voo' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( ARRAY['vou'] ), false, 'materialized_views_are(materialized_views) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Extra views: voo' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( 'public', ARRAY['bar', 'baz'] ), false, 'materialized_views_are(schema, materialized_views) extra and missing', 'Schema public should have the correct views', ' Extra views: vo[ou] vo[ou] Missing views: ba[rz] ba[rz]', true ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( views_are( ARRAY['bar', 'baz'] ), false, 'materialized_views_are(materialized_views) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct views', ' Extra views:' || ' vo[ou] vo[ou] Missing views:' || ' ba[rz] ba[rz]', true ) AS b LOOP RETURN NEXT tap.b; END LOOP; end IF; RETURN; END; $$LANGUAGE PLPGSQL; SELECT * FROM test_materialized_views_are(); /****************************************************************************/ -- tests for foreign_tables_are functions CREATE FUNCTION test_foreign_tables_are() RETURNS SETOF TEXT AS $$ DECLARE tap record; i int; BEGIN IF pg_version_num() >= 90100 THEN -- setup tables for tests EXECUTE $setup$ CREATE FOREIGN DATA WRAPPER null_fdw; CREATE SERVER server_null_fdw FOREIGN DATA WRAPPER null_fdw; CREATE FOREIGN TABLE public.ft_foo( id INT , "name" TEXT , num NUMERIC(10, 2), "myInt" int ) SERVER server_null_fdw ; CREATE FOREIGN TABLE public.ft_bar( id INT ) SERVER server_null_fdw ; $setup$; -- foreign_tables_are( schema, tables, description ) -- CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[], TEXT ) FOR tap IN SELECT * FROM check_test( foreign_tables_are( 'public', ARRAY['ft_foo', 'ft_bar'], 'Correct foreign tables in named schema with custom message' ), true, 'foreign_tables_are(schema, tables, desc)', 'Correct foreign tables in named schema with custom message', '' ) AS r LOOP RETURN NEXT tap.r; END LOOP; -- foreign_tables_are( tables, description ) --CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[], TEXT ) FOR tap IN SELECT * FROM check_test( foreign_tables_are( ARRAY['ft_foo', 'ft_bar'], 'Correct foreign tables in search_path with custom message' ), true, 'foreign_tables_are(tables, desc)', 'Correct foreign tables in search_path with custom message', '' ) AS r LOOP RETURN NEXT tap.r; END LOOP; -- foreign_tables_are( schema, tables ) -- CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME, NAME[] ) FOR tap IN SELECT * FROM check_test( foreign_tables_are( 'public', ARRAY['ft_foo', 'ft_bar'] ), true, 'foreign_tables_are(schema, tables)', 'Schema public should have the correct foreign tables', '' ) AS r LOOP RETURN NEXT tap.r; END LOOP; -- foreign_tables_are( tables ) -- +CREATE OR REPLACE FUNCTION foreign_tables_are ( NAME[] ) FOR tap IN SELECT * FROM check_test( foreign_tables_are( ARRAY['ft_foo', 'ft_bar'] ), true, 'foreign_tables_are(tables)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables', '' ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( 'public', ARRAY['ft_foo', 'ft_bar', 'bar'] ), false, 'foreign_tables_are(schema, tables) missing', 'Schema public should have the correct foreign tables', ' Missing foreign tables: bar' ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( ARRAY['ft_foo', 'ft_bar', 'bar'] ), false, 'foreign_tables_are(tables) missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables', ' Missing foreign tables: bar' ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( 'public', ARRAY['ft_foo'] ), false, 'foreign_tables_are(schema, tables) extra', 'Schema public should have the correct foreign tables', ' Extra foreign tables: ft_bar' ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( ARRAY['ft_foo'] ), false, 'foreign_tables_are(tables) extra', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables', ' Extra foreign tables: ft_bar' ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( 'public', ARRAY['bar', 'baz'] ), false, 'foreign_tables_are(schema, tables) extra and missing', 'Schema public should have the correct foreign tables', ' Extra foreign tables: ft_(?:bar|foo) ft_(?:foo|bar) Missing foreign tables: ba[rz] ba[rz]', true ) AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_tables_are( ARRAY['bar', 'baz'] ), false, 'foreign_tables_are(tables) extra and missing', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct foreign tables', ' Extra foreign tables:' || ' ft_[fobar]+ ft_[fobar]+ Missing foreign tables:' || ' ba[rz] ba[rz]', true ) AS r LOOP RETURN NEXT tap.r; END LOOP; else -- 10 fake pass/fail tests to make test work in older postgres. FOR tap IN SELECT * FROM check_test(pass('pass'), true, 'foreign_tables_are(schema, tables, desc)' , 'pass', '') AS r LOOP return next tap.r; end loop; FOR tap IN SELECT * FROM check_test(pass('pass'), true, 'foreign_tables_are(tables, desc)' , 'pass', '') AS r LOOP return next tap.r; end loop; FOR tap IN SELECT * FROM check_test(pass('pass'), true, 'foreign_tables_are(schema, tables)' ,'pass' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(pass('pass'), true, 'foreign_tables_are(tables)' ,'pass' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(schema, tables) missing' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(tables) missing' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(schema, tables) extra' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(tables) extra' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(schema, tables) extra and missing' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; FOR tap IN SELECT * FROM check_test(fail('fail'), false, 'foreign_tables_are(tables) extra and missing' ,'fail' ,'') AS r LOOP RETURN NEXT tap.r; END LOOP; end if; RETURN; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_foreign_tables_are(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/check.sql000066400000000000000000000107471455775703000162320ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(48); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '' CHECK ( name IN ('foo', 'bar', 'baz') ), numb NUMERIC(10, 2), myint NUMERIC(8), CHECK (numb > 1.0 AND myint < 10) ); RESET client_min_messages; /****************************************************************************/ -- Test has_check(). SELECT * FROM check_test( has_check( 'public', 'sometab', 'public.sometab should have a check constraint' ), true, 'has_check( schema, table, desc )', 'public.sometab should have a check constraint', '' ); SELECT * FROM check_test( has_check( 'sometab', 'sometab should have a check constraint' ), true, 'has_check( table, desc )', 'sometab should have a check constraint', '' ); SELECT * FROM check_test( has_check( 'sometab' ), true, 'has_check( table )', 'Table sometab should have a check constraint', '' ); SELECT * FROM check_test( has_check( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should have a check constraint' ), false, 'has_check( schema, table, descr ) fail', 'pg_catalog.pg_class should have a check constraint', '' ); SELECT * FROM check_test( has_check( 'pg_class', 'pg_class should have a check constraint' ), false, 'has_check( table, desc ) fail', 'pg_class should have a check constraint', '' ); /****************************************************************************/ -- Test col_has_check(). SELECT * FROM check_test( col_has_check( 'public', 'sometab', 'name', 'public.sometab.name should have a check' ), true, 'col_has_check( sch, tab, col, desc )', 'public.sometab.name should have a check', '' ); SELECT * FROM check_test( col_has_check( 'public', 'sometab', ARRAY['numb', 'myint'], 'public.sometab.numb+myint should have a check' ), true, 'col_has_check( sch, tab, cols, desc )', 'public.sometab.numb+myint should have a check', '' ); SELECT * FROM check_test( col_has_check( 'sometab', 'name', 'sometab.name should have a check' ), true, 'col_has_check( tab, col, desc )', 'sometab.name should have a check', '' ); SELECT * FROM check_test( col_has_check( 'sometab', ARRAY['numb', 'myint'], 'sometab.numb+myint should have a check' ), true, 'col_has_check( tab, cols, desc )', 'sometab.numb+myint should have a check', '' ); SELECT * FROM check_test( col_has_check( 'sometab', 'name' ), true, 'col_has_check( table, column )', 'Column sometab(name) should have a check constraint', '' ); SELECT * FROM check_test( col_has_check( 'sometab', ARRAY['numb', 'myint'] ), true, 'col_has_check( table, columns )', 'Columns sometab(numb, myint) should have a check constraint', '' ); SELECT * FROM check_test( col_has_check( 'public', 'sometab', 'id', 'public.sometab.id should have a check' ), false, 'col_has_check( sch, tab, col, desc ) fail', 'public.sometab.id should have a check', ' have: {name} {numb,myint} want: {id}' ); SELECT * FROM check_test( col_has_check( 'sometab', 'id', 'sometab.id should have a check' ), false, 'col_has_check( tab, col, desc ) fail', 'sometab.id should have a check', ' have: {name} {numb,myint} want: {id}' ); /****************************************************************************/ -- Test col_has_check() with an array of columns. SET LOCAL client_min_messages = warning; CREATE TABLE public.argh ( id INT NOT NULL, name TEXT NOT NULL, CHECK ( id IN (1, 2) AND name IN ('foo', 'bar')) ); RESET client_min_messages; SELECT * FROM check_test( col_has_check( 'public', 'argh', ARRAY['id', 'name'], 'id + name should have a check' ), true, 'col_has_check( sch, tab, col[], desc )', 'id + name should have a check', '' ); SELECT * FROM check_test( col_has_check( 'argh', ARRAY['id', 'name'], 'id + name should have a check' ), true, 'col_has_check( tab, col[], desc )', 'id + name should have a check', '' ); SELECT * FROM check_test( col_has_check( 'argh', ARRAY['id', 'name'] ), true, 'col_has_check( tab, col[] )', 'Columns argh(id, name) should have a check constraint', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/cmpok.sql000066400000000000000000000045311455775703000162600ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(38); /****************************************************************************/ -- Test cmp_ok(). SELECT * FROM check_test( cmp_ok( 1, '=', 1, '1 should = 1' ), true, 'cmp_ok( int, =, int )', '1 should = 1', '' ); SELECT * FROM check_test( cmp_ok( 1, '<>', 2, '1 should <> 2' ), true, 'cmp_ok( int, <>, int )', '1 should <> 2', '' ); SELECT * FROM check_test( cmp_ok( '((0,0),(1,1))'::polygon, '~=', '((1,1),(0,0))'::polygon ), true, 'cmp_ok( polygon, ~=, polygon )' '', '' ); SELECT * FROM check_test( cmp_ok( ARRAY[1, 2], '=', ARRAY[1, 2]), true, 'cmp_ok( int[], =, int[] )', '', '' ); SELECT * FROM check_test( cmp_ok( ARRAY['192.168.1.2'::inet], '=', ARRAY['192.168.1.2'::inet] ), true, 'cmp_ok( inet[], =, inet[] )', '', '' ); SELECT * FROM check_test( cmp_ok( 1, '=', 2, '1 should = 2' ), false, 'cmp_ok() fail', '1 should = 2', ' ''1'' = ''2''' ); SELECT * FROM check_test( cmp_ok( 1, '=', NULL, '1 should = NULL' ), false, 'cmp_ok() NULL fail', '1 should = NULL', ' ''1'' = NULL' ); /****************************************************************************/ -- Test isa_ok(). SELECT * FROM check_test( isa_ok( ''::text, 'text', 'an empty string' ), true, 'isa_ok("", text, desc)', 'an empty string isa text', '' ); SELECT * FROM check_test( isa_ok( ''::text, 'text', 'an empty string' ), true, 'isa_ok("", text, desc)', 'an empty string isa text', '' ); SELECT * FROM check_test( isa_ok( false, 'bool' ), true, 'isa_ok(false, boolean)', 'the value isa boolean', '' ); SELECT * FROM check_test( isa_ok( NULL::boolean, 'bool' ), true, 'isa_ok(NULL, boolean)', 'the value isa boolean', '' ); SELECT * FROM check_test( isa_ok( ARRAY[false], 'bool[]' ), true, 'isa_ok(ARRAY, boolean[])', 'the value isa boolean[]', '' ); SELECT * FROM check_test( isa_ok( true, 'int[]' ), false, 'isa_ok(bool, int[])', 'the value isa integer[]', ' the value isn''t a "integer[]" it''s a "boolean"' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/coltap.sql000066400000000000000000000513501455775703000164320ustar00rootroot00000000000000\unset ECHO \i test/setup.sql -- \i sql/pgtap.sql SELECT plan(276); -- SELECT * from no_plan(); CREATE TYPE public."myType" AS ( id INT, foo INT ); CREATE SCHEMA hidden; CREATE TYPE hidden.stuff AS ( id INT, foo INT ); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2) DEFAULT NULL, "myNum" NUMERIC(8) DEFAULT 24, myat TIMESTAMP DEFAULT NOW(), cuser TEXT DEFAULT CURRENT_USER, suser TEXT DEFAULT SESSION_USER, auser TEXT DEFAULT USER, crole TEXT DEFAULT CURRENT_ROLE, csch TEXT DEFAULT CURRENT_SCHEMA, ccat TEXT DEFAULT CURRENT_CATALOG, cdate DATE DEFAULT CURRENT_DATE, ctime TIMETZ DEFAULT CURRENT_TIME, ctstz TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, ltime TIME DEFAULT LOCALTIME, ltstz TIMESTAMPTZ DEFAULT LOCALTIMESTAMP, plain INTEGER, camel "myType", inval INTERVAL(0), isecd INTERVAL SECOND(0), iyear INTERVAL YEAR, stuff hidden.stuff ); CREATE OR REPLACE FUNCTION fakeout( eok boolean, name text ) RETURNS SETOF TEXT AS $$ DECLARE descr text := coalesce( name || ' ', 'Test ' ) || 'should '; BEGIN RETURN NEXT pass(descr || CASE eok WHEN true then 'pass' ELSE 'fail' END); RETURN NEXT pass(descr || 'have the proper description'); RETURN NEXT pass(descr || 'have the proper diagnostics'); RETURN; END; $$ LANGUAGE PLPGSQL; RESET client_min_messages; /****************************************************************************/ -- Test col_not_null(). SELECT * FROM check_test( col_not_null( 'pg_catalog', 'pg_type', 'typname', 'typname not null' ), true, 'col_not_null( sch, tab, col, desc )', 'typname not null', '' ); SELECT * FROM check_test( col_not_null( 'pg_catalog', 'pg_type', 'typname'::name ), true, 'col_not_null( sch, tab, col::name )', 'Column pg_catalog.pg_type.typname should be NOT NULL', '' ); SELECT * FROM check_test( col_not_null( 'sometab', 'id', 'blah blah blah' ), true, 'col_not_null( tab, col, desc )', 'blah blah blah', '' ); SELECT * FROM check_test( col_not_null( 'sometab', 'id' ), true, 'col_not_null( table, column )', 'Column sometab.id should be NOT NULL', '' ); -- Make sure failure is correct. SELECT * FROM check_test( col_not_null( 'sometab', 'name' ), false, 'col_not_null( table, column ) fail', 'Column sometab.name should be NOT NULL', '' ); -- Make sure nonexisting column is correct SELECT * FROM check_test( col_not_null( 'pg_catalog', 'pg_type', 'foo', 'desc' ), false, 'col_not_null( sch, tab, noncol, desc )', 'desc', ' Column pg_catalog.pg_type.foo does not exist' ); SELECT * FROM check_test( col_not_null( 'sometab', 'foo' ), false, 'col_not_null( table, noncolumn ) fail', 'Column sometab.foo should be NOT NULL', ' Column sometab.foo does not exist' ); /****************************************************************************/ -- Test col_is_null(). SELECT * FROM check_test( col_is_null( 'public', 'sometab', 'name', 'name is null' ), true, 'col_is_null( sch, tab, col, desc )', 'name is null', '' ); SELECT * FROM check_test( col_is_null( 'public', 'sometab', 'name'::name ), true, 'col_is_null( sch, tab, col::name )', 'Column public.sometab.name should allow NULL', '' ); SELECT * FROM check_test( col_is_null( 'sometab', 'name', 'my desc' ), true, 'col_is_null( tab, col, desc )', 'my desc', '' ); SELECT * FROM check_test( col_is_null( 'sometab', 'name' ), true, 'col_is_null( tab, col )', 'Column sometab.name should allow NULL', '' ); -- Make sure failure is correct. SELECT * FROM check_test( col_is_null( 'sometab', 'id' ), false, 'col_is_null( tab, col ) fail', 'Column sometab.id should allow NULL', '' ); -- Make sure nonexisting column is correct SELECT * FROM check_test( col_is_null( 'pg_catalog', 'pg_type', 'foo', 'desc' ), false, 'col_is_null( sch, tab, noncol, desc )', 'desc', ' Column pg_catalog.pg_type.foo does not exist' ); SELECT * FROM check_test( col_is_null( 'sometab', 'foo' ), false, 'col_is_null( table, noncolumn ) fail', 'Column sometab.foo should allow NULL', ' Column sometab.foo does not exist' ); /****************************************************************************/ -- Test col_type_is(). SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'ctstz', 'pg_catalog', 'timestamptz', 'ctstz is tstz' ), true, 'col_type_is( sch, tab, col, sch, type, desc )', 'ctstz is tstz', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'ctstz', 'pg_catalog'::name, 'timestamptz' ), true, 'col_type_is( sch, tab, col, sch, type, desc )', 'Column public.sometab.ctstz should be type pg_catalog.timestamptz', '' ); -- Try case-sensitive column name. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'myNum', 'pg_catalog', 'numeric(8,0)', 'myNum is numeric' ), true, 'col_type_is( sch, tab, myNum, sch, type, desc )', 'myNum is numeric', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'myNum', 'pg_catalog'::name, 'numeric(8,0)' ), true, 'col_type_is( sch, tab, myNum, sch, type, desc )', 'Column public.sometab."myNum" should be type pg_catalog.numeric(8,0)', '' ); -- Try case-sensitive type name. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'camel', 'public', '"myType"', 'camel is myType' ), true, 'col_type_is( sch, tab, camel, sch, type, desc )', 'camel is myType', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'camel', 'public'::name, '"myType"' ), true, 'col_type_is( sch, tab, camel, sch, type )', 'Column public.sometab.camel should be type public."myType"', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'camel', '"myType"', 'whatever' ), true, 'col_type_is( sch, tab, camel, type, desc )', 'whatever', '' ); -- Try interval. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'inval', 'pg_catalog', 'interval(0)', 'inval is interval(0)' ), true, 'col_type_is( sch, tab, interval, sch, type, desc )', 'inval is interval(0)', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'inval', 'pg_catalog'::name, 'interval(0)' ), true, 'col_type_is( sch, tab, interval, sch, type, desc )', 'Column public.sometab.inval should be type pg_catalog.interval(0)', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'inval', 'interval(0)', 'whatever' ), true, 'col_type_is( sch, tab, inval, type, desc )', 'whatever', '' ); -- Try interval second. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'isecd', 'pg_catalog', 'interval second(0)', 'isecd is interval second(0)' ), true, 'col_type_is( sch, tab, intsec, sch, type, desc )', 'isecd is interval second(0)', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'inval', 'pg_catalog'::name, 'interval(0)' ), true, 'col_type_is( sch, tab, interval, sch, type, desc )', 'Column public.sometab.inval should be type pg_catalog.interval(0)', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'inval', 'interval(0)', 'whatever' ), true, 'col_type_is( sch, tab, inval, type, desc )', 'whatever', '' ); -- Try type not in search path. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'stuff', 'hidden', 'stuff', 'stuff is stuff' ), true, 'col_type_is( sch, tab, stuff, sch, type, desc )', 'stuff is stuff', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'stuff', 'hidden'::name, 'stuff' ), true, 'col_type_is( sch, tab, stuff, sch, type, desc )', 'Column public.sometab.stuff should be type hidden.stuff', '' ); -- Try failures. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'pg_catalog', 'int', 'whatever' ), false, 'col_type_is( sch, tab, col, sch, type, desc ) fail', 'whatever', ' have: pg_catalog.text want: pg_catalog.integer' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'pg_catalog', 'blech', 'whatever' ), false, 'col_type_is( sch, tab, col, sch, non-type, desc )', 'whatever', ' Type pg_catalog.blech does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'fooey', 'text', 'whatever' ), false, 'col_type_is( sch, tab, col, non-sch, type, desc )', 'whatever', ' Type fooey.text does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'fooey', 'text', 'whatever' ), false, 'col_type_is( sch, tab, col, non-sch, type, desc )', 'whatever', ' Type fooey.text does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'nonesuch', 'whatever' ), false, 'col_type_is( sch, tab, col, non-type, desc )', 'whatever', ' Type nonesuch does not exist' ); SELECT * FROM check_test( col_type_is( 'sometab', 'name', 'nonesuch', 'whatever' ), false, 'col_type_is( tab, col, non-type, desc )', 'whatever', ' Type nonesuch does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'nonesuch', 'pg_catalog', 'text', 'whatever' ), false, 'col_type_is( sch, tab, non-col, sch, type, desc )', 'whatever', ' Column public.sometab.nonesuch does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name', 'text', 'name is text' ), true, 'col_type_is( sch, tab, col, type, desc )', 'name is text', '' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'name'::name, 'text' ), true, 'col_type_is( sch, tab, col, type )', 'Column public.sometab.name should be type text', '' ); SELECT * FROM check_test( col_type_is( 'sometab', 'name', 'text', 'yadda yadda yadda' ), true, 'col_type_is( tab, col, type, desc )', 'yadda yadda yadda', '' ); SELECT * FROM check_test( col_type_is( 'sometab', 'name', 'text' ), true, 'col_type_is( tab, col, type )', 'Column sometab.name should be type text', '' ); -- Make sure failure is correct. SELECT * FROM check_test( col_type_is( 'sometab', 'name', 'int4' ), false, 'col_type_is( tab, col, type ) fail', 'Column sometab.name should be type int4', ' have: text want: integer' ); -- Make sure missing column is in diagnostics. SELECT * FROM check_test( col_type_is( 'sometab', 'blah', 'int4' ), false, 'col_type_is( tab, noncol, type ) fail', 'Column sometab.blah should be type int4', ' Column sometab.blah does not exist' ); SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'blah', 'text', 'blah is text' ), false, 'col_type_is( sch, tab, noncol, type, desc ) fail', 'blah is text', ' Column public.sometab.blah does not exist' ); /****************************************************************************/ -- Try col_type_is() with precision. SELECT * FROM check_test( col_type_is( 'public', 'sometab', 'numb', 'numeric(10,2)', 'lol' ), true, 'col_type_is with precision', 'lol', '' ); -- Check its diagnostics. SELECT * FROM check_test( col_type_is( 'sometab', 'myNum', 'numeric(7)', 'should be numeric(7)' ), false, 'col_type_is precision fail', 'should be numeric(7)', ' have: numeric(8,0) want: numeric(7,0)' ); /****************************************************************************/ -- Test col_has_default(). SELECT * FROM check_test( col_has_default( 'public', 'sometab', 'name', 'desc' ), true, 'col_has_default( sch, tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_has_default( 'sometab', 'name', 'desc' ), true, 'col_has_default( tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_has_default( 'sometab', 'name' ), true, 'col_has_default( tab, col )', 'Column sometab.name should have a default', '' ); -- Check with a column with no default. SELECT * FROM check_test( col_has_default( 'public', 'sometab', 'plain', 'desc' ), false, 'col_has_default( sch, tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_has_default( 'sometab', 'plain', 'desc' ), false, 'col_has_default( tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_has_default( 'sometab', 'plain' ), false, 'col_has_default( tab, col )', 'Column sometab.plain should have a default', '' ); -- Check with a nonexistent column. SELECT * FROM check_test( col_has_default( 'public', 'sometab', '__asdfasdfs__', 'desc' ), false, 'col_has_default( sch, tab, col, desc )', 'desc', ' Column public.sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_has_default( 'sometab', '__asdfasdfs__', 'desc' ), false, 'col_has_default( tab, col, desc )', 'desc', ' Column sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_has_default( 'sometab', '__asdfasdfs__' ), false, 'col_has_default( tab, col )', 'Column sometab.__asdfasdfs__ should have a default', ' Column sometab.__asdfasdfs__ does not exist' ); /****************************************************************************/ -- Test col_hasnt_default(). SELECT * FROM check_test( col_hasnt_default( 'public', 'sometab', 'name', 'desc' ), false, 'col_hasnt_default( sch, tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', 'name', 'desc' ), false, 'col_hasnt_default( tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', 'name' ), false, 'col_hasnt_default( tab, col )', 'Column sometab.name should not have a default', '' ); -- Check with a column with no default. SELECT * FROM check_test( col_hasnt_default( 'public', 'sometab', 'plain', 'desc' ), true, 'col_hasnt_default( sch, tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', 'plain', 'desc' ), true, 'col_hasnt_default( tab, col, desc )', 'desc', '' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', 'plain' ), true, 'col_hasnt_default( tab, col )', 'Column sometab.plain should not have a default', '' ); -- Check with a nonexistent column. SELECT * FROM check_test( col_hasnt_default( 'public', 'sometab', '__asdfasdfs__', 'desc' ), false, 'col_hasnt_default( sch, tab, col, desc )', 'desc', ' Column public.sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', '__asdfasdfs__', 'desc' ), false, 'col_hasnt_default( tab, col, desc )', 'desc', ' Column sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_hasnt_default( 'sometab', '__asdfasdfs__' ), false, 'col_hasnt_default( tab, col )', 'Column sometab.__asdfasdfs__ should not have a default', ' Column sometab.__asdfasdfs__ does not exist' ); /****************************************************************************/ -- Test col_default_is(). SELECT * FROM check_test( col_default_is( 'public', 'sometab', 'name', ''::text, 'name should default to empty string' ), true, 'col_default_is( sch, tab, col, def, desc )', 'name should default to empty string', '' ); SELECT * FROM check_test( col_default_is( 'public', 'sometab', 'name', 'foo'::text, 'name should default to ''foo''' ), false, 'col_default_is() fail', 'name should default to ''foo''', ' have: want: foo' ); SELECT * FROM check_test( col_default_is( 'sometab', 'name', ''::text, 'name should default to empty string' ), true, 'col_default_is( tab, col, def, desc )', 'name should default to empty string', '' ); SELECT * FROM check_test( col_default_is( 'sometab', 'name', ''::text ), true, 'col_default_is( tab, col, def )', 'Column sometab.name should default to ''''', '' ); -- Make sure it works with a NULL default. SELECT * FROM check_test( col_default_is( 'sometab', 'myNum', 24 ), true, 'col_default_is( tab, col, int )', 'Column sometab."myNum" should default to ''24''', '' ); -- We can handle DEFAULT NULL correctly. SELECT * FROM check_test( col_default_is( 'sometab', 'numb', NULL::numeric, 'desc' ), true, 'col_default_is( tab, col, NULL, desc )', 'desc', '' ); SELECT * FROM check_test( col_default_is( 'sometab', 'numb', NULL::numeric ), true, 'col_default_is( tab, col, NULL )', 'Column sometab.numb should default to NULL', '' ); -- Make sure that it fails when there is no default. SELECT * FROM check_test( col_default_is( 'sometab', 'plain', 1, 'desc' ), false, 'col_default_is( tab, col, bogus, desc )', 'desc', ' Column sometab.plain has no default' ); SELECT * FROM check_test( col_default_is( 'sometab', 'plain', 1 ), false, 'col_default_is( tab, col, bogus )', 'Column sometab.plain should default to ''1''', ' Column sometab.plain has no default' ); -- Make sure that it works when the default is an expression. SELECT * FROM check_test( col_default_is( 'sometab', 'myat', 'now()' ), true, 'col_default_is( tab, col, expression )', 'Column sometab.myat should default to ''now()''', '' ); SELECT * FROM check_test( col_default_is( 'sometab', 'myat', 'now()'::text ), true, 'col_default_is( tab, col, expression::text )', 'Column sometab.myat should default to ''now()''', '' ); SELECT * FROM check_test( col_default_is( 'sometab', 'myat', 'now()', 'desc' ), true, 'col_default_is( tab, col, expression, desc )', 'desc', '' ); SELECT * FROM check_test( col_default_is( 'sometab', 'myat', 'now()', 'desc'::text ), true, 'col_default_is( tab, col, expression, desc )', 'desc', '' ); SELECT * FROM check_test( col_default_is( 'public', 'sometab', 'myat', 'now()', 'desc' ), true, 'col_default_is( schema, tab, col, expression, desc )', 'desc', '' ); SELECT * FROM check_test( col_default_is( 'public', 'sometab', 'myat', 'now()', 'desc'::text ), true, 'col_default_is( schema, tab, col, expression, desc )', 'desc', '' ); -- Check with a nonexistent column. SELECT * FROM check_test( col_default_is( 'public', 'sometab', '__asdfasdfs__', NULL::text, 'desc' ), false, 'col_default_is( sch, tab, col, def, desc )', 'desc', ' Column public.sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_default_is( 'sometab', '__asdfasdfs__', NULL::text, 'desc' ), false, 'col_default_is( tab, col, def, desc )', 'desc', ' Column sometab.__asdfasdfs__ does not exist' ); SELECT * FROM check_test( col_default_is( 'sometab', '__asdfasdfs__', NULL::text ), false, 'col_default_is( tab, col, def )', 'Column sometab.__asdfasdfs__ should default to NULL', ' Column sometab.__asdfasdfs__ does not exist' ); -- Make sure that it works when the default is a reserved SQL expression. CREATE OR REPLACE FUNCTION ckreserve() RETURNS SETOF TEXT LANGUAGE PLPGSQL AS $$ DECLARE funcs text[] := '{CURRENT_CATALOG,CURRENT_ROLE,CURRENT_SCHEMA,CURRENT_USER,SESSION_USER,USER,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,LOCALTIME,LOCALTIMESTAMP}'; cols TEXT[] := '{ccat,crole,csch,cuser,suser,auser,cdate,ctime,ctstz,ltime,ltstz}'; exp TEXT[] := funcs; tap record; last_index INTEGER; BEGIN last_index := array_upper(funcs, 1); IF pg_version_num() < 100000 THEN -- Prior to PostgreSQL 10, these were functions rendered with paretheses or as casts. exp := ARRAY['current_database()','"current_user"()','"current_schema"()','"current_user"()','"session_user"()','"current_user"()','(''now''::text)::date','(''now''::text)::time with time zone','now()','(''now''::text)::time without time zone','(''now''::text)::timestamp without time zone']; END IF; FOR i IN 1..last_index LOOP FOR tap IN SELECT * FROM check_test( col_default_is( 'sometab', cols[i], exp[i], 'Test ' || funcs[i] ), true, 'col_default_is( tab, col, ' || funcs[i] || ' )', 'Test ' || funcs[i], '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END LOOP; END; $$; SELECT * FROM ckreserve(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/do_tap.sql000066400000000000000000000033531455775703000164160ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SET client_min_messages = notice; SELECT plan(29); --SELECT * FROM no_plan(); CREATE OR REPLACE FUNCTION public.testthis() RETURNS SETOF TEXT AS $$ SELECT pass('simple pass') AS foo UNION SELECT pass('another simple pass') ORDER BY foo ASC; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION public.testplpgsql() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); RETURN NEXT pass( 'plpgsql simple 2' ); RETURN; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION public."test ident"() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'ident' ); RETURN NEXT pass( 'ident 2' ); RETURN; END; $$ LANGUAGE plpgsql; SELECT is( findfuncs('public'::name, '^test', 'this'), ARRAY[ 'public."test ident"', 'public.testplpgsql'], 'findfuncs(public, ^test, this) should work' ); SELECT is( findfuncs('public'::name, '^test'), ARRAY[ 'public."test ident"', 'public.testplpgsql', 'public.testthis' ], 'findfuncs(public, ^test) should work' ); SELECT is( findfuncs('^test', 'this'), ARRAY[ 'public."test ident"', 'public.testplpgsql'], 'findfuncs(^test, this) should work' ); SELECT is( findfuncs('^test'), ARRAY[ 'public."test ident"', 'public.testplpgsql', 'public.testthis' ], 'findfuncs(^test) should work' ); SELECT is( findfuncs('foo'), CASE WHEN pg_version_num() < 80300 THEN NULL ELSE '{}'::text[] END, 'findfuncs(unknown) should find no tests' ); SELECT * FROM do_tap('public', '^test'); SELECT * FROM do_tap('public'::name); SELECT * FROM do_tap('^test'); SELECT * FROM do_tap(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/enumtap.sql000066400000000000000000000232221455775703000166160ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(108); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TYPE public.bug_status AS ENUM ('new', 'open', 'closed'); RESET client_min_messages; /****************************************************************************/ -- Make sure has_type for enums. SELECT * FROM check_test( has_type( 'bug_status' ), true, 'has_type(enum)', 'Type bug_status should exist', '' ); /****************************************************************************/ -- Test has_enum(). SELECT * FROM check_test( has_enum( 'bug_status' ), true, 'has_enum(enum)', 'Enum bug_status should exist', '' ); SELECT * FROM check_test( has_enum( 'bug_status', 'mydesc' ), true, 'has_enum(enum, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_enum( 'public'::name, 'bug_status'::name ), true, 'has_enum(scheam, enum)', 'Enum public.bug_status should exist', '' ); SELECT * FROM check_test( has_enum( 'public', 'bug_status', 'mydesc' ), true, 'has_enum(schema, enum, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( has_enum( '__foobarbaz__' ), false, 'has_enum(enum)', 'Enum __foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_enum( '__foobarbaz__', 'mydesc' ), false, 'has_enum(enum, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_enum( 'public'::name, '__foobarbaz__'::name ), false, 'has_enum(scheam, enum)', 'Enum public.__foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_enum( 'public', '__foobarbaz__', 'mydesc' ), false, 'has_enum(schema, enum, desc)', 'mydesc', '' ); /****************************************************************************/ -- Test hasnt_enum(). SELECT * FROM check_test( hasnt_enum( '__foobarbaz__' ), true, 'hasnt_enum(enum)', 'Enum __foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_enum( '__foobarbaz__', 'mydesc' ), true, 'hasnt_enum(enum, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_enum( 'public'::name, '__foobarbaz__'::name ), true, 'hasnt_enum(scheam, enum)', 'Enum public.__foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_enum( 'public', '__foobarbaz__', 'mydesc' ), true, 'hasnt_enum(schema, enum, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( hasnt_enum( 'bug_status' ), false, 'hasnt_enum(enum)', 'Enum bug_status should not exist', '' ); SELECT * FROM check_test( hasnt_enum( 'bug_status', 'mydesc' ), false, 'hasnt_enum(enum, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_enum( 'public'::name, 'bug_status'::name ), false, 'hasnt_enum(scheam, enum)', 'Enum public.bug_status should not exist', '' ); SELECT * FROM check_test( hasnt_enum( 'public', 'bug_status', 'mydesc' ), false, 'hasnt_enum(schema, enum, desc)', 'mydesc', '' ); /****************************************************************************/ -- Test enum_has_labels(). SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', ARRAY['new', 'open', 'closed'], 'mydesc' ), true, 'enum_has_labels(schema, enum, labels, desc)', 'mydesc', '' ); SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', ARRAY['new', 'open', 'closed'] ), true, 'enum_has_labels(schema, enum, labels)', 'Enum public.bug_status should have labels (new, open, closed)', '' ); SELECT * FROM check_test( enum_has_labels( 'bug_status', ARRAY['new', 'open', 'closed'], 'mydesc' ), true, 'enum_has_labels(enum, labels, desc)', 'mydesc', '' ); SELECT * FROM check_test( enum_has_labels( 'bug_status', ARRAY['new', 'open', 'closed'] ), true, 'enum_has_labels(enum, labels)', 'Enum bug_status should have labels (new, open, closed)', '' ); -- Try failures. SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', ARRAY['new', 'closed', 'open'], 'mydesc' ), false, 'enum_has_labels(schema, enum, labels, desc) fail', 'mydesc', ' have: {new,open,closed} want: {new,closed,open}' ); SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', ARRAY['new', 'open', 'Closed'], 'mydesc' ), false, 'enum_has_labels(schema, enum, labels, desc) fail', 'mydesc', ' have: {new,open,closed} want: {new,open,Closed}' ); SELECT * FROM check_test( enum_has_labels( 'bug_status', ARRAY['new', 'closed', 'open'], 'mydesc' ), false, 'enum_has_labels(enum, labels, desc) fail', 'mydesc', ' have: {new,open,closed} want: {new,closed,open}' ); /****************************************************************************/ -- Test enums_are(). SELECT * FROM check_test( enums_are( 'public', ARRAY['bug_status'], 'whatever' ), true, 'enums_are(schema, enums, desc)', 'whatever', '' ); SELECT * FROM check_test( enums_are( 'public', ARRAY['bug_status'] ), true, 'enums_are(schema, enums)', 'Schema public should have the correct enums', '' ); SELECT * FROM check_test( enums_are( 'public', ARRAY['freddy'], 'whatever' ), false, 'enums_are(schema, enums, desc) fail', 'whatever', ' Extra types: bug_status Missing types: freddy' ); SELECT * FROM check_test( enums_are( 'public', ARRAY['freddy'] ), false, 'enums_are(schema, enums) fail', 'Schema public should have the correct enums', ' Extra types: bug_status Missing types: freddy' ); CREATE FUNCTION ___myenum(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT t.typname FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE ( t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) ) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname NOT IN('pg_catalog', 'information_schema') AND t.typname <> $1 AND pg_catalog.pg_type_is_visible(t.oid) AND t.typtype = 'e' ), '{}'::name[]); $$ LANGUAGE SQL; SELECT * FROM check_test( enums_are( ___myenum(''), 'whatever' ), true, 'enums_are(enums, desc)', 'whatever', '' ); SELECT * FROM check_test( enums_are( ___myenum('') ), true, 'enums_are(enums)', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct enums', '' ); SELECT * FROM check_test( enums_are( array_append(___myenum('bug_status'), 'fredy'), 'whatever' ), false, 'enums_are(enums, desc) fail', 'whatever', ' Extra types: bug_status Missing types: fredy' ); SELECT * FROM check_test( enums_are( array_append(___myenum('bug_status'), 'fredy') ), false, 'enums_are(enums) fail', 'Search path ' || pg_catalog.current_setting('search_path') || ' should have the correct enums', ' Extra types: bug_status Missing types: fredy' ); /****************************************************************************/ -- Make sure that we properly handle reordered labels. CREATE FUNCTION test_alter_enum() RETURNS SETOF TEXT AS $$ DECLARE tap record; expect TEXT[]; labels TEXT; BEGIN IF pg_version_num() >= 90100 THEN -- Mimic ALTER TYPE ADD VALUE by reordering labels. EXECUTE $E$ UPDATE pg_catalog.pg_enum SET enumsortorder = CASE enumlabel WHEN 'closed' THEN 4 WHEN 'open' THEN 5 ELSE 6 END WHERE enumtypid IN ( SELECT t.oid FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid WHERE n.nspname = 'public' AND t.typname = 'bug_status' AND t.typtype = 'e' ); $E$; expect := ARRAY['closed', 'open', 'new']; ELSE expect := ARRAY['new', 'open', 'closed']; END IF; labels := array_to_string(expect, ', '); FOR tap IN SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', expect, 'mydesc' ), true, 'enum_has_labels(schema, altered_enum, labels, desc)', 'mydesc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( enum_has_labels( 'public', 'bug_status', expect ), true, 'enum_has_labels(schema, altered_enum, labels)', 'Enum public.bug_status should have labels ('|| labels || ')', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( enum_has_labels( 'bug_status', expect, 'mydesc' ), true, 'enum_has_labels(altered_enum, labels, desc)', 'mydesc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( enum_has_labels( 'bug_status', expect ), true, 'enum_has_labels(altered_enum, labels)', 'Enum bug_status should have labels (' || labels || ')', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_alter_enum(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/extension.sql000066400000000000000000000327611455775703000171710ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(72); --SELECT * FROM no_plan(); -- This will be rolled back. :-) /****************************************************************************/ -- Test extensions_are(). CREATE FUNCTION public.test_extensions() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 90100 THEN EXECUTE $E$ CREATE SCHEMA someschema; CREATE SCHEMA ci_schema; CREATE SCHEMA "empty schema"; CREATE EXTENSION IF NOT EXISTS citext SCHEMA ci_schema; CREATE EXTENSION IF NOT EXISTS isn SCHEMA someschema; CREATE EXTENSION IF NOT EXISTS ltree SCHEMA someschema; $E$; FOR tap IN SELECT * FROM check_test( extensions_are( 'someschema', ARRAY['isn', 'ltree'], 'Got em' ), true, 'extensions_are(sch, exts, desc)', 'Got em', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( extensions_are( 'someschema', ARRAY['isn', 'ltree'] ), true, 'extensions_are(sch, exts)', 'Schema someschema should have the correct extensions', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT* FROM check_test( extensions_are( ARRAY['citext', 'isn', 'ltree', 'plpgsql', 'pgtap'], 'Got em' ), true, 'extensions_are(exts, desc)', 'Got em', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT* FROM check_test( extensions_are( ARRAY['citext', 'isn', 'ltree', 'plpgsql', 'pgtap'] ), true, 'extensions_are(exts)', 'Should have the correct extensions', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT* FROM check_test( extensions_are( 'ci_schema', ARRAY['citext'], 'Got em' ), true, 'extensions_are(ci_schema, exts, desc)', 'Got em', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT* FROM check_test( extensions_are( 'empty schema', '{}'::name[] ), true, 'extensions_are(non-sch, exts)', 'Schema "empty schema" should have the correct extensions', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; /********************************************************************/ -- Test failures and diagnostics. FOR tap IN SELECT* FROM check_test( extensions_are( 'someschema', ARRAY['ltree', 'nonesuch'], 'Got em' ), false, 'extensions_are(sch, good/bad, desc)', 'Got em', ' Extra extensions: isn Missing extensions: nonesuch' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT* FROM check_test( extensions_are( ARRAY['citext', 'isn', 'ltree', 'pgtap', 'nonesuch'] ), false, 'extensions_are(someexts)', 'Should have the correct extensions', ' Extra extensions: plpgsql Missing extensions: nonesuch' ) AS b LOOP RETURN NEXT tap.b; END LOOP; /********************************************************************/ -- Test has_extension(). -- 8 tests FOR tap IN SELECT * FROM check_test( has_extension( 'ci_schema', 'citext', 'desc' ), true, 'has_extension( schema, name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( 'ci_schema', 'citext'::name ), true, 'has_extension( schema, name )', 'Extension citext should exist in schema ci_schema', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( 'citext'::name, 'desc' ), true, 'has_extension( name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( 'citext' ), true, 'has_extension( name )', 'Extension citext should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( 'public'::name, '__NON_EXISTS__'::name, 'desc' ), false, 'has_extension( schema, name, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( 'public'::name, '__NON_EXISTS__'::name ), false, 'has_extension( schema, name ) fail', 'Extension "__NON_EXISTS__" should exist in schema public', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( '__NON_EXISTS__'::name, 'desc' ), false, 'has_extension( name, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_extension( '__NON_EXISTS__'::name ), false, 'has_extension( name ) fail', 'Extension "__NON_EXISTS__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; /********************************************************************/ -- Test hasnt_extension(). -- 8 tests FOR tap IN SELECT * FROM check_test( hasnt_extension( 'public', '__NON_EXISTS__', 'desc' ), true, 'hasnt_extension( schema, name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( 'public', '__NON_EXISTS__'::name ), true, 'hasnt_extension( schema, name )', 'Extension "__NON_EXISTS__" should not exist in schema public', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( '__NON_EXISTS__'::name, 'desc' ), true, 'hasnt_extension( name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( '__NON_EXISTS__' ), true, 'hasnt_extension( name )', 'Extension "__NON_EXISTS__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( 'ci_schema', 'citext', 'desc' ), false, 'hasnt_extension( schema, name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( 'ci_schema', 'citext'::name ), false, 'hasnt_extension( schema, name )', 'Extension citext should not exist in schema ci_schema', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( 'citext', 'desc' ), false, 'hasnt_extension( name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_extension( 'citext' ), false, 'hasnt_extension( name )', 'Extension citext should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(sch, exts, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(sch, exts)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(exts, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(exts)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(ci_schema, exts, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'extensions_are(non-sch, exts)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'extensions_are(sch, good/bad, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'extensions_are(someexts)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; /********************************************************************/ -- Test has_extension(). -- 8 tests FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'has_extension( schema, name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'has_extension( schema, name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'has_extension( name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'has_extension( name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'has_extension( schema, name, desc ) fail', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'has_extension( schema, name ) fail', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'has_extension( name, desc ) fail', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'has_extension( name ) fail', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; /********************************************************************/ -- Test hasnt_extension(). -- 8 tests FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'hasnt_extension( schema, name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'hasnt_extension( schema, name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'hasnt_extension( name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'hasnt_extension( name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'hasnt_extension( schema, name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'hasnt_extension( schema, name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'hasnt_extension( name, desc )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'hasnt_extension( name )', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE PLPGSQL; SELECT * FROM public.test_extensions(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/fktap.sql000066400000000000000000000334451455775703000162620ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(134); --SELECT * from no_plan(); -- These will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.pk ( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '' ); CREATE TABLE public.fk ( id INT NOT NULL PRIMARY KEY, pk_id INT NOT NULL REFERENCES pk(id) ); CREATE TABLE public.pk2 ( num int NOT NULL UNIQUE, dot int NOT NULL, PRIMARY KEY (num, dot) ); CREATE TABLE public.fk2 ( pk2_num int NOT NULL, pk2_dot int NOT NULL, FOREIGN KEY(pk2_num, pk2_dot) REFERENCES pk2(num, dot) ); CREATE TABLE public.fk3( id INT NOT NULL PRIMARY KEY, pk_id INT NOT NULL REFERENCES pk(id), pk2_num int NOT NULL, pk2_dot int NOT NULL, foo_id INT NOT NULL, FOREIGN KEY(pk2_num, pk2_dot) REFERENCES pk2( num, dot) ); CREATE TABLE public.pk3( id INT UNIQUE ); CREATE TABLE public.fk4 ( id INT REFERENCES pk3(id) ); CREATE TEMP TABLE temp_pk( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '' ); CREATE TEMP TABLE temp_fk ( id INT NOT NULL PRIMARY KEY, pk_id INT NOT NULL REFERENCES temp_pk(id) ); -- Create a funcion to return the temp scheme name. DO $F$ BEGIN IF pg_version_num() >= 95000 THEN EXECUTE 'CREATE FUNCTION tmpns() RETURNS NAME AS $$ SELECT pg_my_temp_schema()::regnamespace::name $$ LANGUAGE SQL;'; ELSE EXECUTE 'CREATE FUNCTION tmpns() RETURNS NAME AS $$ SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema() $$ LANGUAGE SQL;'; END IF; END; $F$; RESET client_min_messages; /****************************************************************************/ -- Test has_fk(). SELECT * FROM check_test( has_fk( 'public', 'fk', 'public.fk should have an fk' ), true, 'has_fk( schema, table, description )', 'public.fk should have an fk' ); SELECT * FROM check_test( has_fk( 'fk', 'fk should have an fk' ), 'true', 'has_fk( table, description )', 'fk should have an fk' ); SELECT * FROM check_test( has_fk( 'fk4', 'fk4 should have an fk' ), 'true', 'has_fk( table4, description )', 'fk4 should have an fk' ); SELECT * FROM check_test( has_fk( 'public', 'fk4', 'fk4 should have an fk' ), 'true', 'has_fk( schema, table4, description )', 'fk4 should have an fk' ); SELECT * FROM check_test( has_fk( 'fk' ), true, 'has_fk( table )', 'Table fk should have a foreign key constraint' ); SELECT * FROM check_test( has_fk( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should have an fk' ), false, 'has_fk( schema, table, description ) fail', 'pg_catalog.pg_class should have an fk' ); SELECT * FROM check_test( has_fk( 'pg_class', 'pg_class should have an fk' ), false, 'has_fk( table, description ) fail', 'pg_class should have an fk' ); /****************************************************************************/ -- Test hasnt_fk(). SELECT * FROM check_test( hasnt_fk( 'public', 'fk', 'public.fk should not have an fk' ), false, 'hasnt_fk( schema, table, description )', 'public.fk should not have an fk' ); SELECT * FROM check_test( hasnt_fk( 'fk', 'fk should not have an fk' ), 'false', 'hasnt_fk( table, description )', 'fk should not have an fk' ); SELECT * FROM check_test( hasnt_fk( 'fk' ), false, 'hasnt_fk( table )', 'Table fk should not have a foreign key constraint' ); SELECT * FROM check_test( hasnt_fk( 'pg_catalog', 'pg_class', 'pg_catalog.pg_class should not have an fk' ), true, 'hasnt_fk( schema, table, description ) pass', 'pg_catalog.pg_class should not have an fk' ); SELECT * FROM check_test( hasnt_fk( 'pg_class', 'pg_class should not have an fk' ), true, 'hasnt_fk( table, description ) pass', 'pg_class should not have an fk' ); /****************************************************************************/ -- Test col_is_fk(). SELECT * FROM check_test( col_is_fk( 'public', 'fk', 'pk_id', 'public.fk.pk_id should be an fk' ), true, 'col_is_fk( schema, table, column, description )', 'public.fk.pk_id should be an fk' ); SELECT * FROM check_test( col_is_fk( 'fk', 'pk_id', 'fk.pk_id should be an fk' ), true, 'col_is_fk( table, column, description )', 'fk.pk_id should be an fk' ); SELECT * FROM check_test( col_is_fk( 'fk', 'pk_id' ), true, 'col_is_fk( table, column )', 'Column fk(pk_id) should be a foreign key' ); SELECT * FROM check_test( col_is_fk( 'public', 'fk', 'name', 'public.fk.name should be an fk' ), false, 'col_is_fk( schema, table, column, description )', 'public.fk.name should be an fk', ' Table public.fk has foreign key constraints on these columns: pk_id' ); SELECT * FROM check_test( col_is_fk( 'fk3', 'name', 'fk3.name should be an fk' ), false, 'col_is_fk( table, column, description )', 'fk3.name should be an fk', ' Table fk3 has foreign key constraints on these columns: pk2_num, pk2_dot pk_id' ); -- Check table with multiple FKs. SELECT * FROM check_test( col_is_fk( 'fk3', 'pk_id' ), true, 'multi-fk col_is_fk test', 'Column fk3(pk_id) should be a foreign key' ); -- Check failure for table with no FKs. SELECT * FROM check_test( col_is_fk( 'public', 'pk', 'name', 'pk.name should be an fk' ), false, 'col_is_fk with no FKs', 'pk.name should be an fk', ' Table public.pk has no foreign key columns' ); SELECT * FROM check_test( col_is_fk( 'pk', 'name' ), false, 'col_is_fk with no FKs', 'Column pk(name) should be a foreign key', ' Table pk has no foreign key columns' ); /****************************************************************************/ -- Test col_is_fk() with an array of columns. SELECT * FROM check_test( col_is_fk( 'public', 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'id + pk2_dot should be an fk' ), true, 'col_is_fk( schema, table, column[], description )', 'id + pk2_dot should be an fk' ); SELECT * FROM check_test( col_is_fk( 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'id + pk2_dot should be an fk' ), true, 'col_is_fk( table, column[], description )', 'id + pk2_dot should be an fk' ); SELECT * FROM check_test( col_is_fk( 'fk2', ARRAY['pk2_num', 'pk2_dot'] ), true, 'col_is_fk( table, column[] )', 'Columns fk2(pk2_num, pk2_dot) should be a foreign key' ); /****************************************************************************/ -- Test col_isnt_fk(). SELECT * FROM check_test( col_isnt_fk( 'public', 'fk', 'pk_id', 'public.fk.pk_id should not be an fk' ), false, 'col_isnt_fk( schema, table, column, description )', 'public.fk.pk_id should not be an fk', '' ); SELECT * FROM check_test( col_isnt_fk( 'fk', 'pk_id', 'fk.pk_id should not be an fk' ), false, 'col_isnt_fk( table, column, description )', 'fk.pk_id should not be an fk', '' ); SELECT * FROM check_test( col_isnt_fk( 'fk', 'pk_id' ), false, 'col_isnt_fk( table, column )', 'Column fk(pk_id) should not be a foreign key', '' ); SELECT * FROM check_test( col_isnt_fk( 'public', 'fk', 'name', 'public.fk.name should not be an fk' ), true, 'col_isnt_fk( schema, table, column, description )', 'public.fk.name should not be an fk', '' ); SELECT * FROM check_test( col_isnt_fk( 'fk3', 'name', 'fk3.name should not be an fk' ), true, 'col_isnt_fk( table, column, description )', 'fk3.name should not be an fk', '' ); -- Check table with multiple FKs. SELECT * FROM check_test( col_isnt_fk( 'fk3', 'pk_id' ), false, 'multi-fk col_isnt_fk test', 'Column fk3(pk_id) should not be a foreign key', '' ); -- Check failure for table with no FKs. SELECT * FROM check_test( col_isnt_fk( 'public', 'pk', 'name', 'pk.name should not be an fk' ), true, 'col_isnt_fk with no FKs', 'pk.name should not be an fk', '' ); SELECT * FROM check_test( col_isnt_fk( 'pk', 'name' ), true, 'col_isnt_fk with no FKs', 'Column pk(name) should not be a foreign key', '' ); /****************************************************************************/ -- Test col_isnt_fk() with an array of columns. SELECT * FROM check_test( col_isnt_fk( 'public', 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'id + pk2_dot should not be an fk' ), false, 'col_isnt_fk( schema, table, column[], description )', 'id + pk2_dot should not be an fk' ); SELECT * FROM check_test( col_isnt_fk( 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'id + pk2_dot should not be an fk' ), false, 'col_isnt_fk( table, column[], description )', 'id + pk2_dot should not be an fk' ); SELECT * FROM check_test( col_isnt_fk( 'fk2', ARRAY['pk2_num', 'pk2_dot'] ), false, 'col_isnt_fk( table, column[] )', 'Columns fk2(pk2_num, pk2_dot) should not be a foreign key' ); /****************************************************************************/ -- Test fk_ok(). SELECT * FROM check_test( fk_ok( 'public', 'fk', ARRAY['pk_id'], 'public', 'pk', ARRAY['id'], 'WHATEVER' ), true, 'full fk_ok array', 'WHATEVER' ); -- Make sure it works with the temp schema. SELECT * FROM check_test( fk_ok( tmpns(), 'temp_fk', ARRAY['pk_id'], tmpns(), 'temp_pk', ARRAY['id'], 'WHATEVER' ), true, 'pg_my_temp_schema()', 'WHATEVER' ); SELECT * FROM check_test( fk_ok( 'public', 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'public', 'pk2', ARRAY['num', 'dot'] ), true, 'multiple fk fk_ok desc', 'public.fk2(pk2_num, pk2_dot) should reference public.pk2(num, dot)' ); SELECT * FROM check_test( fk_ok( 'public', 'fk', ARRAY['pk_id'], 'public', 'pk', ARRAY['id'] ), true, 'fk_ok array desc', 'public.fk(pk_id) should reference public.pk(id)' ); SELECT * FROM check_test( fk_ok( 'fk', ARRAY['pk_id'], 'pk', ARRAY['id'] ), true, 'fk_ok array noschema desc', 'fk(pk_id) should reference pk(id)' ); SELECT * FROM check_test( fk_ok( 'fk2', ARRAY['pk2_num', 'pk2_dot'], 'pk2', ARRAY['num', 'dot'] ), true, 'multiple fk fk_ok noschema desc', 'fk2(pk2_num, pk2_dot) should reference pk2(num, dot)' ); SELECT * FROM check_test( fk_ok( 'fk', ARRAY['pk_id'], 'pk', ARRAY['id'], 'WHATEVER' ), true, 'fk_ok array noschema', 'WHATEVER' ); SELECT * FROM check_test( fk_ok( 'public', 'fk', 'pk_id', 'public', 'pk', 'id', 'WHATEVER' ), true, 'basic fk_ok', 'WHATEVER' ); SELECT * FROM check_test( fk_ok( 'public', 'fk', 'pk_id', 'public', 'pk', 'id' ), true, 'basic fk_ok desc', 'public.fk(pk_id) should reference public.pk(id)' ); SELECT * FROM check_test( fk_ok( 'fk', 'pk_id', 'pk', 'id', 'WHATEVER' ), true, 'basic fk_ok noschema', 'WHATEVER' ); SELECT * FROM check_test( fk_ok( 'fk', 'pk_id', 'pk', 'id' ), true, 'basic fk_ok noschema desc', 'fk(pk_id) should reference pk(id)', '' ); -- Make sure check_test() works properly with no name argument. SELECT * FROM check_test( fk_ok( 'fk', 'pk_id', 'pk', 'id' ), true ); SELECT * FROM check_test( fk_ok( 'public', 'fk', ARRAY['pk_id'], 'public', 'pk', ARRAY['fid'], 'WHATEVER' ), false, 'fk_ok fail', 'WHATEVER', ' have: public.fk(pk_id) REFERENCES public.pk(id) want: public.fk(pk_id) REFERENCES public.pk(fid)' ); SELECT * FROM check_test( fk_ok( 'public', 'fk', ARRAY['pk_id'], 'public', 'pk', ARRAY['fid'] ), false, 'fk_ok fail desc', 'public.fk(pk_id) should reference public.pk(fid)', ' have: public.fk(pk_id) REFERENCES public.pk(id) want: public.fk(pk_id) REFERENCES public.pk(fid)' ); SELECT * FROM check_test( fk_ok( 'fk', ARRAY['pk_id'], 'pk', ARRAY['fid'], 'WHATEVER' ), false, 'fk_ok fail no schema', 'WHATEVER', ' have: fk(pk_id) REFERENCES pk(id) want: fk(pk_id) REFERENCES pk(fid)' ); SELECT * FROM check_test( fk_ok( 'fk', ARRAY['pk_id'], 'pk', ARRAY['fid'] ), false, 'fk_ok fail no schema desc', 'fk(pk_id) should reference pk(fid)', ' have: fk(pk_id) REFERENCES pk(id) want: fk(pk_id) REFERENCES pk(fid)' ); SELECT * FROM check_test( fk_ok( 'fk', ARRAY['pk_id'], 'ok', ARRAY['fid'], 'WHATEVER' ), false, 'fk_ok bad PK test', 'WHATEVER', ' have: fk(pk_id) REFERENCES pk(id) want: fk(pk_id) REFERENCES ok(fid)' ); -- Try a table with multiple FKs. SELECT * FROM check_test( fk_ok( 'public', 'fk3', 'pk_id', 'public', 'pk', 'id' ), true, 'double fk schema test', 'public.fk3(pk_id) should reference public.pk(id)', '' ); SELECT * FROM check_test( fk_ok( 'fk3', 'pk_id', 'pk', 'id' ), true, 'double fk test', 'fk3(pk_id) should reference pk(id)', '' ); -- Try the second FK on that table, which happens to be a multicolumn FK. SELECT * FROM check_test( fk_ok( 'public', 'fk3', ARRAY['pk2_num', 'pk2_dot'], 'public', 'pk2', ARRAY['num', 'dot'] ), true, 'double fk and col schema test', 'public.fk3(pk2_num, pk2_dot) should reference public.pk2(num, dot)', '' ); -- Try FK columns that reference nothing. SELECT * FROM check_test( fk_ok( 'public', 'fk3', 'id', 'public', 'foo', 'id' ), false, 'missing fk test', 'public.fk3(id) should reference public.foo(id)', ' have: public.fk3(id) REFERENCES NOTHING want: public.fk3(id) REFERENCES public.foo(id)' ); -- Try non-existent FK colums. SELECT * FROM check_test( fk_ok( 'fk3', ARRAY['pk2_blah', 'pk2_dot'], 'pk2', ARRAY['num', 'dot'] ), false, 'bad FK column test', 'fk3(pk2_blah, pk2_dot) should reference pk2(num, dot)', ' have: fk3(pk2_blah, pk2_dot) REFERENCES NOTHING want: fk3(pk2_blah, pk2_dot) REFERENCES pk2(num, dot)' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/functap.sql000066400000000000000000002234301455775703000166100ustar00rootroot00000000000000\unset ECHO \i test/setup.sql -- \i sql/pgtap.sql SELECT plan(1105); -- SELECT * FROM no_plan(); CREATE SCHEMA someschema; CREATE FUNCTION someschema.huh () RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL; CREATE FUNCTION someschema.bah (int, text) RETURNS BOOL AS 'BEGIN RETURN TRUE; END;' LANGUAGE plpgsql; CREATE FUNCTION public.yay () RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL STRICT SECURITY DEFINER VOLATILE; CREATE FUNCTION public.oww (int, text) RETURNS BOOL AS 'BEGIN RETURN TRUE; END;' LANGUAGE plpgsql IMMUTABLE; CREATE FUNCTION public.pet () RETURNS SETOF BOOL AS 'BEGIN RETURN NEXT TRUE; RETURN; END;' LANGUAGE plpgsql STABLE; DO $$ BEGIN IF pg_version_num() >= 140000 THEN CREATE AGGREGATE public.tap_accum ( sfunc = array_append, basetype = anycompatible, stype = anycompatiblearray, initcond = '{}' ); CREATE FUNCTION atype() RETURNS text AS 'SELECT ''anycompatiblearray''::text' LANGUAGE SQL IMMUTABLE; CREATE FUNCTION etype() RETURNS text AS 'SELECT ''anycompatible''::text' LANGUAGE SQL IMMUTABLE; ELSE CREATE AGGREGATE public.tap_accum ( sfunc = array_append, basetype = anyelement, stype = anyarray, initcond = '{}' ); CREATE FUNCTION atype() RETURNS text AS 'SELECT ''anyarray''::text' LANGUAGE SQL IMMUTABLE; CREATE FUNCTION etype() RETURNS text AS 'SELECT ''anyelement''::text' LANGUAGE SQL IMMUTABLE; END IF; IF pg_version_num() >= 110000 THEN EXECUTE 'CREATE PROCEDURE public.someproc(int) LANGUAGE SQL AS '''''; ELSE CREATE FUNCTION public.someproc(int) RETURNS void AS '' LANGUAGE SQL; END IF; END; $$; /****************************************************************************/ -- Test has_function(). SELECT * FROM check_test( has_function( 'now' ), true, 'simple function', 'Function now() should exist', '' ); SELECT * FROM check_test( has_function( 'pg_catalog', 'now'::name ), true, 'simple schema.function', 'Function pg_catalog.now() should exist', '' ); SELECT * FROM check_test( has_function( 'now', 'whatever' ), true, 'simple function desc', 'whatever', '' ); SELECT * FROM check_test( has_function( 'now', '{}'::name[] ), true, 'simple with 0 args', 'Function now() should exist', '' ); SELECT * FROM check_test( has_function( 'now', '{}'::name[], 'whatever' ), true, 'simple with 0 args desc', 'whatever', '' ); SELECT * FROM check_test( has_function( 'pg_catalog', 'now', '{}'::name[] ), true, 'simple schema.func with 0 args', 'Function pg_catalog.now() should exist', '' ); SELECT * FROM check_test( has_function( 'pg_catalog', 'now', 'whatever' ), true, 'simple schema.func with desc', 'whatever', '' ); SELECT * FROM check_test( has_function( 'pg_catalog', 'now', '{}'::name[], 'whatever' ), true, 'simple schema.func with 0 args, desc', 'whatever', '' ); SELECT * FROM check_test( has_function( 'abs', '{int}'::name[] ), true, 'simple function with 1 arg', 'Function abs(int) should exist', '' ); SELECT * FROM check_test( has_function( 'age', '{timestamptz,timestamptz}'::name[] ), true, 'simple function with 2 args', 'Function age(timestamptz, timestamptz) should exist', '' ); SELECT * FROM check_test( has_function( 'array_cat', ARRAY[atype(), atype()] ), true, 'simple array function', 'Function array_cat(' || atype() || ', ' || atype() || ') should exist', '' ); -- Check a custom function with an array argument. CREATE FUNCTION __cat__ (text[]) RETURNS BOOLEAN AS 'SELECT TRUE' LANGUAGE SQL; SELECT * FROM check_test( has_function( '__cat__', '{text[]}'::name[] ), true, 'custom array function', 'Function __cat__(text[]) should exist', '' ); -- Check a custom function with a numeric argument. CREATE FUNCTION __cat__ (numeric(10,2)) RETURNS BOOLEAN AS 'SELECT TRUE' LANGUAGE SQL; SELECT * FROM check_test( has_function( '__cat__', '{numeric}'::name[] ), true, 'custom numeric function', 'Function __cat__(numeric) should exist', '' ); -- Check a custom function with a schema-qualified arugment. CREATE DOMAIN public.intword AS TEXT CHECK (VALUE IN ('one', 'two', 'three')); CREATE FUNCTION __cat__(intword) RETURNS BOOLEAN AS 'SELECT TRUE' LANGUAGE SQL; SELECT * FROM check_test( has_function( '__cat__', '{intword}'::name[] ), true, 'custom unqualified function with intword unqualified argument', 'Function __cat__(intword) should exist', '' ); SELECT * FROM check_test( has_function( '__cat__', '{public.intword}'::name[] ), true, 'custom unqualified function with intword qualified argument', 'Function __cat__(public.intword) should exist', '' ); SELECT * FROM check_test( has_function( 'public', '__cat__', '{intword}'::name[] ), true, 'custom qualified function with intword unqualified argument', 'Function public.__cat__(intword) should exist', '' ); SELECT * FROM check_test( has_function( 'public', '__cat__', '{public.intword}'::text[] ), true, 'custom qualified function with intword qualified argument', 'Function public.__cat__(public.intword) should exist', '' ); -- Check failure output. SELECT * FROM check_test( has_function( '__cat__', '{varchar[]}'::name[] ), false, 'failure output', 'Function __cat__(varchar[]) should exist', '' -- No diagnostics. ); -- Test with a procedure. SELECT * FROM check_test( has_function( 'public', 'someproc', 'hi' ), true, 'public procedure', 'hi', '' ); SELECT * FROM check_test( has_function( 'someproc' ), true, 'public procedure', 'Function someproc() should exist', '' ); /****************************************************************************/ -- Test hasnt_function(). SELECT * FROM check_test( hasnt_function( 'now' ), false, 'simple function', 'Function now() should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'pg_catalog', 'now'::name ), false, 'simple schema.function', 'Function pg_catalog.now() should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'now', 'whatever' ), false, 'simple function desc', 'whatever', '' ); SELECT * FROM check_test( hasnt_function( 'now', '{}'::name[] ), false, 'simple with 0 args', 'Function now() should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'now', '{}'::name[], 'whatever' ), false, 'simple with 0 args desc', 'whatever', '' ); SELECT * FROM check_test( hasnt_function( 'pg_catalog', 'now', '{}'::name[] ), false, 'simple schema.func with 0 args', 'Function pg_catalog.now() should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'pg_catalog', 'now', 'whatever' ), false, 'simple schema.func with desc', 'whatever', '' ); SELECT * FROM check_test( hasnt_function( 'pg_catalog', 'now', '{}'::name[], 'whatever' ), false, 'simple schema.func with 0 args, desc', 'whatever', '' ); SELECT * FROM check_test( hasnt_function( 'lower', '{text}'::name[] ), false, 'simple function with 1 arg', 'Function lower(text) should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'decode', '{text,text}'::name[] ), false, 'simple function with 2 args', 'Function decode(text, text) should not exist', '' ); SELECT * FROM check_test( hasnt_function( 'array_cat', ARRAY[atype(), atype()] ), false, 'simple array function', 'Function array_cat(' || atype() || ', ' || atype() || ') should not exist', '' ); SELECT * FROM check_test( hasnt_function( '__cat__', '{text[]}'::name[] ), false, 'custom array function', 'Function __cat__(text[]) should not exist', '' ); SELECT * FROM check_test( hasnt_function( '__cat__', '{numeric}'::name[] ), false, 'custom numeric function', 'Function __cat__(numeric) should not exist', '' ); -- Test with a procedure. SELECT * FROM check_test( hasnt_function( 'public', 'someproc', 'hi' ), false, 'public procedure', 'hi', '' ); SELECT * FROM check_test( hasnt_function( 'someproc' ), false, 'public procedure', 'Function someproc() should not exist', '' ); /****************************************************************************/ -- Try can() function names. SELECT * FROM check_test( can( 'pg_catalog', ARRAY['lower', 'upper'], 'whatever' ), true, 'can(schema) with desc', 'whatever', '' ); SELECT * FROM check_test( can( 'pg_catalog', ARRAY['lower', 'upper'] ), true, 'can(schema)', 'Schema pg_catalog can', '' ); SELECT * FROM check_test( can( 'pg_catalog', ARRAY['lower', 'foo', 'bar'], 'whatever' ), false, 'fail can(schema) with desc', 'whatever', ' pg_catalog.foo() missing pg_catalog.bar() missing' ); SELECT * FROM check_test( can( 'someschema', ARRAY['huh', 'lower', 'upper'], 'whatever' ), false, 'fail can(someschema) with desc', 'whatever', ' someschema.lower() missing someschema.upper() missing' ); SELECT * FROM check_test( can( ARRAY['__cat__', 'lower', 'upper'], 'whatever' ), true, 'can() with desc', 'whatever', '' ); SELECT * FROM check_test( can( ARRAY['lower', 'upper'] ), true, 'can(schema)', 'Schema ' || array_to_string(current_schemas(true), ' or ') || ' can', '' ); SELECT * FROM check_test( can( ARRAY['__cat__', 'foo', 'bar'], 'whatever' ), false, 'fail can() with desc', 'whatever', ' foo() missing bar() missing' ); -- Try can() with a procedure. SELECT * FROM check_test( can( 'public', ARRAY['someproc'], 'whatever' ), true, 'can(sch, proc) with desc', 'whatever', '' ); SELECT * FROM check_test( can( ARRAY['someproc'], 'whatever' ), true, 'can(proc) with desc', 'whatever', '' ); /****************************************************************************/ -- Test function_lang_is(). SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', '{}'::name[], 'sql', 'whatever' ), true, 'function_lang_is(schema, func, 0 args, sql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', '{}'::name[], 'sql' ), true, 'function_lang_is(schema, func, 0 args, sql)', 'Function someschema.huh() should be written in sql', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'bah', '{"int", "text"}'::name[], 'plpgsql', 'whatever' ), true, 'function_lang_is(schema, func, args, plpgsql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'bah', '{"int", "text"}'::name[], 'plpgsql' ), true, 'function_lang_is(schema, func, args, plpgsql)', 'Function someschema.bah(int, text) should be written in plpgsql', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', '{}'::name[], 'perl', 'whatever' ), false, 'function_lang_is(schema, func, 0 args, perl, desc)', 'whatever', ' have: sql want: perl' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'why', '{}'::name[], 'sql', 'whatever' ), false, 'function_lang_is(schema, non-func, 0 args, sql, desc)', 'whatever', ' Function someschema.why() does not exist' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'why', '{"int", "text"}'::name[], 'plpgsql' ), false, 'function_lang_is(schema, func, args, plpgsql)', 'Function someschema.why(int, text) should be written in plpgsql', ' Function someschema.why(int, text) does not exist' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', 'sql', 'whatever' ), true, 'function_lang_is(schema, func, sql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', 'sql'::name ), true, 'function_lang_is(schema, func, sql)', 'Function someschema.huh() should be written in sql', '' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'huh', 'perl', 'whatever' ), false, 'function_lang_is(schema, func, perl, desc)', 'whatever', ' have: sql want: perl' ); SELECT * FROM check_test( function_lang_is( 'someschema', 'why', 'sql', 'whatever' ), false, 'function_lang_is(schema, non-func, sql, desc)', 'whatever', ' Function someschema.why() does not exist' ); SELECT * FROM check_test( function_lang_is( 'yay', '{}'::name[], 'sql', 'whatever' ), true, 'function_lang_is(func, 0 args, sql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'yay', '{}'::name[], 'sql' ), true, 'function_lang_is(func, 0 args, sql)', 'Function yay() should be written in sql', '' ); SELECT * FROM check_test( function_lang_is( 'oww', '{"int", "text"}'::name[], 'plpgsql', 'whatever' ), true, 'function_lang_is(func, args, plpgsql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'oww', '{"int", "text"}'::name[], 'plpgsql' ), true, 'function_lang_is(func, args, plpgsql)', 'Function oww(int, text) should be written in plpgsql', '' ); SELECT * FROM check_test( function_lang_is( 'yay', '{}'::name[], 'perl', 'whatever' ), false, 'function_lang_is(func, 0 args, perl, desc)', 'whatever', ' have: sql want: perl' ); SELECT * FROM check_test( function_lang_is( 'why', '{}'::name[], 'sql', 'whatever' ), false, 'function_lang_is(non-func, 0 args, sql, desc)', 'whatever', ' Function why() does not exist' ); SELECT * FROM check_test( function_lang_is( 'why', '{"int", "text"}'::name[], 'plpgsql' ), false, 'function_lang_is(func, args, plpgsql)', 'Function why(int, text) should be written in plpgsql', ' Function why(int, text) does not exist' ); SELECT * FROM check_test( function_lang_is( 'yay', 'sql', 'whatever' ), true, 'function_lang_is(func, sql, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'yay', 'sql' ), true, 'function_lang_is(func, sql)', 'Function yay() should be written in sql', '' ); SELECT * FROM check_test( function_lang_is( 'yay', 'perl', 'whatever' ), false, 'function_lang_is(func, perl, desc)', 'whatever', ' have: sql want: perl' ); SELECT * FROM check_test( function_lang_is( 'why', 'sql', 'whatever' ), false, 'function_lang_is(non-func, sql, desc)', 'whatever', ' Function why() does not exist' ); -- Test with procedure. SELECT * FROM check_test( function_lang_is( 'public', 'someproc', 'sql', 'whatever' ), true, 'function_lang_is(schema, proc, desc)', 'whatever', '' ); SELECT * FROM check_test( function_lang_is( 'someproc', 'sql', 'whatever' ), true, 'function_lang_is(schema, proc, desc)', 'whatever', '' ); /****************************************************************************/ -- Test function_returns(). SELECT * FROM check_test( function_returns( 'someschema', 'huh', '{}'::name[], 'bool', 'whatever' ), true, 'function_returns(schema, func, 0 args, bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'huh', '{}'::name[], 'boolean' ), true, 'function_returns(schema, func, 0 args, bool)', 'Function someschema.huh() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'bah', ARRAY['int', 'text'], 'bool', 'whatever' ), true, 'function_returns(schema, func, args, bool, false)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'bah', ARRAY['int', 'text'], 'boolean' ), true, 'function_returns(schema, func, args, bool)', 'Function someschema.bah(int, text) should return boolean', '' ); SELECT * FROM check_test( function_returns( 'public', 'pet', '{}'::name[], 'setof bool', 'whatever' ), true, 'function_returns(schema, func, 0 args, setof bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'public', 'pet', '{}'::name[], 'setof boolean' ), true, 'function_returns(schema, func, 0 args, setof bool)', 'Function public.pet() should return setof boolean', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'huh', 'bool', 'whatever' ), true, 'function_returns(schema, func, bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'huh'::name, 'boolean' ), true, 'function_returns(schema, func, bool)', 'Function someschema.huh() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'bah', 'bool', 'whatever' ), true, 'function_returns(schema, other func, bool, false)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'someschema', 'bah'::name, 'boolean' ), true, 'function_returns(schema, other func, bool)', 'Function someschema.bah() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'public', 'pet', 'setof bool', 'whatever' ), true, 'function_returns(schema, func, setof bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'public', 'pet'::name, 'setof boolean' ), true, 'function_returns(schema, func, setof bool)', 'Function public.pet() should return setof boolean', '' ); SELECT * FROM check_test( function_returns( 'yay', '{}'::name[], 'bool', 'whatever' ), true, 'function_returns(func, 0 args, bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'yay', '{}'::name[], 'boolean' ), true, 'function_returns(func, 0 args, bool)', 'Function yay() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'oww', ARRAY['int', 'text'], 'bool', 'whatever' ), true, 'function_returns(func, args, bool, false)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'oww', ARRAY['int', 'text'], 'boolean' ), true, 'function_returns(func, args, bool)', 'Function oww(int, text) should return boolean', '' ); SELECT * FROM check_test( function_returns( 'pet', '{}'::name[], 'setof bool', 'whatever' ), true, 'function_returns(func, 0 args, setof bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'pet', '{}'::name[], 'setof boolean' ), true, 'function_returns(func, 0 args, setof bool)', 'Function pet() should return setof boolean', '' ); SELECT * FROM check_test( function_returns( 'yay', 'bool', 'whatever' ), true, 'function_returns(func, bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'yay', 'boolean' ), true, 'function_returns(func, bool)', 'Function yay() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'oww', 'bool', 'whatever' ), true, 'function_returns(other func, bool, false)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'oww', 'boolean' ), true, 'function_returns(other func, bool)', 'Function oww() should return boolean', '' ); SELECT * FROM check_test( function_returns( 'pet', 'setof bool', 'whatever' ), true, 'function_returns(func, setof bool, desc)', 'whatever', '' ); SELECT * FROM check_test( function_returns( 'pet', 'setof boolean' ), true, 'function_returns(func, setof bool)', 'Function pet() should return setof boolean', '' ); -- Try with a procedure. SELECT * FROM check_test( function_returns( 'public', 'someproc'::name, 'void' ), true, 'function_returns(sch, proc, void)', 'Function public.someproc() should return void', '' ); SELECT * FROM check_test( function_returns( 'someproc'::name, 'void' ), true, 'function_returns(sch, proc, void)', 'Function someproc() should return void', '' ); /****************************************************************************/ -- Test is_definer() isnt_definer(). SELECT * FROM check_test( is_definer( 'public', 'yay', '{}'::name[], 'whatever' ), true, 'is_definer(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', '{}'::name[], 'whatever' ), false, 'isnt_definer(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay', '{}'::name[] ), true, 'is_definer(schema, func, 0 args)', 'Function public.yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', '{}'::name[] ), false, 'isnt_definer(schema, func, 0 args)', 'Function public.yay() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_definer(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_definer(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'oww', ARRAY['int', 'text'] ), false, 'is_definer(schema, func, args)', 'Function public.oww(int, text) should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'oww', ARRAY['int', 'text'] ), true, 'isnt_definer(schema, func, args)', 'Function public.oww(int, text) should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay', 'whatever' ), true, 'is_definer(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', 'whatever' ), false, 'isnt_definer(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay'::name ), true, 'is_definer(schema, func)', 'Function public.yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay'::name ), false, 'isnt_definer(schema, func)', 'Function public.yay() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay', '{}'::name[], 'whatever' ), true, 'is_definer(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', '{}'::name[], 'whatever' ), false, 'isnt_definer(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay', '{}'::name[] ), true, 'is_definer(schema, func, 0 args)', 'Function public.yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', '{}'::name[] ), false, 'isnt_definer(schema, func, 0 args)', 'Function public.yay() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_definer(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_definer(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'oww', ARRAY['int', 'text'] ), false, 'is_definer(schema, func, args)', 'Function public.oww(int, text) should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'oww', ARRAY['int', 'text'] ), true, 'isnt_definer(schema, func, args)', 'Function public.oww(int, text) should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay', 'whatever' ), true, 'is_definer(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay', 'whatever' ), false, 'isnt_definer(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'public', 'yay'::name ), true, 'is_definer(schema, func)', 'Function public.yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public', 'yay'::name ), false, 'isnt_definer(schema, func)', 'Function public.yay() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'yay', '{}'::name[], 'whatever' ), true, 'is_definer(func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'yay', '{}'::name[], 'whatever' ), false, 'isnt_definer(func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'yay', '{}'::name[] ), true, 'is_definer(func, 0 args)', 'Function yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'yay', '{}'::name[] ), false, 'isnt_definer(func, 0 args)', 'Function yay() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_definer(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_definer(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'oww', ARRAY['int', 'text'] ), false, 'is_definer(func, args)', 'Function oww(int, text) should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'oww', ARRAY['int', 'text'] ), true, 'isnt_definer(func, args)', 'Function oww(int, text) should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'yay', 'whatever' ), true, 'is_definer(func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_definer( 'yay', 'whatever' ), false, 'isnt_definer(func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_definer( 'yay'::name ), true, 'is_definer(func)', 'Function yay() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'yay'::name ), false, 'isnt_definer(func)', 'Function yay() should not be security definer', '' ); -- Try with a procedure. SELECT * FROM check_test( is_definer( 'public'::name, 'someproc'::name ), false, 'is_definer(sch, proc)', 'Function public.someproc() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'public'::name, 'someproc'::name ), true, 'isnt_definer(sch, proc)', 'Function public.someproc() should not be security definer', '' ); SELECT * FROM check_test( is_definer( 'someproc'::name ), false, 'is_definer(proc)', 'Function someproc() should be security definer', '' ); SELECT * FROM check_test( isnt_definer( 'someproc'::name ), true, 'isnt_definer(proc)', 'Function someproc() should not be security definer', '' ); /****************************************************************************/ -- Test is_normal_function() and isnt_normal_function(). -- is_normal_function ( NAME, NAME, NAME[], TEXT ) -- isnt_normal_function ( NAME, NAME, NAME[], TEXT ) SELECT * FROM check_test( is_normal_function( 'someschema', 'huh', '{}', 'whatever' ), true, 'is_normal_function(schema, func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), false, 'is_normal_function(schema, agg, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'huh', '{}', 'whatever' ), false, 'isnt_normal_function(schema, func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), true, 'isnt_normal_function(schema, agg, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'someschema', 'bah', ARRAY['int', 'text'], 'whatever' ), true, 'is_normal_function(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), false, 'is_normal_function(schema, agg, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'bah', ARRAY['int', 'text'], 'whatever' ), false, 'is_normal_function(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), true, 'isnt_normal_function(schema, agg, args, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'someschema', 'nonesuch', '{}', 'whatever' ), false, 'is_normal_function(schema, nofunc, noargs, desc)', 'whatever', ' Function someschema.nonesuch() does not exist' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'nonesuch', ARRAY[etype()], 'whatever' ), false, 'isnt_normal_function(schema, noagg, args, desc)', 'whatever', ' Function someschema.nonesuch(' || etype() || ') does not exist' ); -- is_normal_function( NAME, NAME, NAME[] ) -- isnt_normal_function( NAME, NAME, NAME[] ) SELECT * FROM check_test( is_normal_function( 'someschema', 'huh', '{}'::name[] ), true, 'is_normal_function(schema, func, noargs)', 'Function someschema.huh() should be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'public', 'tap_accum', ARRAY[etype()] ), false, 'is_normal_function(schema, agg, noargs)', 'Function public.tap_accum(' || etype() || ') should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'huh', '{}'::name[] ), false, 'isnt_normal_function(schema, func, noargs)', 'Function someschema.huh() should not be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'public', 'tap_accum', ARRAY[etype()] ), true, 'isnt_normal_function(schema, agg, noargs)', 'Function public.tap_accum(' || etype() || ') should not be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'someschema', 'bah', ARRAY['int', 'text'] ), true, 'is_normal_function(schema, func2, args)', 'Function someschema.bah(int, text) should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'bah', ARRAY['int', 'text'] ), false, 'isnt_normal_function(schema, func2, args)', 'Function someschema.bah(int, text) should not be a normal function', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'someschema', 'nonesuch', '{}'::name[] ), false, 'is_normal_function(schema, func, noargs)', 'Function someschema.nonesuch() should be a normal function', ' Function someschema.nonesuch() does not exist' ); SELECT * FROM check_test( is_normal_function( 'public', 'nonesuch', ARRAY[etype()] ), false, 'is_normal_function(schema, nofunc, noargs)', 'Function public.nonesuch(' || etype() || ') should be a normal function', ' Function public.nonesuch(' || etype() || ') does not exist' '' ); -- is_normal_function ( NAME, NAME, TEXT ) -- isnt_normal_function ( NAME, NAME, TEXT ) SELECT * FROM check_test( is_normal_function( 'someschema', 'huh', 'whatever' ), true, 'is_normal_function(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'public', 'tap_accum', 'whatever' ), false, 'is_normal_function(schema, agg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'huh', 'whatever' ), false, 'isnt_normal_function(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'public', 'tap_accum', 'whatever' ), true, 'isnt_normal_function(schema, agg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'someschema', 'bah', 'whatever' ), true, 'is_normal_function(schema, func2, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'bah', 'whatever' ), false, 'isnt_normal_function(schema, func2, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'someschema', 'nonesuch', 'whatever' ), false, 'is_normal_function(schema, nofunc, desc)', 'whatever', ' Function someschema.nonesuch() does not exist' ); SELECT * FROM check_test( is_normal_function( 'public', 'nonesuch', 'whatever' ), false, 'is_normal_function(schema, noagg, desc)', 'whatever', ' Function public.nonesuch() does not exist' ); -- is_normal_function( NAME, NAME ) -- isnt_normal_function( NAME, NAME ) SELECT * FROM check_test( is_normal_function( 'someschema', 'huh'::name ), true, 'is_normal_function(schema, func)', 'Function someschema.huh() should be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'public', 'tap_accum'::name ), false, 'is_normal_function(schema, agg)', 'Function public.tap_accum() should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'huh'::name ), false, 'isnt_normal_function(schema, func)', 'Function someschema.huh() should not be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'public', 'tap_accum'::name ), true, 'isnt_normal_function(schema, agg)', 'Function public.tap_accum() should not be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'someschema', 'bah'::name ), true, 'is_normal_function(schema, func2, args)', 'Function someschema.bah() should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'someschema', 'bah'::name ), false, 'isnt_normal_function(schema, func2)', 'Function someschema.bah() should not be a normal function', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'someschema', 'nonesuch'::name ), false, 'is_normal_function(schema, nofunc)', 'Function someschema.nonesuch() should be a normal function', ' Function someschema.nonesuch() does not exist' ); SELECT * FROM check_test( is_normal_function( 'public', 'nonesuch'::name ), false, 'is_normal_function(schema, nogg)', 'Function public.nonesuch() should be a normal function', ' Function public.nonesuch() does not exist' ); -- is_normal_function ( NAME, NAME[], TEXT ) -- isnt_normal_function ( NAME, NAME[], TEXT ) SELECT * FROM check_test( is_normal_function( 'yay', '{}'::name[], 'whatever' ), true, 'is_normal_function(func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'tap_accum', ARRAY[etype()], 'whatever' ), false, 'is_normal_function(func, agg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'yay', '{}'::name[], 'whatever' ), false, 'isnt_normal_function(func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'tap_accum', ARRAY[etype()], 'whatever' ), true, 'isnt_normal_function(func, agg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'is_normal_function(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'isnt_normal_function(func, args, desc)', 'whatever', '' ); -- test diagnostics SELECT * FROM check_test( is_normal_function( 'nonesuch', '{}'::name[], 'whatever' ), false, 'is_normal_function(nofunc, noargs, desc)', 'whatever', ' Function nonesuch() does not exist' ); SELECT * FROM check_test( is_normal_function( 'nonesuch', ARRAY[etype()], 'whatever' ), false, 'is_normal_function(func, noagg, desc)', 'whatever', ' Function nonesuch(' || etype() || ') does not exist' ); -- is_normal_function( NAME, NAME[] ) -- isnt_normal_function( NAME, NAME[] ) SELECT * FROM check_test( is_normal_function( 'yay', '{}'::name[] ), true, 'is_normal_function(func, noargs)', 'Function yay() should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'yay', '{}'::name[] ), false, 'isnt_normal_function(func, noargs)', 'Function yay() should not be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'oww', ARRAY['int', 'text'] ), true, 'is_normal_function(func, noargs)', 'Function oww(int, text) should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'oww', ARRAY['int', 'text'] ), false, 'isnt_normal_function(func, noargs)', 'Function oww(int, text) should not be a normal function', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'nope', '{}'::name[] ), false, 'is_normal_function(nofunc, noargs)', 'Function nope() should be a normal function', ' Function nope() does not exist' ); SELECT * FROM check_test( isnt_normal_function( 'nope', '{}'::name[] ), false, 'isnt_normal_function(fnounc, noargs)', 'Function nope() should not be a normal function', ' Function nope() does not exist' ); -- is_normal_function( NAME, TEXT ) -- isnt_normal_function( NAME, TEXT ) SELECT * FROM check_test( is_normal_function( 'yay', 'whatever' ), true, 'is_normal_function(func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'tap_accum', 'whatever' ), false, 'is_normal_function(agg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_normal_function( 'yay', 'howdy' ), false, 'isnt_normal_function(func, desc)', 'howdy', '' ); SELECT * FROM check_test( isnt_normal_function( 'tap_accum', 'whatever' ), true, 'isnt_normal_function(agg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_normal_function( 'oww', 'coyote' ), true, 'is_normal_function(func2, desc)', 'coyote', '' ); SELECT * FROM check_test( isnt_normal_function( 'oww', 'hi there' ), false, 'isnt_normal_function(func2, desc)', 'hi there', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'none', 'whatever' ), false, 'is_normal_function(nofunc, desc)', 'whatever', ' Function "none"() does not exist' ); SELECT * FROM check_test( is_normal_function( 'none', 'whatever' ), false, 'is_normal_function(noagg, desc)', 'whatever', ' Function "none"() does not exist' ); -- is_normal_function( NAME ) -- isnt_normal_function( NAME ) SELECT * FROM check_test( is_normal_function( 'yay' ), true, 'is_normal_function(func)', 'Function yay() should be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'tap_accum' ), false, 'is_normal_function(agg)', 'Function tap_accum() should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'yay' ), false, 'isnt_normal_function(func)', 'Function yay() should not be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'tap_accum' ), true, 'isnt_normal_function(agg)', 'Function tap_accum() should not be a normal function', '' ); SELECT * FROM check_test( is_normal_function( 'oww' ), true, 'is_normal_function(func2)', 'Function oww() should be a normal function', '' ); SELECT * FROM check_test( isnt_normal_function( 'oww' ), false, 'isnt_normal_function(func2,)', 'Function oww() should not be a normal function', '' ); -- Test diagnostics SELECT * FROM check_test( is_normal_function( 'zippo' ), false, 'is_normal_function(nofunc)', 'Function zippo() should be a normal function', ' Function zippo() does not exist' ); SELECT * FROM check_test( is_normal_function( 'zippo' ), false, 'is_normal_function(noagg)', 'Function zippo() should be a normal function', ' Function zippo() does not exist' ); CREATE FUNCTION proc_name() RETURNS TEXT LANGUAGE SQL AS $$ -- Use an aggregate function in place of the proc on v10 and earlier. SELECT CASE WHEN pg_version_num() >= 110000 THEN 'someproc' ELSE 'tap_accum' END; $$; SELECT * FROM check_test( is_normal_function( 'public', proc_name()::name ), false, 'is_normal_function(schema, proc)', format('Function public.%s() should be a normal function', proc_name()), '' ); SELECT * FROM check_test( isnt_normal_function( 'public', proc_name()::name ), true, 'isnt_normal_function(schema, proc)', format('Function public.%s() should not be a normal function', proc_name()), '' ); SELECT * FROM check_test( is_normal_function( proc_name()::name ), false, 'is_normal_function(proc)', format('Function %s() should be a normal function', proc_name()), '' ); SELECT * FROM check_test( isnt_normal_function( proc_name()::name ), true, 'isnt_normal_function(proc)', format('Function %s() should not be a normal function', proc_name()), '' ); /****************************************************************************/ -- Test is_aggregate() and isnt_aggregate(). -- is_aggregate ( NAME, NAME, NAME[], TEXT ) -- isnt_aggregate ( NAME, NAME, NAME[], TEXT ) SELECT * FROM check_test( is_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), true, 'is_aggregate(schema, func, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()], 'whatever' ), false, 'isnt_aggregate(schema, agg, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_aggregate( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_aggregate(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_aggregate(schema, func, args, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'public', 'nope', ARRAY[etype()], 'whatever' ), false, 'is_aggregate(schema, nofunc, arg, desc)', 'whatever', ' Function public.nope(' || etype() || ') does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'nope', ARRAY[etype()], 'whatever' ), false, 'isnt_aggregate(schema, noagg, arg, desc)', 'whatever', ' Function public.nope(' || etype() || ') does not exist' ); -- is_aggregate( NAME, NAME, NAME[] ) -- isnt_aggregate( NAME, NAME, NAME[] ) SELECT * FROM check_test( is_aggregate( 'public', 'tap_accum', ARRAY[etype()] ), true, 'is_aggregate(schema, agg, arg)', 'Function public.tap_accum(' || etype() || ') should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'tap_accum', ARRAY[etype()] ), false, 'isnt_aggregate(schema, agg, arg)', 'Function public.tap_accum(' || etype() || ') should not be an aggregate function', '' ); SELECT * FROM check_test( is_aggregate( 'public', 'oww', ARRAY['int', 'text'] ), false, 'is_aggregate(schema, func, args)', 'Function public.oww(int, text) should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'oww', ARRAY['int', 'text'] ), true, 'isnt_aggregate(schema, func, args)', 'Function public.oww(int, text) should not be an aggregate function', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'public', 'uhuh', ARRAY[etype()] ), false, 'is_aggregate(schema, noagg, arg)', 'Function public.uhuh(' || etype() || ') should be an aggregate function', ' Function public.uhuh(' || etype() || ') does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'uhuh', ARRAY[etype()] ), false, 'isnt_aggregate(schema, noagg, arg)', 'Function public.uhuh(' || etype() || ') should not be an aggregate function', ' Function public.uhuh(' || etype() || ') does not exist' ); -- is_aggregate ( NAME, NAME, TEXT ) -- isnt_aggregate ( NAME, NAME, TEXT ) SELECT * FROM check_test( is_aggregate( 'public', 'tap_accum', 'whatever' ), true, 'is_aggregate(schema, agg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'tap_accum', 'whatever' ), false, 'isnt_aggregate(schema, agg, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'public', 'nada', 'whatever' ), false, 'is_aggregate(schema, noagg, desc)', 'whatever', ' Function public.nada() does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'nada', 'whatever' ), false, 'isnt_aggregate(schema, noagg, desc)', 'whatever', ' Function public.nada() does not exist' ); -- is_aggregate( NAME, NAME ) -- isnt_aggregate( NAME, NAME ) SELECT * FROM check_test( is_aggregate( 'public', 'tap_accum'::name ), true, 'is_aggregate(schema, agg)', 'Function public.tap_accum() should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'tap_accum'::name ), false, 'isnt_aggregate(schema, agg)', 'Function public.tap_accum() should not be an aggregate function', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'public', 'nope'::name ), false, 'is_aggregate(schema, noagg)', 'Function public.nope() should be an aggregate function', ' Function public.nope() does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'nope'::name ), false, 'isnt_aggregate(schema, noagg)', 'Function public.nope() should not be an aggregate function', ' Function public.nope() does not exist' ); -- is_aggregate ( NAME, NAME[], TEXT ) -- isnt_aggregate ( NAME, NAME[], TEXT ) SELECT * FROM check_test( is_aggregate( 'tap_accum', ARRAY[etype()], 'whatever' ), true, 'is_aggregate(agg, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'tap_accum', ARRAY[etype()], 'whatever' ), false, 'isnt_aggregate(agg, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_aggregate( 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_aggregate(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_aggregate(func, args, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'nonesuch', ARRAY[etype()], 'whatever' ), false, 'is_aggregate(noagg, arg, desc)', 'whatever', ' Function nonesuch(' || etype() || ') does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'nonesuch', ARRAY[etype()], 'whatever' ), false, 'isnt_aggregate(noagg, arg, desc)', 'whatever', ' Function nonesuch(' || etype() || ') does not exist' ); -- is_aggregate( NAME, NAME[] ) -- isnt_aggregate( NAME, NAME[] ) SELECT * FROM check_test( is_aggregate( 'tap_accum', ARRAY[etype()] ), true, 'is_aggregate(agg, arg)', 'Function tap_accum(' || etype() || ') should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'tap_accum', ARRAY[etype()] ), false, 'isnt_aggregate(agg, arg)', 'Function tap_accum(' || etype() || ') should not be an aggregate function', '' ); SELECT * FROM check_test( is_aggregate( 'oww', ARRAY['int', 'text'] ), false, 'is_aggregate(func, args)', 'Function oww(int, text) should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'oww', ARRAY['int', 'text'] ), true, 'isnt_aggregate(func, args)', 'Function oww(int, text) should not be an aggregate function', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( '_zip', ARRAY[etype()] ), false, 'is_aggregate(noagg, arg)', 'Function _zip(' || etype() || ') should be an aggregate function', ' Function _zip(' || etype() || ') does not exist' ); SELECT * FROM check_test( isnt_aggregate( '_zip', ARRAY[etype()] ), false, 'isnt_aggregate(noagg, arg)', 'Function _zip(' || etype() || ') should not be an aggregate function', ' Function _zip(' || etype() || ') does not exist' ); -- is_aggregate( NAME, TEXT ) -- isnt_aggregate( NAME, TEXT ) SELECT * FROM check_test( is_aggregate( 'tap_accum', 'whatever' ), true, 'is_aggregate(func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_aggregate( 'tap_accum', 'whatever' ), false, 'isnt_aggregate(agg, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'nope', 'whatever' ), false, 'is_aggregate(nofunc, desc)', 'whatever', ' Function nope() does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'nope', 'whatever' ), false, 'isnt_aggregate(noagg, desc)', 'whatever', ' Function nope() does not exist' ); -- is_aggregate( NAME ) -- isnt_aggregate( NAME ) SELECT * FROM check_test( is_aggregate( 'tap_accum'::name ), true, 'is_aggregate(agg)', 'Function tap_accum() should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'tap_accum'::name ), false, 'isnt_aggregate(agg)', 'Function tap_accum() should not be an aggregate function', '' ); -- Test diagnostics SELECT * FROM check_test( is_aggregate( 'nope'::name ), false, 'is_aggregate(noagg)', 'Function nope() should be an aggregate function', ' Function nope() does not exist' ); SELECT * FROM check_test( isnt_aggregate( 'nope'::name ), false, 'isnt_aggregate(noagg)', 'Function nope() should not be an aggregate function', ' Function nope() does not exist' ); -- Try with a procedure. SELECT * FROM check_test( is_aggregate( 'public', 'someproc'::name ), false, 'is_aggregate(schema, proc)', 'Function public.someproc() should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'public', 'someproc'::name ), true, 'is_aggregate(schema, proc)', 'Function public.someproc() should not be an aggregate function', '' ); SELECT * FROM check_test( is_aggregate( 'someproc' ), false, 'is_aggregate(proc)', 'Function someproc() should be an aggregate function', '' ); SELECT * FROM check_test( isnt_aggregate( 'someproc' ), true, 'is_aggregate(proc)', 'Function someproc() should not be an aggregate function', '' ); /****************************************************************************/ -- Test is_window() and isnt_window(). -- is_window ( NAME, NAME, NAME[], TEXT ) -- isnt_window ( NAME, NAME, NAME[], TEXT ) SELECT * FROM check_test( is_window( 'pg_catalog', 'ntile', ARRAY['int'], 'whatever' ), true, 'is_window(schema, win, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'ntile', ARRAY['int'], 'whatever' ), false, 'isnt_window(schema, win, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'someschema', 'bah', ARRAY['int', 'text'], 'whatever' ), false, 'is_window(schema, func, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'someschema', 'bah', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_window(schema, func, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'pg_catalog', 'dense_rank', '{}'::name[], 'whatever' ), true, 'is_window(schema, win, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'dense_rank', '{}'::name[], 'whatever' ), false, 'isnt_window(schema, win, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'someschema', 'huh', '{}'::name[], 'whatever' ), false, 'is_window(schema, func, noarg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'dense_rank', '{}'::name[], 'whatever' ), false, 'is_window(schema, win, noargs, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'someschema', 'nope', ARRAY['int'], 'whatever' ), false, 'is_window(schema, nowin, arg, desc)', 'whatever', ' Function someschema.nope(int) does not exist' ); SELECT * FROM check_test( isnt_window( 'someschema', 'nope', ARRAY['int'], 'whatever' ), false, 'isnt_window(schema, nowin, arg, desc)', 'whatever', ' Function someschema.nope(int) does not exist' ); -- is_window ( NAME, NAME, NAME[] ) -- isnt_window ( NAME, NAME, NAME[] ) SELECT * FROM check_test( is_window( 'pg_catalog', 'ntile', ARRAY['int'] ), true, 'is_window(schema, win, arg)', 'Function pg_catalog.ntile(int) should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'ntile', ARRAY['int'] ), false, 'isnt_window(schema, win, arg)', 'Function pg_catalog.ntile(int) should not be a window function', '' ); SELECT * FROM check_test( is_window( 'someschema', 'bah', ARRAY['int', 'text'] ), false, 'is_window(schema, func, arg)', 'Function someschema.bah(int, text) should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'someschema', 'bah', ARRAY['int', 'text'] ), true, 'isnt_window(schema, func, arg)', 'Function someschema.bah(int, text) should not be a window function', '' ); SELECT * FROM check_test( is_window( 'pg_catalog', 'dense_rank', '{}'::name[] ), true, 'is_window(schema, win, noargs)', 'Function pg_catalog.dense_rank() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'dense_rank', '{}'::name[] ), false, 'isnt_window(schema, win, noargs)', 'Function pg_catalog.dense_rank() should not be a window function', '' ); SELECT * FROM check_test( is_window( 'someschema', 'huh', '{}'::name[] ), false, 'is_window(schema, func, noarg)', 'Function someschema.huh() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'dense_rank', '{}'::name[] ), false, 'isnt_window(schema, win, noargs)', 'Function pg_catalog.dense_rank() should not be a window function', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'someschema', 'nada', ARRAY['int'] ), false, 'is_window(schema, nowin, arg)', 'Function someschema.nada(int) should be a window function', ' Function someschema.nada(int) does not exist' ); SELECT * FROM check_test( isnt_window( 'someschema', 'nada', ARRAY['int'] ), false, 'isnt_window(schema, nowin, arg)', 'Function someschema.nada(int) should not be a window function', ' Function someschema.nada(int) does not exist' ); -- is_window ( NAME, NAME, TEXT ) -- isnt_window ( NAME, NAME, TEXT ) SELECT * FROM check_test( is_window( 'pg_catalog', 'ntile'::name, 'whatever' ), true, 'is_window(schema, win, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'ntile'::name, 'whatever' ), false, 'isnt_window(schema, win, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'someschema', 'bah'::name, 'whatever' ), false, 'is_window(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'someschema', 'bah'::name, 'whatever' ), true, 'isnt_window(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'someschema', 'huh'::name, 'whatever' ), false, 'is_window(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'dense_rank'::name, 'whatever' ), false, 'isnt_window(schema, win, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'someschema', 'nil'::name, 'whatever' ), false, 'is_window(schema, nowin, desc)', 'whatever', ' Function someschema.nil() does not exist' ); SELECT * FROM check_test( isnt_window( 'someschema', 'nil'::name, 'whatever' ), false, 'isnt_window(schema, nowin, desc)', 'whatever', ' Function someschema.nil() does not exist' ); -- is_window( NAME, NAME ) -- isnt_window( NAME, NAME ) SELECT * FROM check_test( is_window( 'pg_catalog', 'ntile'::name ), true, 'is_window(schema, win)', 'Function pg_catalog.ntile() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'pg_catalog', 'ntile'::name ), false, 'isnt_window(schema, win)', 'Function pg_catalog.ntile() should not be a window function', '' ); SELECT * FROM check_test( is_window( 'someschema', 'bah'::name ), false, 'is_window(schema, func)', 'Function someschema.bah() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'someschema', 'bah'::name ), true, 'isnt_window(schema, func)', 'Function someschema.bah() should not be a window function', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'someschema', 'zilch'::name ), false, 'is_window(schema, nowin)', 'Function someschema.zilch() should be a window function', ' Function someschema.zilch() does not exist' ); SELECT * FROM check_test( isnt_window( 'someschema', 'zilch'::name ), false, 'isnt_window(schema, nowin)', 'Function someschema.zilch() should not be a window function', ' Function someschema.zilch() does not exist' ); -- is_window ( NAME, NAME[], TEXT ) -- isnt_window ( NAME, NAME[], TEXT ) SELECT * FROM check_test( is_window( 'ntile', ARRAY['int'], 'whatever' ), true, 'is_window(win, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'ntile', ARRAY['int'], 'whatever' ), false, 'isnt_window(win, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_window(func, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_window(func, arg, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'dense_rank', '{}'::name[], 'whatever' ), true, 'is_window(win, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'dense_rank', '{}'::name[], 'whatever' ), false, 'isnt_window(win, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'yay', '{}'::name[], 'whatever' ), false, 'is_window(func, noarg, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'dense_rank', '{}'::name[], 'whatever' ), false, 'isnt_window(win, noargs, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'nada', ARRAY['int'], 'whatever' ), false, 'is_window(nowin, arg, desc)', 'whatever', ' Function nada(int) does not exist' ); SELECT * FROM check_test( isnt_window( 'nada', ARRAY['int'], 'whatever' ), false, 'isnt_window(nowin, arg, desc)', 'whatever', ' Function nada(int) does not exist' ); -- is_window( NAME, NAME[] ) -- isnt_window( NAME, NAME[] ) SELECT * FROM check_test( is_window( 'ntile', ARRAY['int'] ), true, 'is_window(win, arg, desc)', 'Function ntile(int) should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'ntile', ARRAY['int'] ), false, 'isnt_window(win, arg, desc)', 'Function ntile(int) should not be a window function', '' ); SELECT * FROM check_test( is_window( 'oww', ARRAY['int', 'text'] ), false, 'is_window(func, arg, desc)', 'Function oww(int, text) should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'oww', ARRAY['int', 'text'] ), true, 'isnt_window(func, arg, desc)', 'Function oww(int, text) should not be a window function', '' ); SELECT * FROM check_test( is_window( 'dense_rank', '{}'::name[] ), true, 'is_window(win, noargs, desc)', 'Function dense_rank() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'dense_rank', '{}'::name[] ), false, 'isnt_window(win, noargs, desc)', 'Function dense_rank() should not be a window function', '' ); SELECT * FROM check_test( is_window( 'yay', '{}'::name[] ), false, 'is_window(func, noarg, desc)', 'Function yay() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'dense_rank', '{}'::name[] ), false, 'isnt_window(win, noargs, desc)', 'Function dense_rank() should not be a window function', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'nope', ARRAY['int'] ), false, 'is_window(nowin, arg, desc)', 'Function nope(int) should be a window function', ' Function nope(int) does not exist' ); SELECT * FROM check_test( isnt_window( 'nope', ARRAY['int'] ), false, 'isnt_window(nowin, arg, desc)', 'Function nope(int) should not be a window function', ' Function nope(int) does not exist' ); -- is_window( NAME, TEXT ) -- isnt_window( NAME, TEXT ) SELECT * FROM check_test( is_window( 'ntile'::name, 'whatever' ), true, 'is_window(win, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window( 'lag'::name, 'whatever' ), false, 'isnt_window(win, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'oww'::name, 'whatever' ), false, 'is_window(func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_window('oww'::name, 'whatever' ), true, 'isnt_window(func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_window( 'yay'::name, 'whatever' ), false, 'is_window(func, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'nonesuch'::name, 'whatever' ), false, 'is_window(nowin, desc)', 'whatever', ' Function nonesuch() does not exist' ); SELECT * FROM check_test( isnt_window( 'nonesuch'::name, 'whatever' ), false, 'isnt_window(nowin, desc)', 'whatever', ' Function nonesuch() does not exist' ); -- is_window( NAME ) -- isnt_window( NAME ) SELECT * FROM check_test( is_window( 'ntile' ), true, 'is_window(win)', 'Function ntile() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'ntile' ), false, 'isnt_window(win)', 'Function ntile() should not be a window function', '' ); SELECT * FROM check_test( is_window( 'oww' ), false, 'is_window(func)', 'Function oww() should be a window function', '' ); SELECT * FROM check_test( isnt_window('oww' ), true, 'isnt_window(func)', 'Function oww() should not be a window function', '' ); -- Test diagnostics SELECT * FROM check_test( is_window( 'nooo' ), false, 'is_window(nowin)', 'Function nooo() should be a window function', ' Function nooo() does not exist' ); SELECT * FROM check_test( isnt_window( 'nooo' ), false, 'isnt_window(nowin)', 'Function nooo() should not be a window function', ' Function nooo() does not exist' ); -- Try with a procedure. SELECT * FROM check_test( is_window( 'public', 'someproc'::name ), false, 'is_window(schema, proc)', 'Function public.someproc() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'public', 'someproc'::name ), true, 'is_window(schema, proc)', 'Function public.someproc() should not be a window function', '' ); SELECT * FROM check_test( is_window( 'someproc' ), false, 'is_window(proc)', 'Function someproc() should be a window function', '' ); SELECT * FROM check_test( isnt_window( 'someproc' ), true, 'is_window(proc)', 'Function someproc() should not be a window function', '' ); /****************************************************************************/ -- Test is_strict() and isnt_strict(). SELECT * FROM check_test( is_strict( 'public', 'yay', '{}'::name[], 'whatever' ), true, 'is_strict(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'yay', '{}'::name[], 'whatever' ), false, 'isnt_strict(schema, func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'public', 'yay', '{}'::name[] ), true, 'is_strict(schema, func, 0 args)', 'Function public.yay() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'yay', '{}'::name[] ), false, 'isnt_strict(schema, func, 0 args)', 'Function public.yay() should not be strict', '' ); SELECT * FROM check_test( is_strict( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_strict(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_strict(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'public', 'oww', ARRAY['int', 'text'] ), false, 'is_strict(schema, func, args)', 'Function public.oww(int, text) should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'oww', ARRAY['int', 'text'] ), true, 'isnt_strict(schema, func, args)', 'Function public.oww(int, text) should not be strict', '' ); SELECT * FROM check_test( is_strict( 'public', 'yay', 'whatever' ), true, 'is_strict(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'yay', 'whatever' ), false, 'isnt_strict(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'public', 'yay'::name ), true, 'is_strict(schema, func)', 'Function public.yay() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'yay'::name ), false, 'isnt_strict(schema, func)', 'Function public.yay() should not be strict', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_strict(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'oww', ARRAY['int', 'text'] ), true, 'isnt_strict(schema, func, args)', 'Function public.oww(int, text) should not be strict', '' ); SELECT * FROM check_test( is_strict( 'yay', '{}'::name[], 'whatever' ), true, 'is_strict(func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'yay', '{}'::name[], 'whatever' ), false, 'isnt_strict(func, 0 args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'yay', '{}'::name[] ), true, 'is_strict(func, 0 args)', 'Function yay() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'yay', '{}'::name[] ), false, 'isnt_strict(func, 0 args)', 'Function yay() should not be strict', '' ); SELECT * FROM check_test( is_strict( 'oww', ARRAY['int', 'text'], 'whatever' ), false, 'is_strict(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'oww', ARRAY['int', 'text'], 'whatever' ), true, 'isnt_strict(func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'oww', ARRAY['int', 'text'] ), false, 'is_strict(func, args)', 'Function oww(int, text) should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'oww', ARRAY['int', 'text'] ), true, 'isnt_strict(func, args)', 'Function oww(int, text) should not be strict', '' ); SELECT * FROM check_test( is_strict( 'yay', 'whatever' ), true, 'is_strict(func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_strict( 'yay', 'whatever' ), false, 'isnt_strict(func, desc)', 'whatever', '' ); SELECT * FROM check_test( is_strict( 'yay'::name ), true, 'is_strict(func)', 'Function yay() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'yay'::name ), false, 'isnt_strict(func)', 'Function yay() should not be strict', '' ); -- Try a procedure (never strict). SELECT * FROM check_test( is_strict( 'public', 'someproc'::name ), false, 'is_strict(sch, proc)', 'Function public.someproc() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'public', 'someproc'::name ), true, 'isnt_strict(sch, proc)', 'Function public.someproc() should not be strict', '' ); SELECT * FROM check_test( is_strict( 'someproc'::name ), false, 'is_strict(proc)', 'Function someproc() should be strict', '' ); SELECT * FROM check_test( isnt_strict( 'someproc'::name ), true, 'isnt_strict(proc)', 'Function someproc() should not be strict', '' ); /****************************************************************************/ -- Test volatility_is(). SELECT * FROM check_test( volatility_is( 'public', 'yay', '{}'::name[], 'volatile', 'whatever' ), true, 'function_volatility(schema, func, 0 args, volatile, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'yay', '{}'::name[], 'v', 'whatever' ), true, 'function_volatility(schema, func, 0 args, v, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'oww', ARRAY['int', 'text'], 'immutable', 'whatever' ), true, 'function_volatility(schema, func, args, immutable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'pet', '{}'::name[], 'stable', 'whatever' ), true, 'function_volatility(schema, func, 0 args, stable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'yay', '{}'::name[], 'volatile' ), true, 'function_volatility(schema, func, 0 args, volatile)', 'Function public.yay() should be VOLATILE', '' ); SELECT * FROM check_test( volatility_is( 'public', 'oww', ARRAY['int', 'text'], 'immutable' ), true, 'function_volatility(schema, func, args, immutable)', 'Function public.oww(int, text) should be IMMUTABLE' '' ); SELECT * FROM check_test( volatility_is( 'public', 'yay', 'volatile', 'whatever' ), true, 'function_volatility(schema, func, volatile, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'yay'::name, 'volatile' ), true, 'function_volatility(schema, func, volatile)', 'Function public.yay() should be VOLATILE', '' ); SELECT * FROM check_test( volatility_is( 'public', 'oww', 'immutable', 'whatever' ), true, 'function_volatility(schema, func, immutable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'public', 'pet', 'stable', 'whatever' ), true, 'function_volatility(schema, func, stable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'yay', '{}'::name[], 'volatile', 'whatever' ), true, 'function_volatility(func, 0 args, volatile, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'yay', '{}'::name[], 'v', 'whatever' ), true, 'function_volatility(func, 0 args, v, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'oww', ARRAY['int', 'text'], 'immutable', 'whatever' ), true, 'function_volatility(func, args, immutable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'pet', '{}'::name[], 'stable', 'whatever' ), true, 'function_volatility(func, 0 args, stable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'yay', '{}'::name[], 'volatile' ), true, 'function_volatility(func, 0 args, volatile)', 'Function yay() should be VOLATILE', '' ); SELECT * FROM check_test( volatility_is( 'oww', ARRAY['int', 'text'], 'immutable' ), true, 'function_volatility(func, args, immutable)', 'Function oww(int, text) should be IMMUTABLE' '' ); SELECT * FROM check_test( volatility_is( 'yay', 'volatile', 'whatever' ), true, 'function_volatility(func, volatile, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'yay'::name, 'volatile' ), true, 'function_volatility(func, volatile)', 'Function yay() should be VOLATILE', '' ); SELECT * FROM check_test( volatility_is( 'oww', 'immutable', 'whatever' ), true, 'function_volatility(func, immutable, desc)', 'whatever', '' ); SELECT * FROM check_test( volatility_is( 'pet', 'stable', 'whatever' ), true, 'function_volatility(func, stable, desc)', 'whatever', '' ); -- Test a procedure (always volatile) SELECT * FROM check_test( volatility_is( 'public', 'someproc'::name, 'volatile' ), true, 'function_volatility(sch, proc, volatile)', 'Function public.someproc() should be VOLATILE', '' ); SELECT * FROM check_test( volatility_is( 'someproc'::name, 'volatile' ), true, 'function_volatility(proc, volatile)', 'Function someproc() should be VOLATILE', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/hastap.sql000066400000000000000000002567161455775703000164450ustar00rootroot00000000000000\unset ECHO \i test/setup.sql -- \i sql/pgtap.sql SELECT plan(1004); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), "myInt" NUMERIC(8) ); -- Create a partition. CREATE FUNCTION mkpart() RETURNS SETOF TEXT AS $$ BEGIN IF pg_version_num() >= 100000 THEN EXECUTE $E$ CREATE TABLE public.apart (dt DATE NOT NULL) PARTITION BY RANGE (dt); $E$; ELSE EXECUTE $E$ CREATE TABLE public.apart (dt DATE NOT NULL); $E$; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM mkpart(); CREATE TYPE public.sometype AS ( id INT, name TEXT ); CREATE TYPE public."myType" AS ( id INT, foo INT ); CREATE DOMAIN public.us_postal_code AS TEXT CHECK( VALUE ~ '^[[:digit:]]{5}$' OR VALUE ~ '^[[:digit:]]{5}-[[:digit:]]{4}$' ); CREATE DOMAIN public."myDomain" AS TEXT CHECK(TRUE); CREATE SEQUENCE public.someseq; CREATE SCHEMA someschema; RESET client_min_messages; /****************************************************************************/ -- Test has_tablespace(). Can't really test with the location argument, though. SELECT * FROM check_test( has_tablespace( '__SDFSDFD__' ), false, 'has_tablespace(non-existent tablespace)', 'Tablespace "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_tablespace( '__SDFSDFD__', 'lol' ), false, 'has_tablespace(non-existent tablespace, tab)', 'lol', '' ); SELECT * FROM check_test( has_tablespace( 'pg_default' ), true, 'has_tablespace(tablespace)', 'Tablespace pg_default should exist', '' ); SELECT * FROM check_test( has_tablespace( 'pg_default', 'lol' ), true, 'has_tablespace(tablespace, desc)', 'lol', '' ); /****************************************************************************/ -- Test hasnt_tablespace(). SELECT * FROM check_test( hasnt_tablespace( '__SDFSDFD__' ), true, 'hasnt_tablespace(non-existent tablespace)', 'Tablespace "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_tablespace( '__SDFSDFD__', 'lol' ), true, 'hasnt_tablespace(non-existent tablespace, tab)', 'lol', '' ); SELECT * FROM check_test( hasnt_tablespace( 'pg_default' ), false, 'hasnt_tablespace(pg_default)', 'Tablespace pg_default should not exist', '' ); SELECT * FROM check_test( hasnt_tablespace( 'pg_default', 'lol' ), false, 'hasnt_tablespace(tablespace, desc)', 'lol', '' ); /****************************************************************************/ -- Test has_schema(). SELECT * FROM check_test( has_schema( '__SDFSDFD__' ), false, 'has_schema(non-existent schema)', 'Schema "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_schema( '__SDFSDFD__', 'lol' ), false, 'has_schema(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( has_schema( 'someschema' ), true, 'has_schema(schema)', 'Schema someschema should exist', '' ); SELECT * FROM check_test( has_schema( 'someschema', 'lol' ), true, 'has_schema(schema, desc)', 'lol', '' ); /****************************************************************************/ -- Test hasnt_schema(). SELECT * FROM check_test( hasnt_schema( '__SDFSDFD__' ), true, 'hasnt_schema(non-existent schema)', 'Schema "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_schema( '__SDFSDFD__', 'lol' ), true, 'hasnt_schema(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( hasnt_schema( 'someschema' ), false, 'hasnt_schema(schema)', 'Schema someschema should not exist', '' ); SELECT * FROM check_test( hasnt_schema( 'someschema', 'lol' ), false, 'hasnt_schema(schema, desc)', 'lol', '' ); /****************************************************************************/ -- Test has_table(). SELECT * FROM check_test( has_table( '__SDFSDFD__' ), false, 'has_table(non-existent table)', 'Table "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_table( '__SDFSDFD__', 'lol'::name ), false, 'has_table(non-existent schema, tab)', 'Table "__SDFSDFD__".lol should exist', '' ); SELECT * FROM check_test( has_table( '__SDFSDFD__', 'lol' ), false, 'has_table(non-existent table, desc)', 'lol', '' ); SELECT * FROM check_test( has_table( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_table(sch, non-existent table, desc)', 'desc', '' ); SELECT * FROM check_test( has_table( 'pg_type', 'lol' ), true, 'has_table(tab, desc)', 'lol', '' ); SELECT * FROM check_test( has_table( 'pg_catalog', 'pg_type', 'desc' ), true, 'has_table(sch, tab, desc)', 'desc', '' ); -- It should ignore views and types. SELECT * FROM check_test( has_table( 'pg_catalog', 'pg_tables', 'desc' ), false, 'has_table(sch, view, desc)', 'desc', '' ); SELECT * FROM check_test( has_table( 'sometype', 'desc' ), false, 'has_table(type, desc)', 'desc', '' ); -- But not partitions. SELECT * FROM check_test( has_table( 'public', 'apart', 'have apart' ), true, 'has_table(sch, part, desc)', 'have apart', '' ); SELECT * FROM check_test( has_table( 'apart', 'have apart' ), true, 'has_table(part, desc)', 'have apart', '' ); /****************************************************************************/ -- Test hasnt_table(). SELECT * FROM check_test( hasnt_table( '__SDFSDFD__' ), true, 'hasnt_table(non-existent table)', 'Table "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_table( '__SDFSDFD__', 'lol'::name ), true, 'hasnt_table(non-existent schema, tab)', 'Table "__SDFSDFD__".lol should not exist', '' ); SELECT * FROM check_test( hasnt_table( '__SDFSDFD__', 'lol' ), true, 'hasnt_table(non-existent table, desc)', 'lol', '' ); SELECT * FROM check_test( hasnt_table( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_table(sch, non-existent tab, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_table( 'pg_type', 'lol' ), false, 'hasnt_table(tab, desc)', 'lol', '' ); SELECT * FROM check_test( hasnt_table( 'pg_catalog', 'pg_type', 'desc' ), false, 'hasnt_table(sch, tab, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_table( 'apart', 'got apart' ), false, 'hasnt_table(part, desc)', 'got apart', '' ); SELECT * FROM check_test( hasnt_table( 'public', 'apart', 'got apart' ), false, 'hasnt_table(sch, part, desc)', 'got apart', '' ); /****************************************************************************/ -- Test has_view(). SELECT * FROM check_test( has_view( '__SDFSDFD__' ), false, 'has_view(non-existent view)', 'View "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_view( '__SDFSDFD__', 'howdy' ), false, 'has_view(non-existent view, desc)', 'howdy', '' ); SELECT * FROM check_test( has_view( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_view(sch, non-existent view, desc)', 'desc', '' ); SELECT * FROM check_test( has_view( 'pg_tables', 'yowza' ), true, 'has_view(view, desc)', 'yowza', '' ); SELECT * FROM check_test( has_view( 'information_schema', 'tables', 'desc' ), true, 'has_view(sch, view, desc)', 'desc', '' ); SELECT * FROM check_test( has_view( 'information_schema', 'tables'::name ), true, 'has_view(sch, view)', 'View information_schema.tables should exist', '' ); SELECT * FROM check_test( has_view( 'foo', '__SDFSDFD__'::name ), false, 'has_view(sch, non-existent view, desc)', 'View foo."__SDFSDFD__" should exist', '' ); /****************************************************************************/ -- Test hasnt_view(). SELECT * FROM check_test( hasnt_view( '__SDFSDFD__' ), true, 'hasnt_view(non-existent view)', 'View "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_view( '__SDFSDFD__', 'howdy' ), true, 'hasnt_view(non-existent view, desc)', 'howdy', '' ); SELECT * FROM check_test( hasnt_view( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_view(sch, non-existent view, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_view( 'pg_tables', 'yowza' ), false, 'hasnt_view(view, desc)', 'yowza', '' ); SELECT * FROM check_test( hasnt_view( 'information_schema', 'tables', 'desc' ), false, 'hasnt_view(sch, view, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_view( 'information_schema', 'tables'::name ), false, 'hasnt_view(sch, view)', 'View information_schema.tables should not exist', '' ); SELECT * FROM check_test( hasnt_view( 'foo', '__SDFSDFD__'::name ), true, 'hasnt_view(sch, non-existent view)', 'View foo."__SDFSDFD__" should not exist', '' ); /****************************************************************************/ -- Test has_sequence(). SELECT * FROM check_test( has_sequence( '__SDFSDFD__' ), false, 'has_sequence(non-existent sequence)', 'Sequence "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_sequence( '__SDFSDFD__', 'howdy' ), false, 'has_sequence(non-existent sequence, desc)', 'howdy', '' ); SELECT * FROM check_test( has_sequence( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_sequence(sch, non-existent sequence, desc)', 'desc', '' ); SELECT * FROM check_test( has_sequence( 'someseq', 'yowza' ), true, 'has_sequence(sequence, desc)', 'yowza', '' ); SELECT * FROM check_test( has_sequence( 'public', 'someseq', 'desc' ), true, 'has_sequence(sch, sequence, desc)', 'desc', '' ); SELECT * FROM check_test( has_sequence( 'public', 'someseq'::name ), true, 'has_sequence(sch, sequence)', 'Sequence public.someseq should exist' '' ); /****************************************************************************/ -- Test hasnt_sequence(). SELECT * FROM check_test( hasnt_sequence( '__SDFSDFD__' ), true, 'hasnt_sequence(non-existent sequence)', 'Sequence "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_sequence( '__SDFSDFD__', 'howdy' ), true, 'hasnt_sequence(non-existent sequence, desc)', 'howdy', '' ); SELECT * FROM check_test( hasnt_sequence( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_sequence(sch, non-existent sequence, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_sequence( 'someseq', 'yowza' ), false, 'hasnt_sequence(sequence, desc)', 'yowza', '' ); SELECT * FROM check_test( hasnt_sequence( 'public', 'someseq', 'desc' ), false, 'hasnt_sequence(sch, sequence, desc)', 'desc', '' ); /****************************************************************************/ -- Test has_composite(). SELECT * FROM check_test( has_composite( '__SDFSDFD__' ), false, 'has_composite(non-existent composite type)', 'Composite type "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_composite( '__SDFSDFD__', 'lol' ), false, 'has_composite(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( has_composite( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_composite(sch, non-existent composite type, desc)', 'desc', '' ); SELECT * FROM check_test( has_composite( 'sometype', 'lol' ), true, 'has_composite(tab, desc)', 'lol', '' ); SELECT * FROM check_test( has_composite( 'public', 'sometype', 'desc' ), true, 'has_composite(sch, tab, desc)', 'desc', '' ); -- It should ignore views and tables. SELECT * FROM check_test( has_composite( 'pg_catalog', 'pg_composites', 'desc' ), false, 'has_composite(sch, view, desc)', 'desc', '' ); SELECT * FROM check_test( has_composite( 'sometab', 'desc' ), false, 'has_composite(type, desc)', 'desc', '' ); /****************************************************************************/ -- Test hasnt_composite(). SELECT * FROM check_test( hasnt_composite( '__SDFSDFD__' ), true, 'hasnt_composite(non-existent composite type)', 'Composite type "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_composite( '__SDFSDFD__', 'lol' ), true, 'hasnt_composite(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( hasnt_composite( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_composite(sch, non-existent tab, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_composite( 'sometype', 'lol' ), false, 'hasnt_composite(tab, desc)', 'lol', '' ); SELECT * FROM check_test( hasnt_composite( 'public', 'sometype', 'desc' ), false, 'hasnt_composite(sch, tab, desc)', 'desc', '' ); /****************************************************************************/ -- Test has_type(). SELECT * FROM check_test( has_type( 'sometype' ), true, 'has_type(type)', 'Type sometype should exist', '' ); SELECT * FROM check_test( has_type( 'sometype', 'mydesc' ), true, 'has_type(type, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_type( 'public'::name, 'sometype'::name ), true, 'has_type(scheam, type)', 'Type public.sometype should exist', '' ); SELECT * FROM check_test( has_type( 'public', 'sometype', 'mydesc' ), true, 'has_type(schema, type, desc)', 'mydesc', '' ); -- Try case-sensitive. SELECT * FROM check_test( has_type( 'myType' ), true, 'has_type(myType)', 'Type "myType" should exist', '' ); SELECT * FROM check_test( has_type( 'myType', 'mydesc' ), true, 'has_type(myType, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_type( 'public'::name, 'myType'::name ), true, 'has_type(scheam, myType)', 'Type public."myType" should exist', '' ); SELECT * FROM check_test( has_type( 'public', 'myType', 'mydesc' ), true, 'has_type(schema, myType, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( has_type( '__foobarbaz__' ), false, 'has_type(type)', 'Type __foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_type( '__foobarbaz__', 'mydesc' ), false, 'has_type(type, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_type( 'public'::name, '__foobarbaz__'::name ), false, 'has_type(scheam, type)', 'Type public.__foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_type( 'public', '__foobarbaz__', 'mydesc' ), false, 'has_type(schema, type, desc)', 'mydesc', '' ); -- Make sure it works for domains. SELECT * FROM check_test( has_type( 'us_postal_code' ), true, 'has_type(domain)', 'Type us_postal_code should exist', '' ); SELECT * FROM check_test( has_type( 'myDomain' ), true, 'has_type(myDomain)', 'Type "myDomain" should exist', '' ); /****************************************************************************/ -- Test hasnt_type(). SELECT * FROM check_test( hasnt_type( '__foobarbaz__' ), true, 'hasnt_type(type)', 'Type __foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_type( '__foobarbaz__', 'mydesc' ), true, 'hasnt_type(type, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_type( 'public'::name, '__foobarbaz__'::name ), true, 'hasnt_type(scheam, type)', 'Type public.__foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_type( 'public', '__foobarbaz__', 'mydesc' ), true, 'hasnt_type(schema, type, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( hasnt_type( 'sometype' ), false, 'hasnt_type(type)', 'Type sometype should not exist', '' ); SELECT * FROM check_test( hasnt_type( 'sometype', 'mydesc' ), false, 'hasnt_type(type, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_type( 'public'::name, 'sometype'::name ), false, 'hasnt_type(scheam, type)', 'Type public.sometype should not exist', '' ); SELECT * FROM check_test( hasnt_type( 'public', 'sometype', 'mydesc' ), false, 'hasnt_type(schema, type, desc)', 'mydesc', '' ); /****************************************************************************/ -- Test has_domain(). SELECT * FROM check_test( has_domain( 'us_postal_code' ), true, 'has_domain(domain)', 'Domain us_postal_code should exist', '' ); SELECT * FROM check_test( has_domain( 'us_postal_code', 'mydesc' ), true, 'has_domain(domain, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_domain( 'public'::name, 'us_postal_code'::name ), true, 'has_domain(scheam, domain)', 'Domain public.us_postal_code should exist', '' ); SELECT * FROM check_test( has_domain( 'public', 'us_postal_code', 'mydesc' ), true, 'has_domain(schema, domain, desc)', 'mydesc', '' ); -- Try case-sensitive. SELECT * FROM check_test( has_domain( 'myDomain' ), true, 'has_domain(myDomain)', 'Domain "myDomain" should exist', '' ); SELECT * FROM check_test( has_domain( 'myDomain', 'mydesc' ), true, 'has_domain(myDomain, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_domain( 'public'::name, 'myDomain'::name ), true, 'has_domain(scheam, myDomain)', 'Domain public."myDomain" should exist', '' ); SELECT * FROM check_test( has_domain( 'public', 'myDomain', 'mydesc' ), true, 'has_domain(schema, myDomain, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( has_domain( '__foobarbaz__' ), false, 'has_domain(domain)', 'Domain __foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_domain( '__foobarbaz__', 'mydesc' ), false, 'has_domain(domain, desc)', 'mydesc', '' ); SELECT * FROM check_test( has_domain( 'public'::name, '__foobarbaz__'::name ), false, 'has_domain(scheam, domain)', 'Domain public.__foobarbaz__ should exist', '' ); SELECT * FROM check_test( has_domain( 'public', '__foobarbaz__', 'mydesc' ), false, 'has_domain(schema, domain, desc)', 'mydesc', '' ); /****************************************************************************/ -- Test hasnt_domain(). SELECT * FROM check_test( hasnt_domain( '__foobarbaz__' ), true, 'hasnt_domain(domain)', 'Domain __foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_domain( '__foobarbaz__', 'mydesc' ), true, 'hasnt_domain(domain, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_domain( 'public'::name, '__foobarbaz__'::name ), true, 'hasnt_domain(scheam, domain)', 'Domain public.__foobarbaz__ should not exist', '' ); SELECT * FROM check_test( hasnt_domain( 'public', '__foobarbaz__', 'mydesc' ), true, 'hasnt_domain(schema, domain, desc)', 'mydesc', '' ); -- Try failures. SELECT * FROM check_test( hasnt_domain( 'us_postal_code' ), false, 'hasnt_domain(domain)', 'Domain us_postal_code should not exist', '' ); SELECT * FROM check_test( hasnt_domain( 'us_postal_code', 'mydesc' ), false, 'hasnt_domain(domain, desc)', 'mydesc', '' ); SELECT * FROM check_test( hasnt_domain( 'public'::name, 'us_postal_code'::name ), false, 'hasnt_domain(scheam, domain)', 'Domain public.us_postal_code should not exist', '' ); SELECT * FROM check_test( hasnt_domain( 'public', 'us_postal_code', 'mydesc' ), false, 'hasnt_domain(schema, domain, desc)', 'mydesc', '' ); /****************************************************************************/ -- Test has_column(). SELECT * FROM check_test( has_column( '__SDFSDFD__', 'foo' ), false, 'has_column(non-existent tab, col)', 'Column "__SDFSDFD__".foo should exist', '' ); SELECT * FROM check_test( has_column( '__SDFSDFD__', 'bar', 'whatever' ), false, 'has_column(non-existent tab, col, desc)', 'whatever', '' ); SELECT * FROM check_test( has_column( 'foo', '__SDFSDFD__', 'bar', 'desc' ), false, 'has_column(non-existent sch, tab, col, desc)', 'desc', '' ); SELECT * FROM check_test( has_column( 'sometab', 'id' ), true, 'has_column(table, column)', 'Column sometab.id should exist', '' ); SELECT * FROM check_test( has_column( 'information_schema', 'tables', 'table_name', 'desc' ), true, 'has_column(sch, tab, col, desc)', 'desc', '' ); SELECT * FROM check_test( has_column( 'sometab', 'myInt' ), true, 'has_column(table, camleCase column)', 'Column sometab."myInt" should exist', '' ); -- Make sure it works with views. SELECT * FROM check_test( has_column( 'pg_tables', 'schemaname' ), true, 'has_column(view, column)', 'Column pg_tables.schemaname should exist', '' ); -- Make sure it works with composite types. SELECT * FROM check_test( has_column( 'sometype', 'name' ), true, 'has_column(type, column)', 'Column sometype.name should exist', '' ); /****************************************************************************/ -- Test hasnt_column(). SELECT * FROM check_test( hasnt_column( '__SDFSDFD__', 'foo' ), true, 'hasnt_column(non-existent tab, col)', 'Column "__SDFSDFD__".foo should not exist', '' ); SELECT * FROM check_test( hasnt_column( '__SDFSDFD__', 'bar', 'whatever' ), true, 'hasnt_column(non-existent tab, col, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_column( 'foo', '__SDFSDFD__', 'bar', 'desc' ), true, 'hasnt_column(non-existent sch, tab, col, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_column( 'sometab', 'id' ), false, 'hasnt_column(table, column)', 'Column sometab.id should not exist', '' ); SELECT * FROM check_test( hasnt_column( 'information_schema', 'tables', 'table_name', 'desc' ), false, 'hasnt_column(sch, tab, col, desc)', 'desc', '' ); -- Make sure it works with views. SELECT * FROM check_test( hasnt_column( 'pg_tables', 'whatever' ), true, 'hasnt_column(view, column)', 'Column pg_tables.whatever should not exist', '' ); -- Make sure it works with composite types. SELECT * FROM check_test( hasnt_column( 'sometype', 'foobar' ), true, 'hasnt_column(type, column)', 'Column sometype.foobar should not exist', '' ); /****************************************************************************/ -- Test has_cast(). SELECT * FROM check_test( has_cast( 'integer', 'bigint', 'pg_catalog', 'int8', 'desc' ), true, 'has_cast( src, targ, schema, func, desc)', 'desc', '' ); SELECT * FROM check_test( has_cast( 'int4', 'BIGINT', 'pg_catalog', 'int8'::name), true, 'has_cast( src, targ, schema, func )', 'Cast (int4 AS "BIGINT") WITH FUNCTION pg_catalog.int8() should exist', '' ); SELECT * FROM check_test( has_cast( 'integer', 'bigint', 'int8', 'desc' ), true, 'has_cast( src, targ, func, desc )', 'desc', '' ); SELECT * FROM check_test( has_cast( 'INT4', 'BIGINT', 'int8'::name), true, 'has_cast( src, targ, func)', 'Cast ("INT4" AS "BIGINT") WITH FUNCTION int8() should exist', '' ); SELECT * FROM check_test( has_cast( 'integer', 'bigint', 'desc' ), true, 'has_cast( src, targ, desc )', 'desc', '' ); SELECT * FROM check_test( has_cast( 'int4', 'BIGINT' ), true, 'has_cast( src, targ )', 'Cast (int4 AS "BIGINT") should exist', '' ); SELECT * FROM check_test( has_cast( 'integer', 'bigint', 'pg_catalog', 'foo', 'desc' ), false, 'has_cast( src, targ, schema, func, desc) fail', 'desc', '' ); SELECT * FROM check_test( has_cast( 'INT4', 'BIGINT', 'foo', 'desc' ), false, 'has_cast( src, targ, func, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_cast( 'integer', 'clue', 'desc' ), false, 'has_cast( src, targ, desc ) fail', 'desc', '' ); /****************************************************************************/ -- Test hasnt_cast(). SELECT * FROM check_test( hasnt_cast( 'integer', 'bigint', 'pg_catalog', 'int8', 'desc' ), false, 'hasnt_cast( src, targ, schema, func, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_cast( 'int4', 'int8', 'pg_catalog', 'int8'::name), false, 'hasnt_cast( src, targ, schema, func )', 'Cast (int4 AS int8) WITH FUNCTION pg_catalog.int8() should not exist', '' ); SELECT * FROM check_test( hasnt_cast( 'integer', 'bigint', 'int8', 'desc' ), false, 'hasnt_cast( src, targ, func, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_cast( 'INT4', 'INT8', 'int8'::name), false, 'hasnt_cast( src, targ, func)', 'Cast ("INT4" AS "INT8") WITH FUNCTION int8() should not exist', '' ); SELECT * FROM check_test( hasnt_cast( 'integer', 'bigint', 'desc' ), false, 'hasnt_cast( src, targ, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_cast( 'int4', 'int8' ), false, 'hasnt_cast( src, targ )', 'Cast (int4 AS int8) should not exist', '' ); SELECT * FROM check_test( hasnt_cast( 'integer', 'bigint', 'pg_catalog', 'foo', 'desc' ), true, 'hasnt_cast( src, targ, schema, func, desc) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_cast( 'INT4', 'INT8', 'foo', 'desc' ), true, 'hasnt_cast( src, targ, func, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_cast( 'integer', 'clue', 'desc' ), true, 'hasnt_cast( src, targ, desc ) fail', 'desc', '' ); /****************************************************************************/ -- Test cast_has_context(). SELECT * FROM check_test( cast_context_is( 'integer', 'bigint', 'implicit', 'desc' ), true, 'cast_context_is( src, targ, context, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'int4', 'int8', 'implicit' ), true, 'cast_context_is( src, targ, context )', 'Cast (int4 AS int8) context should be implicit', '' ); SELECT * FROM check_test( cast_context_is( 'integer', 'bigint', 'i', 'desc' ), true, 'cast_context_is( src, targ, i, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'INT4', 'INT8', 'IMPL', 'desc' ), true, 'cast_context_is( src, targ, IMPL, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'bigint', 'smallint', 'assignment', 'desc' ), true, 'cast_context_is( src, targ, assignment, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'int4', 'int2', 'a', 'desc' ), true, 'cast_context_is( src, targ, a, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'bigint', 'smallint', 'ASS', 'desc' ), true, 'cast_context_is( src, targ, ASS, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'bit(128)', 'integer', 'explicit', 'desc' ), true, 'cast_context_is( src, targ, explicit, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'bit', 'int4', 'e', 'desc' ), true, 'cast_context_is( src, targ, e, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'bit', 'integer', 'EX', 'desc' ), true, 'cast_context_is( src, targ, EX, desc )', 'desc', '' ); SELECT * FROM check_test( cast_context_is( 'integer', 'int8', 'ex', 'desc' ), false, 'cast_context_is( src, targ, context, desc ) fail', 'desc', ' have: implicit want: explicit' ); SELECT * FROM check_test( cast_context_is( 'INT4', 'INT8', 'ex' ), false, 'cast_context_is( src, targ, context ) fail', 'Cast ("INT4" AS "INT8") context should be explicit', ' have: implicit want: explicit' ); SELECT * FROM check_test( cast_context_is( 'integer', 'bogus', 'ex', 'desc' ), false, 'cast_context_is( src, targ, context, desc ) noexist', 'desc', ' Cast ("integer" AS bogus) does not exist' ); /****************************************************************************/ -- Test has_operator(). SELECT * FROM check_test( has_operator( 'integer', 'pg_catalog', '<=', 'int', 'bool', 'desc' ), true, 'has_operator( left, schema, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( has_operator( 'int4', 'pg_catalog', '<=', 'integer', 'boolean'::name ), true, 'has_operator( left, schema, name, right, result )', 'Operator pg_catalog.<=(int4,integer) RETURNS boolean should exist', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'int', 'bool', 'desc' ), true, 'has_operator( left, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'int4', 'boolean'::name ), true, 'has_operator( left, name, right, result )', 'Operator <=(integer,int4) RETURNS boolean should exist', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'int', 'desc' ), true, 'has_operator( left, name, right, desc )', 'desc', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'int4'::name ), true, 'has_operator( left, name, right )', 'Operator <=(integer,int4) should exist', '' ); SELECT * FROM check_test( has_operator( 'integer', 'pg_catalog', '<=', 'text', 'bool', 'desc' ), false, 'has_operator( left, schema, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_operator( 'integer', 'pg_catalog', '<=', 'text', 'boolean'::name ), false, 'has_operator( left, schema, name, right, result ) fail', 'Operator pg_catalog.<=(integer,text) RETURNS boolean should exist', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'text', 'bool', 'desc' ), false, 'has_operator( left, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'text', 'boolean'::name ), false, 'has_operator( left, name, right, result ) fail', 'Operator <=(integer,text) RETURNS boolean should exist', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'text', 'desc' ), false, 'has_operator( left, name, right, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_operator( 'integer', '<=', 'text'::name ), false, 'has_operator( left, name, right ) fail', 'Operator <=(integer,text) should exist', '' ); /****************************************************************************/ -- Test hasnt_operator(). SELECT * FROM check_test( hasnt_operator( 'integer', 'pg_catalog', '<=', 'integer', 'boolean', 'desc' ), false, 'hasnt_operator( left, schema, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', 'pg_catalog', '<=', 'int', 'bool'::name ), false, 'hasnt_operator( left, schema, name, right, result ) fail', 'Operator pg_catalog.<=(integer,int) RETURNS bool should not exist', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'integer', 'boolean', 'desc' ), false, 'hasnt_operator( left, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'int', 'bool'::name ), false, 'hasnt_operator( left, name, right, result ) fail', 'Operator <=(integer,int) RETURNS bool should not exist', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'integer', 'desc' ), false, 'hasnt_operator( left, name, right, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'int'::name ), false, 'hasnt_operator( left, name, right ) fail', 'Operator <=(integer,int) should not exist', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', 'pg_catalog', '<=', 'text', 'boolean', 'desc' ), true, 'hasnt_operator( left, schema, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', 'pg_catalog', '<=', 'text', 'bool'::name ), true, 'hasnt_operator( left, schema, name, right, result )', 'Operator pg_catalog.<=(integer,text) RETURNS bool should not exist', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'text', 'boolean', 'desc' ), true, 'hasnt_operator( left, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'text', 'bool'::name ), true, 'hasnt_operator( left, name, right, result )', 'Operator <=(integer,text) RETURNS bool should not exist', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'text', 'desc' ), true, 'hasnt_operator( left, name, right, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_operator( 'integer', '<=', 'text'::name ), true, 'hasnt_operator( left, name, right )', 'Operator <=(integer,text) should not exist', '' ); /****************************************************************************/ -- Test has_leftop(). SELECT * FROM check_test( has_leftop( 'pg_catalog', '+', 'bigint', 'int8', 'desc' ), true, 'has_leftop( schema, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( has_leftop( 'pg_catalog', '+', 'bigint', 'bigint'::name ), true, 'has_leftop( schema, name, right, result )', 'Left operator pg_catalog.+(NONE,bigint) RETURNS bigint should exist', '' ); SELECT * FROM check_test( has_leftop( '+', 'bigint', 'int8', 'desc' ), true, 'has_leftop( name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( has_leftop( '+', 'bigint', 'int8'::name ), true, 'has_leftop( name, right, result )', 'Left operator +(NONE,bigint) RETURNS int8 should exist', '' ); SELECT * FROM check_test( has_leftop( '+', 'bigint', 'desc' ), true, 'has_leftop( name, right, desc )', 'desc', '' ); SELECT * FROM check_test( has_leftop( '+', 'int8' ), true, 'has_leftop( name, right )', 'Left operator +(NONE,int8) should exist', '' ); SELECT * FROM check_test( has_leftop( 'pg_catalog', '+', 'text', 'numeric', 'desc' ), false, 'has_leftop( schema, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_leftop( 'pg_catalog', '+', 'text', 'numeric'::name ), false, 'has_leftop( schema, name, right, result ) fail', 'Left operator pg_catalog.+(NONE,text) RETURNS numeric should exist', '' ); SELECT * FROM check_test( has_leftop( '+', 'text', 'inte', 'desc' ), false, 'has_leftop( name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_leftop( '+', 'text', 'int'::name ), false, 'has_leftop( name, right, result ) fail', 'Left operator +(NONE,text) RETURNS int should exist', '' ); SELECT * FROM check_test( has_leftop( '+', 'text', 'desc' ), false, 'has_leftop( name, right, desc ) fail', 'desc', '' ); SELECT * FROM check_test( has_leftop( '+', 'text' ), false, 'has_leftop( name, right ) fail', 'Left operator +(NONE,text) should exist', '' ); /****************************************************************************/ -- Test hasnt_leftop(). SELECT * FROM check_test( hasnt_leftop( 'pg_catalog', '+', 'bigint', 'int8', 'desc' ), false, 'hasnt_leftop( schema, name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( 'pg_catalog', '+', 'bigint', 'int8'::name ), false, 'hasnt_leftop( schema, name, right, result ) fail', 'Left operator pg_catalog.+(NONE,bigint) RETURNS int8 should not exist', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'bigint', 'bigint', 'desc' ), false, 'hasnt_leftop( name, right, result, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'int8', 'int8'::name ), false, 'hasnt_leftop( name, right, result ) fail', 'Left operator +(NONE,int8) RETURNS int8 should not exist', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'bigint', 'desc' ), false, 'hasnt_leftop( name, right, desc ) fail', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'int8' ), false, 'hasnt_leftop( name, right ) fail', 'Left operator +(NONE,int8) should not exist', '' ); SELECT * FROM check_test( hasnt_leftop( 'pg_catalog', '+', 'text', 'bigint', 'desc' ), true, 'hasnt_leftop( schema, name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( 'pg_catalog', '+', 'text', 'bigint'::name ), true, 'hasnt_leftop( schema, name, right, result )', 'Left operator pg_catalog.+(NONE,text) RETURNS bigint should not exist', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'text', 'bigint', 'desc' ), true, 'hasnt_leftop( name, right, result, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'text', 'int8'::name ), true, 'hasnt_leftop( name, right, result )', 'Left operator +(NONE,text) RETURNS int8 should not exist', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'text', 'desc' ), true, 'hasnt_leftop( name, right, desc )', 'desc', '' ); SELECT * FROM check_test( hasnt_leftop( '+', 'text' ), true, 'hasnt_leftop( name, right )', 'Left operator +(NONE,text) should not exist', '' ); /****************************************************************************/ -- Test has_rightop(). CREATE FUNCTION test_has_rightop() RETURNS SETOF TEXT LANGUAGE plpgsql AS $$ DECLARE tap record; BEGIN IF pg_version_num() < 140000 THEN FOR tap IN SELECT * FROM check_test( has_rightop( 'bigint', 'pg_catalog', '!', 'numeric', 'desc' ), true, 'has_rightop( left, schema, name, result, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'bigint', 'pg_catalog', '!', 'numeric'::name ), true, 'has_rightop( left, schema, name, result )', 'Right operator pg_catalog.!(bigint,NONE) RETURNS numeric should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'bigint', '!', 'numeric', 'desc' ), true, 'has_rightop( left, name, result, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'bigint', '!', 'numeric'::name ), true, 'has_rightop( left, name, result )', 'Right operator !(bigint,NONE) RETURNS numeric should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'int8', '!', 'desc' ), true, 'has_rightop( left, name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'int8', '!' ), true, 'has_rightop( left, name )', 'Right operator !(int8,NONE) should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', 'pg_catalog', '!', 'numeric', 'desc' ), false, 'has_rightop( left, schema, name, result, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', 'pg_catalog', '!', 'numeric'::name ), false, 'has_rightop( left, schema, name, result ) fail', 'Right operator pg_catalog.!(text,NONE) RETURNS numeric should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', '!', 'numeric', 'desc' ), false, 'has_rightop( left, name, result, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', '!', 'numeric'::name ), false, 'has_rightop( left, name, result ) fail', 'Right operator !(text,NONE) RETURNS numeric should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', '!', 'desc' ), false, 'has_rightop( left, name, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_rightop( 'text', '!' ), false, 'has_rightop( left, name ) fail', 'Right operator !(text,NONE) should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- PostgreSQL 14 dropped support for postfix operators, so mock the -- output for the tests to pass. FOR tap IN SELECT * FROM (VALUES ('has_rightop( left, schema, name, result, desc ) should pass'), ('has_rightop( left, schema, name, result, desc ) should have the proper description'), ('has_rightop( left, schema, name, result, desc ) should have the proper diagnostics'), ('has_rightop( left, schema, name, result ) should pass'), ('has_rightop( left, schema, name, result ) should have the proper description'), ('has_rightop( left, schema, name, result ) should have the proper diagnostics'), ('has_rightop( left, name, result, desc ) should pass'), ('has_rightop( left, name, result, desc ) should have the proper description'), ('has_rightop( left, name, result, desc ) should have the proper diagnostics'), ('has_rightop( left, name, result ) should pass'), ('has_rightop( left, name, result ) should have the proper description'), ('has_rightop( left, name, result ) should have the proper diagnostics'), ('has_rightop( left, name, desc ) should pass'), ('has_rightop( left, name, desc ) should have the proper description'), ('has_rightop( left, name, desc ) should have the proper diagnostics'), ('has_rightop( left, name ) should pass'), ('has_rightop( left, name ) should have the proper description'), ('has_rightop( left, name ) should have the proper diagnostics'), ('has_rightop( left, schema, name, result, desc ) fail should fail'), ('has_rightop( left, schema, name, result, desc ) fail should have the proper description'), ('has_rightop( left, schema, name, result, desc ) fail should have the proper diagnostics'), ('has_rightop( left, schema, name, result ) fail should fail'), ('has_rightop( left, schema, name, result ) fail should have the proper description'), ('has_rightop( left, schema, name, result ) fail should have the proper diagnostics'), ('has_rightop( left, name, result, desc ) fail should fail'), ('has_rightop( left, name, result, desc ) fail should have the proper description'), ('has_rightop( left, name, result, desc ) fail should have the proper diagnostics'), ('has_rightop( left, name, result ) fail should fail'), ('has_rightop( left, name, result ) fail should have the proper description'), ('has_rightop( left, name, result ) fail should have the proper diagnostics'), ('has_rightop( left, name, desc ) fail should fail'), ('has_rightop( left, name, desc ) fail should have the proper description'), ('has_rightop( left, name, desc ) fail should have the proper diagnostics'), ('has_rightop( left, name ) fail should fail'), ('has_rightop( left, name ) fail should have the proper description'), ('has_rightop( left, name ) fail should have the proper diagnostics') ) AS A(b) LOOP RETURN NEXT pass(tap.b); END LOOP; END IF; END; $$; SELECT * FROM test_has_rightop(); /****************************************************************************/ -- Test hasnt_rightop(). CREATE FUNCTION test_hasnt_rightop() RETURNS SETOF TEXT LANGUAGE plpgsql AS $$ DECLARE tap record; BEGIN IF pg_version_num() < 140000 THEN FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'int8', 'pg_catalog', '!', 'numeric', 'desc' ), false, 'hasnt_rightop( left, schema, name, result, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'bigint', 'pg_catalog', '!', 'numeric'::name ), false, 'hasnt_rightop( left, schema, name, result ) fail', 'Right operator pg_catalog.!(bigint,NONE) RETURNS numeric should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'int8', '!', 'numeric', 'desc' ), false, 'hasnt_rightop( left, name, result, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'bigint', '!', 'numeric'::name ), false, 'hasnt_rightop( left, name, result ) fail', 'Right operator !(bigint,NONE) RETURNS numeric should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'int8', '!', 'desc' ), false, 'hasnt_rightop( left, name, desc ) fail', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'bigint', '!' ), false, 'hasnt_rightop( left, name ) fail', 'Right operator !(bigint,NONE) should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', 'pg_catalog', '!', 'numeric', 'desc' ), true, 'hasnt_rightop( left, schema, name, result, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', 'pg_catalog', '!', 'numeric'::name ), true, 'hasnt_rightop( left, schema, name, result )', 'Right operator pg_catalog.!(text,NONE) RETURNS numeric should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', '!', 'numeric', 'desc' ), true, 'hasnt_rightop( left, name, result, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', '!', 'numeric'::name ), true, 'hasnt_rightop( left, name, result )', 'Right operator !(text,NONE) RETURNS numeric should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', '!', 'desc' ), true, 'hasnt_rightop( left, name, desc )', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_rightop( 'text', '!' ), true, 'hasnt_rightop( left, name )', 'Right operator !(text,NONE) should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- PostgreSQL 14 dropped support for postfix operators, so mock the -- output for the tests to pass. FOR tap IN SELECT * FROM (VALUES ('hasnt_rightop( left, schema, name, result, desc ) fail should fail'), ('hasnt_rightop( left, schema, name, result, desc ) fail should have the proper description'), ('hasnt_rightop( left, schema, name, result, desc ) fail should have the proper diagnostics'), ('hasnt_rightop( left, schema, name, result ) fail should fail'), ('hasnt_rightop( left, schema, name, result ) fail should have the proper description'), ('hasnt_rightop( left, schema, name, result ) fail should have the proper diagnostics'), ('hasnt_rightop( left, name, result, desc ) fail should fail'), ('hasnt_rightop( left, name, result, desc ) fail should have the proper description'), ('hasnt_rightop( left, name, result, desc ) fail should have the proper diagnostics'), ('hasnt_rightop( left, name, result ) fail should fail'), ('hasnt_rightop( left, name, result ) fail should have the proper description'), ('hasnt_rightop( left, name, result ) fail should have the proper diagnostics'), ('hasnt_rightop( left, name, desc ) fail should fail'), ('hasnt_rightop( left, name, desc ) fail should have the proper description'), ('hasnt_rightop( left, name, desc ) fail should have the proper diagnostics'), ('hasnt_rightop( left, name ) fail should fail'), ('hasnt_rightop( left, name ) fail should have the proper description'), ('hasnt_rightop( left, name ) fail should have the proper diagnostics'), ('hasnt_rightop( left, schema, name, result, desc ) should pass'), ('hasnt_rightop( left, schema, name, result, desc ) should have the proper description'), ('hasnt_rightop( left, schema, name, result, desc ) should have the proper diagnostics'), ('hasnt_rightop( left, schema, name, result ) should pass'), ('hasnt_rightop( left, schema, name, result ) should have the proper description'), ('hasnt_rightop( left, schema, name, result ) should have the proper diagnostics'), ('hasnt_rightop( left, name, result, desc ) should pass'), ('hasnt_rightop( left, name, result, desc ) should have the proper description'), ('hasnt_rightop( left, name, result, desc ) should have the proper diagnostics'), ('hasnt_rightop( left, name, result ) should pass'), ('hasnt_rightop( left, name, result ) should have the proper description'), ('hasnt_rightop( left, name, result ) should have the proper diagnostics'), ('hasnt_rightop( left, name, desc ) should pass'), ('hasnt_rightop( left, name, desc ) should have the proper description'), ('hasnt_rightop( left, name, desc ) should have the proper diagnostics'), ('hasnt_rightop( left, name ) should pass'), ('hasnt_rightop( left, name ) should have the proper description'), ('hasnt_rightop( left, name ) should have the proper diagnostics') ) AS A(b) LOOP RETURN NEXT pass(tap.b); END LOOP; END IF; END; $$; SELECT * FROM test_hasnt_rightop(); /****************************************************************************/ -- Test has_language() and hasnt_language(). SELECT * FROM check_test( has_language('plpgsql'), true, 'has_language(language)', 'Procedural language ' || quote_ident('plpgsql') || ' should exist', '' ); SELECT * FROM check_test( has_language('plpgsql', 'whatever'), true, 'has_language(language, desc)', 'whatever', '' ); SELECT * FROM check_test( has_language('aoijaoisjfaoidfjaisjdfosjf'), false, 'has_language(nonexistent language)', 'Procedural language aoijaoisjfaoidfjaisjdfosjf should exist', '' ); SELECT * FROM check_test( has_language('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'has_language(nonexistent language, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_language('plpgsql'), false, 'hasnt_language(language)', 'Procedural language ' || quote_ident('plpgsql') || ' should not exist', '' ); SELECT * FROM check_test( hasnt_language('plpgsql', 'whatever'), false, 'hasnt_language(language, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_language('plomgwtf'), true, 'hasnt_language(nonexistent language)', 'Procedural language plomgwtf should not exist', '' ); SELECT * FROM check_test( hasnt_language('plomgwtf', 'desc'), true, 'hasnt_language(nonexistent language, desc)', 'desc', '' ); /****************************************************************************/ -- Test language_is_trusted(). SELECT * FROM check_test( language_is_trusted('sql', 'whatever'), true, 'language_is_trusted(language, desc)', 'whatever', '' ); SELECT * FROM check_test( language_is_trusted('sql'), true, 'language_is_trusted(language)', 'Procedural language sql should be trusted', '' ); SELECT * FROM check_test( language_is_trusted('c', 'whatever'), false, 'language_is_trusted(language, desc) fail', 'whatever', '' ); SELECT * FROM check_test( language_is_trusted('plomgwtf', 'whatever'), false, 'language_is_trusted(language, desc) non-existent', 'whatever', ' Procedural language plomgwtf does not exist' ); /****************************************************************************/ -- Test has_opclass() and hasnt_opclass(). SELECT * FROM check_test( has_opclass( 'pg_catalog', 'int4_ops', 'whatever' ), true, 'has_opclass( schema, name, desc )', 'whatever', '' ); SELECT * FROM check_test( has_opclass( 'pg_catalog', 'int4_ops'::name ), true, 'has_opclass( schema, name )', 'Operator class pg_catalog.int4_ops should exist', '' ); SELECT * FROM check_test( has_opclass( 'int4_ops', 'whatever' ), true, 'has_opclass( name, desc )', 'whatever', '' ); SELECT * FROM check_test( has_opclass( 'int4_ops' ), true, 'has_opclass( name )', 'Operator class int4_ops should exist', '' ); SELECT * FROM check_test( has_opclass( 'pg_catalog', 'int4_opss', 'whatever' ), false, 'has_opclass( schema, name, desc ) fail', 'whatever', '' ); SELECT * FROM check_test( has_opclass( 'int4_opss', 'whatever' ), false, 'has_opclass( name, desc ) fail', 'whatever', '' ); SELECT * FROM check_test( hasnt_opclass( 'pg_catalog', 'int4_ops', 'whatever' ), false, 'hasnt_opclass( schema, name, desc )', 'whatever', '' ); SELECT * FROM check_test( hasnt_opclass( 'pg_catalog', 'int4_ops'::name ), false, 'hasnt_opclass( schema, name )', 'Operator class pg_catalog.int4_ops should not exist', '' ); SELECT * FROM check_test( hasnt_opclass( 'int4_ops', 'whatever' ), false, 'hasnt_opclass( name, desc )', 'whatever', '' ); SELECT * FROM check_test( hasnt_opclass( 'int4_ops' ), false, 'hasnt_opclass( name )', 'Operator class int4_ops should not exist', '' ); SELECT * FROM check_test( hasnt_opclass( 'pg_catalog', 'int4_opss', 'whatever' ), true, 'hasnt_opclass( schema, name, desc ) fail', 'whatever', '' ); SELECT * FROM check_test( hasnt_opclass( 'int4_opss', 'whatever' ), true, 'hasnt_opclass( name, desc ) fail', 'whatever', '' ); /****************************************************************************/ -- Test domain_type_is() and domain_type_isnt(). SELECT * FROM check_test( domain_type_is( 'public', 'us_postal_code', 'pg_catalog', 'text', 'whatever'), true, 'domain_type_is(schema, domain, schema, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_is( 'public', 'us_postal_code', 'pg_catalog'::name, 'text'), true, 'domain_type_is(schema, domain, schema, type)', 'Domain public.us_postal_code should extend type pg_catalog.text', '' ); SELECT * FROM check_test( domain_type_is( 'public', 'us_postal_code', 'pg_catalog', 'int4', 'whatever'), false, 'domain_type_is(schema, domain, schema, type, desc) fail', 'whatever', ' have: pg_catalog.text want: pg_catalog.integer' ); SELECT * FROM check_test( domain_type_is( 'public', 'zip_code', 'pg_catalog', 'int', 'whatever'), false, 'domain_type_is(schema, nondomain, schema, type, desc)', 'whatever', ' Domain public.zip_code does not exist' ); SELECT * FROM check_test( domain_type_is( 'public', 'integer', 'pg_catalog', 'int', 'whatever'), false, 'domain_type_is(schema, type, schema, type, desc) fail', 'whatever', ' Domain public.integer does not exist' ); SELECT * FROM check_test( domain_type_is( 'public', 'us_postal_code', 'text', 'whatever'), true, 'domain_type_is(schema, domain, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_is( 'public'::name, 'us_postal_code', 'text'), true, 'domain_type_is(schema, domain, type)', 'Domain public.us_postal_code should extend type text', '' ); SELECT * FROM check_test( domain_type_is( 'public', 'us_postal_code', 'int', 'whatever'), false, 'domain_type_is(schema, domain, type, desc) fail', 'whatever', ' have: text want: integer' ); SELECT * FROM check_test( domain_type_is( 'public', 'zip_code', 'int', 'whatever'), false, 'domain_type_is(schema, nondomain, type, desc)', 'whatever', ' Domain public.zip_code does not exist' ); SELECT * FROM check_test( domain_type_is( 'public', 'integer', 'int', 'whatever'), false, 'domain_type_is(schema, type, type, desc) fail', 'whatever', ' Domain public.integer does not exist' ); SELECT * FROM check_test( domain_type_is( 'us_postal_code', 'text', 'whatever'), true, 'domain_type_is(domain, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_is( 'us_postal_code', 'text'), true, 'domain_type_is(domain, type)', 'Domain us_postal_code should extend type text', '' ); SELECT * FROM check_test( domain_type_is( 'us_postal_code', 'int', 'whatever'), false, 'domain_type_is(domain, type, desc) fail', 'whatever', ' have: text want: integer' ); SELECT * FROM check_test( domain_type_is( 'zip_code', 'int', 'whatever'), false, 'domain_type_is(nondomain, type, desc)', 'whatever', ' Domain zip_code does not exist' ); SELECT * FROM check_test( domain_type_is( 'integer', 'int', 'whatever'), false, 'domain_type_is(type, type, desc) fail', 'whatever', ' Domain integer does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'us_postal_code', 'public', 'int', 'whatever'), true, 'domain_type_isnt(schema, domain, schema, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'us_postal_code', 'pg_catalog'::name, 'int4'), true, 'domain_type_isnt(schema, domain, schema, type)', 'Domain public.us_postal_code should not extend type pg_catalog.int4', '' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'us_postal_code', 'pg_catalog', 'text', 'whatever'), false, 'domain_type_isnt(schema, domain, schema, type, desc) fail', 'whatever', ' have: pg_catalog.text want: anything else' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'zip_code', 'pg_catalog', 'text', 'whatever'), false, 'domain_type_isnt(schema, nondomain, schema, type, desc)', 'whatever', ' Domain public.zip_code does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'integer', 'pg_catalog', 'text', 'whatever'), false, 'domain_type_isnt(schema, type, schema, type, desc)', 'whatever', ' Domain public.integer does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'us_postal_code', 'integer', 'whatever'), true, 'domain_type_isnt(schema, domain, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_isnt( 'public'::name, 'us_postal_code', 'int'), true, 'domain_type_isnt(schema, domain, type)', 'Domain public.us_postal_code should not extend type int', '' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'us_postal_code', 'text', 'whatever'), false, 'domain_type_isnt(schema, domain, type, desc) fail', 'whatever', ' have: text want: anything else' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'zip_code', 'text', 'whatever'), false, 'domain_type_isnt(schema, nondomain, type, desc)', 'whatever', ' Domain public.zip_code does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'public', 'integer', 'text', 'whatever'), false, 'domain_type_isnt(schema, type, type, desc)', 'whatever', ' Domain public.integer does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'us_postal_code', 'integer', 'whatever'), true, 'domain_type_isnt(domain, type, desc)', 'whatever', '' ); SELECT * FROM check_test( domain_type_isnt( 'us_postal_code', 'int'), true, 'domain_type_isnt(domain, type)', 'Domain us_postal_code should not extend type int', '' ); SELECT * FROM check_test( domain_type_isnt( 'us_postal_code', 'text', 'whatever'), false, 'domain_type_isnt(domain, type, desc) fail', 'whatever', ' have: text want: anything else' ); SELECT * FROM check_test( domain_type_isnt( 'zip_code', 'text', 'whatever'), false, 'domain_type_isnt(nondomain, type, desc)', 'whatever', ' Domain zip_code does not exist' ); SELECT * FROM check_test( domain_type_isnt( 'integer', 'text', 'whatever'), false, 'domain_type_isnt(type, type, desc)', 'whatever', ' Domain integer does not exist' ); /****************************************************************************/ -- Test has_foreign_table() and hasnt_foreign_table(). CREATE FUNCTION test_fdw() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 90100 THEN EXECUTE $E$ CREATE FOREIGN DATA WRAPPER dummy; CREATE SERVER foo FOREIGN DATA WRAPPER dummy; CREATE FOREIGN TABLE public.my_fdw (id int) SERVER foo; $E$; FOR tap IN SELECT * FROM check_test( has_foreign_table( '__SDFSDFD__' ), false, 'has_foreign_table(non-existent table)', 'Foreign table "__SDFSDFD__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( '__SDFSDFD__', 'lol'::name ), false, 'has_foreign_table(non-existent schema, tab)', 'Foreign table "__SDFSDFD__".lol should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( '__SDFSDFD__', 'lol' ), false, 'has_foreign_table(non-existent table, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_foreign_table(sch, non-existent table, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( 'my_fdw', 'lol' ), true, 'has_foreign_table(tab, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( 'public', 'my_fdw', 'desc' ), true, 'has_foreign_table(sch, tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore views and types. FOR tap IN SELECT * FROM check_test( has_foreign_table( 'pg_catalog', 'pg_foreign_tables', 'desc' ), false, 'has_foreign_table(sch, view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_foreign_table( 'sometype', 'desc' ), false, 'has_foreign_table(type, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( '__SDFSDFD__' ), true, 'hasnt_foreign_table(non-existent table)', 'Foreign table "__SDFSDFD__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( '__SDFSDFD__', 'lol'::name ), true, 'hasnt_foreign_table(non-existent schema, tab)', 'Foreign table "__SDFSDFD__".lol should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( '__SDFSDFD__', 'lol' ), true, 'hasnt_foreign_table(non-existent table, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_foreign_table(sch, non-existent tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( 'my_fdw', 'lol' ), false, 'hasnt_foreign_table(tab, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_foreign_table( 'public', 'my_fdw', 'desc' ), false, 'hasnt_foreign_table(sch, tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with has_table(). FOR tap IN SELECT * FROM check_test( has_table( '__SDFSDFD__' ), false, 'has_foreign_table(non-existent table)', 'Table "__SDFSDFD__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( '__SDFSDFD__', 'lol'::name ), false, 'has_foreign_table(non-existent schema, tab)', 'Table "__SDFSDFD__".lol should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( '__SDFSDFD__', 'lol' ), false, 'has_foreign_table(non-existent table, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_foreign_table(sch, non-existent table, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( 'pg_type', 'lol' ), true, 'has_foreign_table(tab, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( 'pg_catalog', 'pg_type', 'desc' ), true, 'has_foreign_table(sch, tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore views and types. FOR tap IN SELECT * FROM check_test( has_table( 'pg_catalog', 'pg_foreign_tables', 'desc' ), false, 'has_foreign_table(sch, view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_table( 'sometype', 'desc' ), false, 'has_foreign_table(type, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( '__SDFSDFD__' ), true, 'hasnt_foreign_table(non-existent table)', 'Table "__SDFSDFD__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( '__SDFSDFD__', 'lol'::name ), true, 'hasnt_foreign_table(non-existent schema, tab)', 'Table "__SDFSDFD__".lol should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( '__SDFSDFD__', 'lol' ), true, 'hasnt_foreign_table(non-existent table, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_foreign_table(sch, non-existent tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( 'pg_type', 'lol' ), false, 'hasnt_foreign_table(tab, desc)', 'lol', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_table( 'pg_catalog', 'pg_type', 'desc' ), false, 'hasnt_foreign_table(sch, tab, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE PLPGSQL; /****************************************************************************/ -- Test has_relation(). SELECT * FROM check_test( has_relation( '__SDFSDFD__' ), false, 'has_relation(non-existent relation)', 'Relation "__SDFSDFD__" should exist', '' ); SELECT * FROM check_test( has_relation( '__SDFSDFD__', 'lol' ), false, 'has_relation(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( has_relation( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_relation(sch, non-existent relation, desc)', 'desc', '' ); SELECT * FROM check_test( has_relation( 'pg_type', 'lol' ), true, 'has_relation(tab, desc)', 'lol', '' ); SELECT * FROM check_test( has_relation( 'pg_catalog', 'pg_type', 'desc' ), true, 'has_relation(sch, tab, desc)', 'desc', '' ); -- It should not ignore views and types. SELECT * FROM check_test( has_relation( 'pg_catalog', 'pg_type', 'desc' ), true, 'has_relation(sch, view, desc)', 'desc', '' ); SELECT * FROM check_test( has_relation( 'sometype', 'desc' ), true, 'has_relation(type, desc)', 'desc', '' ); /****************************************************************************/ -- Test hasnt_relation(). SELECT * FROM check_test( hasnt_relation( '__SDFSDFD__' ), true, 'hasnt_relation(non-existent relation)', 'Relation "__SDFSDFD__" should not exist', '' ); SELECT * FROM check_test( hasnt_relation( '__SDFSDFD__', 'lol' ), true, 'hasnt_relation(non-existent schema, tab)', 'lol', '' ); SELECT * FROM check_test( hasnt_relation( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_relation(sch, non-existent tab, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_relation( 'pg_type', 'lol' ), false, 'hasnt_relation(tab, desc)', 'lol', '' ); SELECT * FROM check_test( hasnt_relation( 'pg_catalog', 'pg_type', 'desc' ), false, 'hasnt_relation(sch, tab, desc)', 'desc', '' ); SELECT * FROM test_fdw(); /****************************************************************************/ -- Test has_materialized_view(). CREATE FUNCTION test_has_materialized_view() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 93000 THEN EXECUTE $E$ CREATE MATERIALIZED VIEW public.mview AS SELECT * FROM public.sometab; $E$; FOR tap IN SELECT * FROM check_test( has_materialized_view( '__SDFSDFD__' ), false, 'has_materialized_view(non-existent materialized_view)', 'Materialized view "__SDFSDFD__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_materialized_view( '__SDFSDFD__', 'howdy' ), false, 'has_materialized_view(non-existent materialized_view, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_materialized_view( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_materialized_view(sch, non-existent materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_materialized_view( 'mview', 'yowza' ), true, 'has_materialized_view(materialized_view, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_materialized_view( 'public', 'mview', 'desc' ), true, 'has_materialized_view(sch, materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE FOR tap IN SELECT * FROM check_test( has_view( '__SDFSDFD__' ), false, 'has_materialized_view(non-existent materialized_view)', 'View "__SDFSDFD__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( '__SDFSDFD__', 'howdy' ), false, 'has_materialized_view(non-existent materialized_view, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'foo', '__SDFSDFD__', 'desc' ), false, 'has_materialized_view(sch, non-existent materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'pg_tables', 'yowza' ), true, 'has_materialized_view(materialized_view, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'information_schema', 'tables', 'desc' ), true, 'has_materialized_view(sch, materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ language PLPGSQL; /****************************************************************************/ -- Test hasnt_materialized_view(). CREATE FUNCTION test_hasnt_materialized_views_are() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 93000 THEN FOR tap IN SELECT * FROM check_test( hasnt_materialized_view( '__SDFSDFD__' ), true, 'hasnt_materialized_view(non-existent materialized_view)', 'Materialized view "__SDFSDFD__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_materialized_view( '__SDFSDFD__', 'howdy' ), true, 'hasnt_materialized_view(non-existent materialized_view, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_materialized_view( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_materialized_view(sch, non-existent materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_materialized_view( 'mview', 'yowza' ), false, 'hasnt_materialized_view(materialized_view, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_materialized_view( 'public', 'mview', 'desc' ), false, 'hasnt_materialized_view(sch, materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; else FOR tap IN SELECT * FROM check_test( hasnt_view( '__SDFSDFD__' ), true, 'hasnt_materialized_view(non-existent materialized_view)', 'View "__SDFSDFD__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( '__SDFSDFD__', 'howdy' ), true, 'hasnt_materialized_view(non-existent materialized_view, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'foo', '__SDFSDFD__', 'desc' ), true, 'hasnt_materialized_view(sch, non-existent materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'pg_tables', 'yowza' ), false, 'hasnt_materialized_view(materialized_view, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'information_schema', 'tables', 'desc' ), false, 'hasnt_materialized_view(sch, materialized_view, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ language PLPGSQL; SELECT * FROM test_has_materialized_view(); SELECT * FROm test_hasnt_materialized_views_are(); /****************************************************************************/ -- Test is_partitioned(). CREATE FUNCTION test_is_partitioned() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 100000 THEN FOR tap IN SELECT * FROM check_test( is_partitioned( '__SDFSDFD__' ), false, 'is_partitioned(non-existent part)', 'Table "__SDFSDFD__" should be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( '__SDFSDFD__', 'howdy' ), false, 'is_partitioned(non-existent part, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( 'foo', '__SDFSDFD__', 'desc' ), false, 'is_partitioned(sch, non-existent part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( 'public', 'apart', 'desc' ), true, 'is_partitioned(sch, part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( 'public', 'apart'::name ), true, 'is_partitioned(sch, part)', 'Table public.apart should be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( 'apart', 'yowza' ), true, 'is_partitioned(part, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_partitioned( 'apart' ), true, 'is_partitioned(part)', 'Table apart should be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE FOR tap IN SELECT * FROM check_test( has_view( '__SDFSDFD__' ), false, 'is_partitioned(non-existent part)', 'View "__SDFSDFD__" should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( '__SDFSDFD__', 'howdy' ), false, 'is_partitioned(non-existent part, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'foo', '__SDFSDFD__', 'desc' ), false, 'is_partitioned(sch, non-existent part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'information_schema', 'tables', 'desc' ), true, 'is_partitioned(sch, part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'information_schema', 'tables', 'desc' ), true, 'is_partitioned(sch, part)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'information_schema', 'tables', 'desc' ), true, 'is_partitioned(part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( has_view( 'pg_tables' ), true, 'is_partitioned(part)', 'View pg_tables should exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ language PLPGSQL; /****************************************************************************/ -- Test isnt_partitioned(). CREATE FUNCTION test_isnt_partitioned() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 100000 THEN FOR tap IN SELECT * FROM check_test( isnt_partitioned( '__SDFSDFD__' ), true, 'isnt_partitioned(non-existent part)', 'Table "__SDFSDFD__" should not be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( '__SDFSDFD__', 'howdy' ), true, 'isnt_partitioned(non-existent part, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( 'foo', '__SDFSDFD__', 'desc' ), true, 'isnt_partitioned(sch, non-existent part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( 'public', 'apart', 'desc' ), false, 'isnt_partitioned(sch, part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( 'public', 'apart'::name ), false, 'isnt_partitioned(sch, part)', 'Table public.apart should not be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( 'apart', 'yowza'::text ), false, 'isnt_partitioned(part, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( isnt_partitioned( 'apart' ), false, 'isnt_partitioned(part)', 'Table apart should not be partitioned', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; else FOR tap IN SELECT * FROM check_test( hasnt_view( '__SDFSDFD__' ), true, 'isnt_partitioned(non-existent part)', 'View "__SDFSDFD__" should not exist', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( '__SDFSDFD__', 'howdy' ), true, 'isnt_partitioned(non-existent part, desc)', 'howdy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'foo', '__SDFSDFD__', 'desc' ), true, 'isnt_partitioned(sch, non-existent part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'information_schema', 'tables', 'desc' ), false, 'isnt_partitioned(sch, part, desc)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'information_schema', 'tables', 'desc' ), false, 'isnt_partitioned(sch, part)', 'desc', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'pg_tables', 'yowza' ), false, 'isnt_partitioned(part, desc)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( hasnt_view( 'pg_tables', 'yowza' ), false, 'isnt_partitioned(part)', 'yowza', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ language PLPGSQL; SELECT * FROM test_is_partitioned(); SELECT * FROM test_isnt_partitioned(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/index.sql000066400000000000000000000437541455775703000162700ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(270); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), myint NUMERIC(8) ); CREATE INDEX idx_hey ON public.sometab(numb); SET client_min_messages = error; CREATE INDEX idx_foo ON public.sometab using hash(name); SET client_min_messages = warning; CREATE INDEX idx_bar ON public.sometab(numb, name); CREATE UNIQUE INDEX idx_baz ON public.sometab(LOWER(name)); CREATE INDEX idx_mul ON public.sometab(numb, LOWER(name)); CREATE INDEX idx_expr ON public.sometab(UPPER(name), numb, LOWER(name)); CREATE INDEX idx_double ON public.sometab(numb, myint); RESET client_min_messages; /****************************************************************************/ -- Test has_index(). SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_hey', 'numb', 'whatever' ), true, 'has_index() single column', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_hey', 'numb'::name ), true, 'has_index() single column no desc', 'Index idx_hey should exist', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_foo', 'name', 'whatever' ), true, 'has_index() hash index', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_foo', 'name'::name ), true, 'has_index() hash index no desc', 'Index idx_foo should exist', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_bar', ARRAY['numb', 'name'], 'whatever' ), true, 'has_index() multi-column', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_bar', ARRAY['numb', 'name'] ), true, 'has_index() multi-column no desc', 'Index idx_bar should exist', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_baz', 'lower(name)', 'whatever' ), true, 'has_index() functional', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_baz', ARRAY['lower(name)'], 'whatever' ), true, 'has_index() [functional]', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_mul', ARRAY['numb', 'lower(name)'], 'whatever' ), true, 'has_index() [col, expr]', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_expr', ARRAY['upper(name)', 'numb', 'lower(name)'], 'whatever' ), true, 'has_index() [expr, col, expr]', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_baz', 'whatever' ), true, 'has_index() no cols', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_foo', 'whatever' ), true, 'has_index() hash index', 'whatever', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_baz'::name ), true, 'has_index() no cols no desc', 'Index idx_baz should exist', '' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_foo'::name ), true, 'has_index() no cols hash index no desc', 'Index idx_foo should exist', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_foo', 'name', 'whatever' ), true, 'has_index() no schema single column', 'whatever', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_foo', 'name'::name ), true, 'has_index() no schema single column no desc', 'Index idx_foo should exist', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_bar', ARRAY['numb', 'name'], 'whatever' ), true, 'has_index() no schema multi-column', 'whatever', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_bar', ARRAY['numb', 'name'] ), true, 'has_index() no schema multi-column no desc', 'Index idx_bar should exist', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_baz', 'lower(name)', 'whatever' ), true, 'has_index() no schema functional', 'whatever', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_baz', 'lower(name)' ), true, 'has_index() no schema functional no desc', 'Index idx_baz should exist', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_baz', 'whatever' ), true, 'has_index() no schema or cols', 'whatever', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_foo', 'whatever' ), true, 'has_index() hash index no schema or cols', 'whatever', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_baz' ), true, 'has_index() no schema or cols or desc', 'Index idx_baz should exist', '' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_foo' ), true, 'has_index() hash index no schema or cols or desc', 'Index idx_foo should exist', '' ); -- Check failure diagnostics. SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_heya', 'numb', 'whatever' ), false, 'has_index() non-existent', 'whatever', 'Index idx_heya ON public.sometab not found' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'blah', ARRAY['numb', 'name'], 'whatever' ), false, 'has_index() missing', 'whatever', 'Index blah ON public.sometab not found' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_bar', ARRAY['name', 'id'], 'whatever' ), false, 'has_index() invalid', 'whatever', ' have: idx_bar ON public.sometab(numb, name) want: idx_bar ON public.sometab(name, id)' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_bar', ARRAY['name'], 'whatever' ), false, 'has_index() missing column', 'whatever', ' have: idx_bar ON public.sometab(numb, name) want: idx_bar ON public.sometab(name)' ); SELECT * FROM check_test( has_index( 'sometab', 'blah', ARRAY['numb', 'name'], 'whatever' ), false, 'has_index() missing no schema', 'whatever', 'Index blah ON sometab not found' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_bar', ARRAY['name', 'id'], 'whatever' ), false, 'has_index() invalid no schema', 'whatever', ' have: idx_bar ON sometab(numb, name) want: idx_bar ON sometab(name, id)' ); SELECT * FROM check_test( has_index( 'public', 'sometab', 'idx_baz', 'lower(wank)', 'whatever' ), false, 'has_index() functional fail', 'whatever', ' have: idx_baz ON public.sometab(lower(name)) want: idx_baz ON public.sometab(lower(wank))' ); SELECT * FROM check_test( has_index( 'sometab', 'idx_baz', 'lower(wank)', 'whatever' ), false, 'has_index() functional fail no schema', 'whatever', ' have: idx_baz ON sometab(lower(name)) want: idx_baz ON sometab(lower(wank))' ); /****************************************************************************/ -- Test hasnt_index(). SELECT * FROM check_test( hasnt_index( 'public', 'sometab', 'idx_foo', 'whatever' ), false, 'hasnt_index(schema, table, index, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_index( 'public', 'sometab', 'idx_foo'::name ), false, 'hasnt_index(schema, table, index)', 'Index idx_foo should not exist', '' ); SELECT * FROM check_test( hasnt_index( 'public', 'sometab', 'idx_blah', 'whatever' ), true, 'hasnt_index(schema, table, non-index, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_index( 'public', 'sometab', 'idx_blah'::name ), true, 'hasnt_index(schema, table, non-index)', 'Index idx_blah should not exist', '' ); SELECT * FROM check_test( hasnt_index( 'sometab', 'idx_foo', 'whatever' ), false, 'hasnt_index(table, index, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_index( 'sometab', 'idx_foo'::name ), false, 'hasnt_index(table, index)', 'Index idx_foo should not exist', '' ); SELECT * FROM check_test( hasnt_index( 'sometab', 'idx_blah', 'whatever' ), true, 'hasnt_index(table, non-index, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_index( 'sometab', 'idx_blah'::name ), true, 'hasnt_index(table, non-index)', 'Index idx_blah should not exist', '' ); /****************************************************************************/ -- Test index_is_unique(). SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'idx_baz', 'whatever' ), true, 'index_is_unique()', 'whatever', '' ); SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'idx_baz' ), true, 'index_is_unique() no desc', 'Index idx_baz should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'sometab', 'idx_baz' ), true, 'index_is_unique() no schema', 'Index idx_baz should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'idx_baz' ), true, 'index_is_unique() index only', 'Index idx_baz should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'sometab_pkey', 'whatever' ), true, 'index_is_unique() on pk', 'whatever', '' ); SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'sometab_pkey' ), true, 'index_is_unique() on pk no desc', 'Index sometab_pkey should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'sometab', 'sometab_pkey' ), true, 'index_is_unique() on pk no schema', 'Index sometab_pkey should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'sometab_pkey' ), true, 'index_is_unique() on pk index only', 'Index sometab_pkey should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'idx_bar', 'whatever' ), false, 'index_is_unique() fail', 'whatever', '' ); SELECT * FROM check_test( index_is_unique( 'public', 'sometab', 'idx_bar' ), false, 'index_is_unique() fail no desc', 'Index idx_bar should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'sometab', 'idx_bar' ), false, 'index_is_unique() fail no schema', 'Index idx_bar should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'idx_bar' ), false, 'index_is_unique() fail index only', 'Index idx_bar should be unique', '' ); SELECT * FROM check_test( index_is_unique( 'blahblah' ), false, 'index_is_unique() no such index', 'Index blahblah should be unique', '' ); /****************************************************************************/ -- Test index_is_primary(). SELECT * FROM check_test( index_is_primary( 'public', 'sometab', 'sometab_pkey', 'whatever' ), true, 'index_is_primary()', 'whatever', '' ); SELECT * FROM check_test( index_is_primary( 'public', 'sometab', 'sometab_pkey' ), true, 'index_is_primary() no desc', 'Index sometab_pkey should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'sometab', 'sometab_pkey' ), true, 'index_is_primary() no schema', 'Index sometab_pkey should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'sometab_pkey' ), true, 'index_is_primary() index only', 'Index sometab_pkey should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'public', 'sometab', 'idx_baz', 'whatever' ), false, 'index_is_primary() fail', 'whatever', '' ); SELECT * FROM check_test( index_is_primary( 'public', 'sometab', 'idx_baz' ), false, 'index_is_primary() fail no desc', 'Index idx_baz should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'sometab', 'idx_baz' ), false, 'index_is_primary() fail no schema', 'Index idx_baz should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'idx_baz' ), false, 'index_is_primary() fail index only', 'Index idx_baz should be on a primary key', '' ); SELECT * FROM check_test( index_is_primary( 'blahblah' ), false, 'index_is_primary() no such index', 'Index blahblah should be on a primary key', '' ); /****************************************************************************/ -- Test is_clustered(). SELECT * FROM check_test( is_clustered( 'public', 'sometab', 'idx_bar', 'whatever' ), false, 'is_clustered() fail', 'whatever', '' ); SELECT * FROM check_test( is_clustered( 'public', 'sometab', 'idx_bar' ), false, 'is_clustered() fail no desc', 'Table public.sometab should be clustered on index idx_bar', '' ); SELECT * FROM check_test( is_clustered( 'sometab', 'idx_bar' ), false, 'is_clustered() fail no schema', 'Table sometab should be clustered on index idx_bar', '' ); SELECT * FROM check_test( is_clustered( 'idx_bar' ), false, 'is_clustered() fail index only', 'Table should be clustered on index idx_bar', '' ); CLUSTER idx_bar ON public.sometab; SELECT * FROM check_test( is_clustered( 'public', 'sometab', 'idx_bar', 'whatever' ), true, 'is_clustered()', 'whatever', '' ); SELECT * FROM check_test( is_clustered( 'public', 'sometab', 'idx_bar' ), true, 'is_clustered() no desc', 'Table public.sometab should be clustered on index idx_bar', '' ); SELECT * FROM check_test( is_clustered( 'sometab', 'idx_bar' ), true, 'is_clustered() no schema', 'Table sometab should be clustered on index idx_bar', '' ); SELECT * FROM check_test( is_clustered( 'idx_bar' ), true, 'is_clustered() index only', 'Table should be clustered on index idx_bar', '' ); /****************************************************************************/ -- Test index_is_type(). SELECT * FROM check_test( index_is_type( 'public', 'sometab', 'idx_bar', 'btree', 'whatever' ), true, 'index_is_type()', 'whatever', '' ); SELECT * FROM check_test( index_is_type( 'public', 'sometab', 'idx_bar', 'btree' ), true, 'index_is_type() no desc', 'Index idx_bar should be a btree index', '' ); SELECT * FROM check_test( index_is_type( 'public', 'sometab', 'idx_bar', 'hash' ), false, 'index_is_type() fail', 'Index idx_bar should be a hash index', ' have: btree want: hash' ); SELECT * FROM check_test( index_is_type( 'sometab', 'idx_bar', 'btree' ), true, 'index_is_type() no schema', 'Index idx_bar should be a btree index', '' ); SELECT * FROM check_test( index_is_type( 'sometab', 'idx_bar', 'hash' ), false, 'index_is_type() no schema fail', 'Index idx_bar should be a hash index', ' have: btree want: hash' ); SELECT * FROM check_test( index_is_type( 'idx_bar', 'btree' ), true, 'index_is_type() no table', 'Index idx_bar should be a btree index', '' ); SELECT * FROM check_test( index_is_type( 'idx_bar', 'hash' ), false, 'index_is_type() no table fail', 'Index idx_bar should be a hash index', ' have: btree want: hash' ); SELECT * FROM check_test( index_is_type( 'idx_foo', 'hash' ), true, 'index_is_type() hash', 'Index idx_foo should be a hash index', '' ); /****************************************************************************/ -- Test is_indexed(). SELECT * FROM check_test( is_indexed( 'public', 'sometab', ARRAY['numb','name']::name[], 'desc' ), true, 'is_indexed( schema, table, columns[], description )', 'desc', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab', ARRAY['numb','name']::name[] ), true, 'is_indexed( schema, table, columns[] )', 'Should have an index on public.sometab(numb, name)', '' ); SELECT * FROM check_test( is_indexed( 'sometab', ARRAY['numb','name']::name[], 'desc' ), true, 'is_indexed( table, columns[], description )', 'desc', '' ); SELECT * FROM check_test( is_indexed( 'sometab', ARRAY['numb','name']::name[] ), true, 'is_indexed( table, columns[] )', 'Should have an index on sometab(numb, name)', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab', 'numb', 'desc' ), true, 'is_indexed( schema, table, column, description )', 'desc', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab'::name, 'numb'::name ), true, 'is_indexed( schema, table, column )', 'Should have an index on public.sometab(numb)', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab'::name, 'myint'::name ), false, 'is_indexed( schema, table, column ) fail', 'Should have an index on public.sometab(myint)', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab', ARRAY['name','numb']::name[] ), false, 'is_indexed( schema, table, columns[] ) fail, column order matters', 'Should have an index on public.sometab(name, numb)', '' ); -- Make sure index expressions are supported. SELECT * FROM check_test( is_indexed( 'public', 'sometab', ARRAY['upper(name)', 'numb', 'lower(name)'], 'whatever' ), true, 'is_indexed(schema, table, expressions)', 'whatever', '' ); SELECT * FROM check_test( is_indexed( 'public', 'sometab', 'lower(name)', 'whatever' ), true, 'is_indexed(schema, table, expression)', 'whatever', '' ); SELECT * FROM check_test( is_indexed( 'sometab', ARRAY['upper(name)', 'numb', 'lower(name)'], 'whatever' ), true, 'is_indexed(table, expressions)', 'whatever', '' ); SELECT * FROM check_test( is_indexed( 'sometab', 'lower(name)'::name, 'whatever' ), true, 'is_indexed( table, expression)', 'whatever', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/inheritance.sql000066400000000000000000000657271455775703000174560ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan( 408 ); -- SELECT * FROM no_plan(); SET client_min_messages = warning; -- Create inherited tables CREATE TABLE public.parent( id INT PRIMARY KEY ); CREATE TABLE public.child1( id INT PRIMARY KEY ) INHERITS ( public.parent ); CREATE TABLE public.child2( id INT PRIMARY KEY ) INHERITS ( public.child1 ); -- Create inherited tables in another schema CREATE SCHEMA hide; CREATE TABLE hide.h_parent( id INT PRIMARY KEY ); CREATE TABLE hide.h_child1( id INT PRIMARY KEY ) INHERITS ( hide.h_parent ); CREATE TABLE hide.h_child2( id INT PRIMARY KEY ) INHERITS ( hide.h_child1 ); -- test has_inhereted_tables SELECT * FROM check_test( has_inherited_tables( 'hide', 'h_parent', 'Gimme inheritance' ), true, 'has_inherited_tables(sch, tab, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( has_inherited_tables( 'hide', 'h_child2', 'Gimme inheritance' ), false, 'has_inherited_tables(sch, tab, desc) fail', 'Gimme inheritance', '' ); SELECT * FROM check_test( has_inherited_tables( 'hide', 'nonesuch', 'Gimme inheritance' ), false, 'has_inherited_tables(sch, nonesuch, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( has_inherited_tables( 'hide', 'h_parent'::name ), true, 'has_inherited_tables(sch, tab)', 'Table hide.h_parent should have descendents', '' ); SELECT * FROM check_test( has_inherited_tables( 'hide', 'h_child2'::name ), false, 'has_inherited_tables(sch, tab) fail', 'Table hide.h_child2 should have descendents', '' ); SELECT * FROM check_test( has_inherited_tables( 'hide', 'nonesuch'::name ), false, 'has_inherited_tables(sch, nonesuch)', 'Table hide.nonesuch should have descendents', '' ); SELECT * FROM check_test( has_inherited_tables( 'parent', 'Gimme more' ), true, 'has_inherited_tables(tab, desc)', 'Gimme more', '' ); SELECT * FROM check_test( has_inherited_tables( 'child2', 'Gimme more' ), false, 'has_inherited_tables(tab, desc) fail', 'Gimme more', '' ); SELECT * FROM check_test( has_inherited_tables( 'nonesuch', 'Gimme more' ), false, 'has_inherited_tables(nonesuch, desc)', 'Gimme more', '' ); SELECT * FROM check_test( has_inherited_tables( 'parent' ), true, 'has_inherited_tables(tab)', 'Table parent should have descendents', '' ); SELECT * FROM check_test( has_inherited_tables( 'child2' ), false, 'has_inherited_tables(tab) fail', 'Table child2 should have descendents', '' ); SELECT * FROM check_test( has_inherited_tables( 'nonesuch' ), false, 'has_inherited_tables(nonesuch)', 'Table nonesuch should have descendents', '' ); -- test hasnt_inherited_tables SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'h_child2', 'Gimme inheritance' ), true, 'hasnt_inherited_tables(sch, tab, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'h_child1', 'Gimme inheritance' ), false, 'hasnt_inherited_tables(sch, tab, desc) fail', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'nonesuch', 'Gimme inheritance' ), true, 'hasnt_inherited_tables(sch, nonesuch, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'h_child2'::name ), true, 'hasnt_inherited_tables(sch, tab)', 'Table hide.h_child2 should not have descendents', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'h_child1'::name ), false, 'hasnt_inherited_tables(sch, tab) fail', 'Table hide.h_child1 should not have descendents', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'hide', 'nonesuch'::name ), true, 'hasnt_inherited_tables(sch, nonesuch)', 'Table hide.nonesuch should not have descendents', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'child2', 'Gimme inheritance' ), true, 'hasnt_inherited_tables(tab, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'child1', 'Gimme inheritance' ), false, 'hasnt_inherited_tables(tab, desc) fail', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'nonesuch', 'Gimme inheritance' ), true, 'hasnt_inherited_tables(nonesuch, desc)', 'Gimme inheritance', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'child2' ), true, 'hasnt_inherited_tables(tab)', 'Table child2 should not have descendents', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'child1' ), false, 'hasnt_inherited_tables(tab) fail', 'Table child1 should not have descendents', '' ); SELECT * FROM check_test( hasnt_inherited_tables( 'nonesuch' ), true, 'hasnt_inherited_tables(nonesuch)', 'Table nonesuch should not have descendents', '' ); -- test is_ancestor_of SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 1, 'Lookie' ), true, 'is_ancestor_of(psch, ptab, csch, ctab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 2, 'Lookie' ), true, 'is_ancestor_of(psch, ptab, csch, ctab, 2, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'nope', 'h_child2', 1, 'Lookie' ), false, 'is_ancestor_of(psch, nope, csch, ctab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 1, 'Lookie' ), false, 'is_ancestor_of(psch, ptab, csch, nope, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 1 ), true, 'is_ancestor_of(psch, ptab, csch, ctab, 1)', 'Table hide.h_parent should be ancestor 1 for hide.h_child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'nope', 'hide', 'h_child1', 1 ), false, 'is_ancestor_of(psch, nope, csch, ctab, 1)', 'Table hide.nope should be ancestor 1 for hide.h_child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 1 ), false, 'is_ancestor_of(psch, ptab, csch, nope, 1)', 'Table hide.h_parent should be ancestor 1 for hide.nope', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 2 ), true, 'is_ancestor_of(psch, ptab, csch, ctab, 2)', 'Table hide.h_parent should be ancestor 2 for hide.h_child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'nope', 'hide', 'h_child2', 2 ), false, 'is_ancestor_of(psch, nope, csch, ctab, 2)', 'Table hide.nope should be ancestor 2 for hide.h_child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 2 ), false, 'is_ancestor_of(psch, ptab, csch, nope, 2)', 'Table hide.h_parent should be ancestor 2 for hide.nope', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 'Howdy' ), true, 'is_ancestor_of(psch, ptab, csch, ctab, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 'Howdy' ), true, 'is_ancestor_of(psch, ptab, csch, ctab2, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1'::name ), true, 'is_ancestor_of(psch, ptab, csch, ctab)', 'Table hide.h_parent should be an ancestor of hide.h_child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2'::name ), true, 'is_ancestor_of(psch, ptab, csch, ctab2)', 'Table hide.h_parent should be an ancestor of hide.h_child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'nope', 'hide', 'h_child1'::name ), false, 'is_ancestor_of(psch, nope, csch, ctab)', 'Table hide.nope should be an ancestor of hide.h_child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'hide', 'h_parent', 'hide', 'nope'::name ), false, 'is_ancestor_of(psch, ptab, csch, nope)', 'Table hide.h_parent should be an ancestor of hide.nope', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child1', 1, 'Howdy' ), true, 'is_ancestor_of(ptab, ctab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child2', 2, 'Howdy' ), true, 'is_ancestor_of(ptab, ctab, 2, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child2', 1, 'Howdy' ), false, 'is_ancestor_of(ptab, ctab, 1, desc) fail', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'nope', 1, 'Howdy' ), false, 'is_ancestor_of(ptab, nope, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child1', 1 ), true, 'is_ancestor_of(ptab, ctab, 1)', 'Table parent should be ancestor 1 of child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child2', 2 ), true, 'is_ancestor_of(ptab, ctab, 2)', 'Table parent should be ancestor 2 of child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child2', 1 ), false, 'is_ancestor_of(ptab, ctab, 1) fail', 'Table parent should be ancestor 1 of child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'nope', 1 ), false, 'is_ancestor_of(ptab, nope, 1)', 'Table parent should be ancestor 1 of nope', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child1' ), true, 'is_ancestor_of(ptab, ctab)', 'Table parent should be an ancestor of child1', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'child2' ), true, 'is_ancestor_of(ptab, ctab2)', 'Table parent should be an ancestor of child2', '' ); SELECT * FROM check_test( is_ancestor_of( 'parent', 'nope' ), false, 'is_ancestor_of(ptab, nope)', 'Table parent should be an ancestor of nope', '' ); SELECT * FROM check_test( is_ancestor_of( 'nope', 'child1' ), false, 'is_ancestor_of(nope, ctab2)', 'Table nope should be an ancestor of child1', '' ); -- test isnt_ancestor_of SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 1, 'Lookie' ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 2, 'Lookie' ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab, 2, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'nope', 'h_child2', 1, 'Lookie' ), true, 'isnt_ancestor_of(psch, nope, csch, ctab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 1, 'Lookie' ), true, 'isnt_ancestor_of(psch, ptab, csch, nope, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 1 ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab, 1)', 'Table hide.h_parent should not be ancestor 1 for hide.h_child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'nope', 'hide', 'h_child1', 1 ), true, 'isnt_ancestor_of(psch, nope, csch, ctab, 1)', 'Table hide.nope should not be ancestor 1 for hide.h_child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 1 ), true, 'isnt_ancestor_of(psch, ptab, csch, nope, 1)', 'Table hide.h_parent should not be ancestor 1 for hide.nope', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 2 ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab, 2)', 'Table hide.h_parent should not be ancestor 2 for hide.h_child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'nope', 'hide', 'h_child2', 2 ), true, 'isnt_ancestor_of(psch, nope, csch, ctab, 2)', 'Table hide.nope should not be ancestor 2 for hide.h_child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'nope', 2 ), true, 'isnt_ancestor_of(psch, ptab, csch, nope, 2)', 'Table hide.h_parent should not be ancestor 2 for hide.nope', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1', 'Howdy' ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2', 'Howdy' ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab2, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child1'::name ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab)', 'Table hide.h_parent should not be an ancestor of hide.h_child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'h_child2'::name ), false, 'isnt_ancestor_of(psch, ptab, csch, ctab2)', 'Table hide.h_parent should not be an ancestor of hide.h_child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'nope', 'hide', 'h_child1'::name ), true, 'isnt_ancestor_of(psch, nope, csch, ctab)', 'Table hide.nope should not be an ancestor of hide.h_child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'hide', 'h_parent', 'hide', 'nope'::name ), true, 'isnt_ancestor_of(psch, ptab, csch, nope)', 'Table hide.h_parent should not be an ancestor of hide.nope', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child1', 1, 'Howdy' ), false, 'isnt_ancestor_of(ptab, ctab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child2', 2, 'Howdy' ), false, 'isnt_ancestor_of(ptab, ctab, 2, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child2', 1, 'Howdy' ), true, 'isnt_ancestor_of(ptab, ctab, 1, desc) fail', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'nope', 1, 'Howdy' ), true, 'isnt_ancestor_of(ptab, nope, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child1', 1 ), false, 'isnt_ancestor_of(ptab, ctab, 1)', 'Table parent should not be ancestor 1 of child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child2', 2 ), false, 'isnt_ancestor_of(ptab, ctab, 2)', 'Table parent should not be ancestor 2 of child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child2', 1 ), true, 'isnt_ancestor_of(ptab, ctab, 1) fail', 'Table parent should not be ancestor 1 of child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'nope', 1 ), true, 'isnt_ancestor_of(ptab, nope, 1)', 'Table parent should not be ancestor 1 of nope', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child1' ), false, 'isnt_ancestor_of(ptab, ctab)', 'Table parent should not be an ancestor of child1', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'child2' ), false, 'isnt_ancestor_of(ptab, ctab2)', 'Table parent should not be an ancestor of child2', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'parent', 'nope' ), true, 'isnt_ancestor_of(ptab, nope)', 'Table parent should not be an ancestor of nope', '' ); SELECT * FROM check_test( isnt_ancestor_of( 'nope', 'child1' ), true, 'isnt_ancestor_of(nope, ctab2)', 'Table nope should not be an ancestor of child1', '' ); -- test is_descendent_of SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 1, 'Lookie' ), true, 'is_descendent_of(csch, ctab, psch, ptab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 2, 'Lookie' ), true, 'is_descendent_of(csch, ctab, psch, ptab, 2, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_descendent_of( 'nope', 'h_child2', 'hide', 'h_parent', 1, 'Lookie' ), false, 'is_descendent_of(csch, ctab, psch, nope, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 1, 'Lookie' ), false, 'is_descendent_of(csch, nope, psch, ptab, desc)', 'Lookie', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 1 ), true, 'is_descendent_of(csch, ctab, psch, ptab, 1)', 'Table hide.h_child1 should be descendent 1 from hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'nope', 1 ), false, 'is_descendent_of(csch, ctab, psch, nope, 1)', 'Table hide.h_child1 should be descendent 1 from hide.nope', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 1 ), false, 'is_descendent_of(csch, nope, psch, ptab, 1)', 'Table hide.nope should be descendent 1 from hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 2 ), true, 'is_descendent_of(csch, ctab, psch, ptab, 2)', 'Table hide.h_child2 should be descendent 2 from hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child2', 'hide', 'nope', 2 ), false, 'is_descendent_of(csch, ctab, psch, nope, 2)', 'Table hide.h_child2 should be descendent 2 from hide.nope', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 2 ), false, 'is_descendent_of(csch, nope, psch, ptab, 2)', 'Table hide.nope should be descendent 2 from hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 'Howdy' ), true, 'is_descendent_of(csch, ctab, psch, ptab, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 'Howdy' ), true, 'is_descendent_of(csch, ctab2, psch, ptab, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent'::name ), true, 'is_descendent_of(csch, ctab, psch, ptab)', 'Table hide.h_child1 should be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent'::name ), true, 'is_descendent_of(csch, ctab2, psch, ptab)', 'Table hide.h_child2 should be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'h_child1', 'hide', 'nope'::name ), false, 'is_descendent_of(csch, ctab, psch, nope)', 'Table hide.h_child1 should be a descendent of hide.nope', '' ); SELECT * FROM check_test( is_descendent_of( 'hide', 'nope', 'hide', 'h_parent'::name ), false, 'is_descendent_of(csch, nope, psch, ptab)', 'Table hide.nope should be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child1', 'parent', 1, 'Howdy' ), true, 'is_descendent_of(ctab, ptab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'child2', 'parent', 2, 'Howdy' ), true, 'is_descendent_of(ctab, ptab, 2, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'child2', 'parent', 1, 'Howdy' ), false, 'is_descendent_of(ctab, ptab, 1, desc) fail', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'nope', 'parent', 1, 'Howdy' ), false, 'is_descendent_of(nope, ptab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( is_descendent_of( 'child1', 'parent', 1 ), true, 'is_descendent_of(ctab, ptab, 1)', 'Table child1 should be descendent 1 from parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child2', 'parent', 2 ), true, 'is_descendent_of(ctab, ptab, 2)', 'Table child2 should be descendent 2 from parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child2', 'parent', 1 ), false, 'is_descendent_of(ctab, ptab, 1) fail', 'Table child2 should be descendent 1 from parent', '' ); SELECT * FROM check_test( is_descendent_of( 'nope', 'parent', 1 ), false, 'is_descendent_of(nope, ptab, 1)', 'Table nope should be descendent 1 from parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child1', 'parent' ), true, 'is_descendent_of(ctab, ptab)', 'Table child1 should be a descendent of parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child2', 'parent' ), true, 'is_descendent_of( ctab2, ptab )', 'Table child2 should be a descendent of parent', '' ); SELECT * FROM check_test( is_descendent_of( 'nope', 'parent' ), false, 'is_descendent_of(nope, ptab)', 'Table nope should be a descendent of parent', '' ); SELECT * FROM check_test( is_descendent_of( 'child1', 'nope' ), false, 'is_descendent_of(ctab2, nope)', 'Table child1 should be a descendent of nope', '' ); -- test isnt_descendent_of SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 1, 'Lookie' ), false, 'isnt_descendent_of(csch, ctab, psch, ptab, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 2, 'Lookie' ), false, 'isnt_descendent_of(csch, ctab, psch, ptab, 2, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_descendent_of( 'nope', 'h_child2', 'hide', 'h_parent', 1, 'Lookie' ), true, 'isnt_descendent_of(csch, ctab, psch, nope, 1, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 1, 'Lookie' ), true, 'isnt_descendent_of(csch, nope, psch, ptab, desc)', 'Lookie', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 1 ), false, 'isnt_descendent_of(csch, ctab, psch, ptab, 1)', 'Table hide.h_child1 should not be descendent 1 from hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'nope', 1 ), true, 'isnt_descendent_of(csch, ctab, psch, nope, 1)', 'Table hide.h_child1 should not be descendent 1 from hide.nope', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 1 ), true, 'isnt_descendent_of(csch, nope, psch, ptab, 1)', 'Table hide.nope should not be descendent 1 from hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 2 ), false, 'isnt_descendent_of(csch, ctab, psch, ptab, 2)', 'Table hide.h_child2 should not be descendent 2 from hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child2', 'hide', 'nope', 2 ), true, 'isnt_descendent_of(csch, ctab, psch, nope, 2)', 'Table hide.h_child2 should not be descendent 2 from hide.nope', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'nope', 'hide', 'h_parent', 2 ), true, 'isnt_descendent_of(csch, nope, psch, ptab, 2)', 'Table hide.nope should not be descendent 2 from hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent', 'Howdy' ), false, 'isnt_descendent_of(csch, ctab, psch, ptab, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent', 'Howdy' ), false, 'isnt_descendent_of(csch, ctab2, psch, ptab, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'h_parent'::name ), false, 'isnt_descendent_of(csch, ctab, psch, ptab)', 'Table hide.h_child1 should not be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child2', 'hide', 'h_parent'::name ), false, 'isnt_descendent_of(csch, ctab2, psch, ptab)', 'Table hide.h_child2 should not be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'h_child1', 'hide', 'nope'::name ), true, 'isnt_descendent_of(csch, ctab, psch, nope)', 'Table hide.h_child1 should not be a descendent of hide.nope', '' ); SELECT * FROM check_test( isnt_descendent_of( 'hide', 'nope', 'hide', 'h_parent'::name ), true, 'isnt_descendent_of(csch, nope, psch, ptab)', 'Table hide.nope should not be a descendent of hide.h_parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child1', 'parent', 1, 'Howdy' ), false, 'isnt_descendent_of(ctab, ptab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child2', 'parent', 2, 'Howdy' ), false, 'isnt_descendent_of(ctab, ptab, 2, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child2', 'parent', 1, 'Howdy' ), true, 'isnt_descendent_of(ctab, ptab, 1, desc) fail', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'nope', 'parent', 1, 'Howdy' ), true, 'isnt_descendent_of(nope, ptab, 1, desc)', 'Howdy', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child1', 'parent', 1 ), false, 'isnt_descendent_of(ctab, ptab, 1)', 'Table child1 should not be descendent 1 from parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child2', 'parent', 2 ), false, 'isnt_descendent_of(ctab, ptab, 2)', 'Table child2 should not be descendent 2 from parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child2', 'parent', 1 ), true, 'isnt_descendent_of(ctab, ptab, 1) fail', 'Table child2 should not be descendent 1 from parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'nope', 'parent', 1 ), true, 'isnt_descendent_of(nope, ptab, 1)', 'Table nope should not be descendent 1 from parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child1', 'parent' ), false, 'isnt_descendent_of(ctab, ptab)', 'Table child1 should not be a descendent of parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child2', 'parent' ), false, 'isnt_descendent_of( ctab2, ptab )', 'Table child2 should not be a descendent of parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'nope', 'parent' ), true, 'isnt_descendent_of(nope, ptab)', 'Table nope should not be a descendent of parent', '' ); SELECT * FROM check_test( isnt_descendent_of( 'child1', 'nope' ), true, 'isnt_descendent_of(ctab2, nope)', 'Table child1 should not be a descendent of nope', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/istap.sql000066400000000000000000000052061455775703000162670ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(47); --SELECT * from no_plan(); /****************************************************************************/ -- Test is(). SELECT * FROM check_test( is(1, 1), true, 'is(1, 1)', '', '' ); SELECT * FROM check_test( is('x'::text, 'x'::text), true, 'is(''x'', ''x'')', '', '' ); SELECT * FROM check_test( is(1.1, 1.10), true, 'is(1.1, 1.10)', '', '' ); SELECT * FROM check_test( is(true, true), true, 'is(true, true)', '', '' ); SELECT * FROM check_test( is(false, false), true, 'is(false, false)', '', '' ); SELECT * FROM check_test( is(1, 1, 'foo'), true, 'is(1, 1, desc)', 'foo', '' ); SELECT * FROM check_test( is( 1, 2 ), false, 'is(1, 2)', '', ' have: 1 want: 2'); /****************************************************************************/ -- Test isnt(). SELECT * FROM check_test( isnt(1, 2), true, 'isnt(1, 2)', '', '' ); SELECT * FROM check_test( isnt( 1, 1 ), false, 'isnt(1, 1)', '', ' have: 1 want: anything else' ); /****************************************************************************/ -- Try using variables. \set foo '\'' waffle '\'' \set bar '\'' waffle '\'' SELECT is( :foo::text, :bar::text, 'is() should work with psql variables' ); /****************************************************************************/ -- Try using NULLs. SELECT * FROM check_test( is( NULL::text, NULL::text, 'NULLs' ), true, 'is(NULL, NULL)', 'NULLs', '' ); SELECT * FROM check_test( is( NULL::text, 'foo' ), false, 'is(NULL, foo)', '', ' have: NULL want: foo' ); SELECT * FROM check_test( is( 'foo', NULL::text ), false, 'is(foo, NULL)', '', ' have: foo want: NULL' ); SET client_min_messages = warning; CREATE TABLE mumble ( id int, name text ); RESET client_min_messages; INSERT INTO mumble VALUES (1, 'hey'); SELECT is( mumble.*, ROW(1, 'hey')::mumble, 'with records!' ) FROM mumble; SELECT check_test( is( mumble.*, ROW(1, 'HEY')::mumble ), false, 'is(mumble, row) fail', '', ' have: (1,hey) want: (1,HEY)' ) FROM mumble; SELECT check_test( is( mumble.*, ROW(1, NULL)::mumble ), false, 'is(mumble, row) fail with NULL', '', ' have: (1,hey) want: (1,)' ) FROM mumble; SELECT check_test( is( mumble.*, NULL::mumble ), false, 'is(mumble, NULL)', '', ' have: (1,hey) want: NULL' ) FROM mumble; /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(false); -- Arbitrarily decided to test `finish(false)` here... :) ROLLBACK; pgtap-1.3.2/test/sql/matching.sql000066400000000000000000000040751455775703000167440ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(24); /****************************************************************************/ -- Test matches(). SELECT matches( 'foo'::text, 'o', 'matches() should work' ); SELECT matches( 'foo'::text, '^fo', 'matches() should work with a regex' ); SELECT imatches( 'FOO'::text, '^fo', 'imatches() should work with a regex' ); -- Check matches() diagnostics. SELECT * FROM check_test( matches( 'foo'::text, '^a' ), false, 'matches() fail', '', ' ''foo'' doesn''t match: ''^a''' ); -- Check doesnt_match. SELECT doesnt_match( 'foo'::text, 'a', 'doesnt_match() should work' ); SELECT doesnt_match( 'foo'::text, '^o', 'doesnt_match() should work with a regex' ); SELECT doesnt_imatch( 'foo'::text, '^o', 'doesnt_imatch() should work with a regex' ); -- Check doesnt_match diagnostics. SELECT * FROM check_test( doesnt_match( 'foo'::text, 'o' ), false, 'doesnt_match() fail', '', ' ''foo'' matches: ''o''' ); /****************************************************************************/ -- Test alike(). SELECT alike( 'foo'::text, 'foo', 'alike() should work' ); SELECT alike( 'foo'::text, 'fo%', 'alike() should work with a regex' ); SELECT ialike( 'FOO'::text, 'fo%', 'ialike() should work with a regex' ); -- Check alike() diagnostics. SELECT * FROM check_test( alike( 'foo'::text, 'a%'::text ), false, 'alike() fail', '', ' ''foo'' doesn''t match: ''a%''' ); -- Test unalike(). SELECT unalike( 'foo'::text, 'f', 'unalike() should work' ); SELECT unalike( 'foo'::text, 'f%i', 'unalike() should work with a regex' ); SELECT unialike( 'FOO'::text, 'f%i', 'iunalike() should work with a regex' ); -- Check unalike() diagnostics. SELECT * FROM check_test( unalike( 'foo'::text, 'f%'::text ), false, 'unalike() fail', '', ' ''foo'' matches: ''f%''' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/moretap.sql000066400000000000000000000123651455775703000166220ustar00rootroot00000000000000\unset ECHO \i test/setup.sql \set numb_tests 54 SELECT plan(:numb_tests); -- Replace the internal record of the plan for a few tests. SELECT is( _set('plan', 4), 4, 'Modify internal plan value'); /****************************************************************************/ -- Test pass(). SELECT pass( 'My pass() passed, w00t!' ); -- Test fail(). \set fail_numb 3 \echo ok :fail_numb - Testing fail() SELECT is( fail('oops'), format( E'not ok %1$s - oops\n# Failed test %1$s: "oops"', :fail_numb ), 'We should get the proper output from fail()' ); /* * NOTE: From this point until we call _set('failed') below we should always * have *one* test failure, *BUT* if the tests themselves start failing then * you'll have extra failures which will throw off all the successive counts! */ -- Check the finish() output with no value. SELECT is( (SELECT * FROM finish() LIMIT 1), '# Looks like you failed 1 test of 4', 'The output of finish() should reflect the test failure' ); -- Make sure that false and NULL work as well SELECT is( _set('plan', 6), 6, 'Increase internal plan value after testing finish' ); SELECT is( (SELECT * FROM finish(false) LIMIT 1), '# Looks like you failed 1 test of 6', 'The output of finish(false) should reflect the test failure' ); SELECT is( _set('plan', 8), 8, 'Increase internal plan value after testing finish' ); SELECT is( (SELECT * FROM finish(NULL) LIMIT 1), '# Looks like you failed 1 test of 8', 'The output of finish(NULL) should reflect the test failure' ); -- Verify that finish(true) works SELECT is( _set('plan', 10), 10, 'Increase internal plan value after testing finish' ); SELECT throws_ok( $$SELECT finish(true)$$, '1 test failed of 10', 'finish(true) should throw an exception' ); /****************************************************************************/ -- Check num_failed SELECT is( num_failed(), 1, 'We should have one failure' ); SELECT is( _set('failed', 0), 0, 'Reset internal failure count' ); SELECT is( num_failed(), 0, 'We should now have no failures' ); /****************************************************************************/ -- Check diag. SELECT is( diag('foo'), '# foo', 'diag() should work properly' ); SELECT is( diag( 'foo bar'), '# foo # bar', 'multiline diag() should work properly' ); SELECT is( diag( 'foo # bar'), '# foo # # bar', 'multiline diag() should work properly with existing comments' ); -- Try anyelement form. SELECT is(diag(6), '# 6', 'diag(int)'); SELECT is(diag(11.2), '# 11.2', 'diag(numeric)'); SELECT is(diag(NOW()), '# ' || NOW(), 'diag(timestamptz)'); -- Try variadic anyarray CREATE FUNCTION test_variadic() RETURNS SETOF TEXT AS $$ BEGIN IF pg_version_num() >= 80400 THEN RETURN NEXT is(diag('foo'::text, 'bar', 'baz'), '# foobarbaz', 'variadic text'); RETURN NEXT is(diag(1::int, 3, 4), '# 134', 'variadic int'); RETURN NEXT is(diag('foo', 'bar', 'baz'), '# foobarbaz', 'variadic unknown'); ELSE RETURN NEXT pass('variadic text'); RETURN NEXT pass('variadic int'); RETURN NEXT pass('variadic unknown'); RETURN; END IF; END; $$ LANGUAGE plpgsql; SELECT * FROM test_variadic(); /****************************************************************************/ -- Check no_plan. DELETE FROM __tcache__ WHERE label = 'plan'; SELECT * FROM no_plan(); SELECT is( _get('plan'), 0, 'no_plan() should have stored a plan of 0' ); -- Set the plan to a high number. DELETE FROM __tcache__ WHERE label = 'plan'; SELECT is( plan(4000), '1..4000', 'Set the plan to 4000' ); SELECT is( (SELECT * FROM finish() LIMIT 1), '# Looks like you planned 4000 tests but ran 25', 'The output of finish() should reflect a high test plan' ); -- Set the plan to a low number. DELETE FROM __tcache__ WHERE label = 'plan'; SELECT is( plan(4), '1..4', 'Set the plan to 4' ); SELECT is( (SELECT * FROM finish() LIMIT 1), '# Looks like you planned 4 tests but ran 27', 'The output of finish() should reflect a low test plan' ); -- Reset the original plan. DELETE FROM __tcache__ WHERE label = 'plan'; SELECT is( plan(:numb_tests), '1..' || :numb_tests, 'Reset the plan' ); SELECT is( _get('plan'), :numb_tests, 'plan() should have stored the test count' ); /****************************************************************************/ -- Test ok() SELECT * FROM check_test( ok(true), true, 'ok(true)', '', ''); SELECT * FROM check_test( ok(true, ''), true, 'ok(true, '''')', '', '' ); SELECT * FROM check_test( ok(true, 'foo'), true, 'ok(true, ''foo'')', 'foo', '' ); SELECT * FROM check_test( ok(false), false, 'ok(false)', '', '' ); SELECT * FROM check_test( ok(false, ''), false, 'ok(false, '''')', '', '' ); SELECT * FROM check_test( ok(false, 'foo'), false, 'ok(false, ''foo'')', 'foo', '' ); SELECT * FROM check_test( ok(NULL, 'null'), false, 'ok(NULL, ''null'')', 'null', ' (test result was NULL)' ); /****************************************************************************/ -- test multiline description. Second line is effectively diagnostic output. SELECT * FROM check_test( ok( true, 'foo bar' ), true, 'multiline desc', 'foo', 'bar' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/ownership.sql000066400000000000000000001255131455775703000171710ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(411); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), "myInt" NUMERIC(8) ); CREATE INDEX idx_hey ON public.sometab(numb); -- Create a partition. CREATE FUNCTION mkpart() RETURNS SETOF TEXT AS $$ BEGIN IF pg_version_num() >= 100000 THEN EXECUTE $E$ CREATE TABLE public.apart (dt DATE NOT NULL) PARTITION BY RANGE (dt); $E$; ELSE EXECUTE $E$ CREATE TABLE public.apart (dt DATE NOT NULL); $E$; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM mkpart(); CREATE VIEW public.someview AS SELECT * FROM public.sometab; CREATE TYPE public.sometype AS ( id INT, name TEXT ); CREATE SEQUENCE public.someseq; CREATE SCHEMA someschema; CREATE TABLE someschema.anothertab( id INT PRIMARY KEY, name TEXT DEFAULT '' ); CREATE DOMAIN someschema.us_postal_code AS TEXT CHECK( VALUE ~ '^[[:digit:]]{5}$' OR VALUE ~ '^[[:digit:]]{5}-[[:digit:]]{4}$' ); CREATE INDEX idx_name ON someschema.anothertab(name); CREATE FUNCTION public.somefunction(int) RETURNS VOID LANGUAGE SQL AS ''; RESET client_min_messages; /****************************************************************************/ -- Test db_owner_is(). SELECT * FROM check_test( db_owner_is(current_database(), current_user, 'mumble'), true, 'db_owner_is(db, user, desc)', 'mumble', '' ); SELECT * FROM check_test( db_owner_is(current_database(), current_user), true, 'db_owner_is(db, user)', 'Database ' || quote_ident(current_database()) || ' should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( db_owner_is('__not__' || current_database(), current_user, 'mumble'), false, 'db_owner_is(non-db, user)', 'mumble', ' Database __not__' || current_database() || ' does not exist' ); SELECT * FROM check_test( db_owner_is(current_database(), '__not__' || current_user, 'mumble'), false, 'db_owner_is(db, non-user)', 'mumble', ' have: ' || current_user || ' want: __not__' || current_user ); /****************************************************************************/ -- Test schema_owner_is(). SELECT * FROM check_test( schema_owner_is(current_schema(), _get_schema_owner(current_schema()), 'mumble'), true, 'schema_owner_is(schema, user, desc)', 'mumble', '' ); SELECT * FROM check_test( schema_owner_is(current_schema(), _get_schema_owner(current_schema())), true, 'schema_owner_is(schema, user)', 'Schema ' || quote_ident(current_schema()) || ' should be owned by ' || _get_schema_owner(current_schema()), '' ); SELECT * FROM check_test( schema_owner_is('__not__' || current_schema(), _get_schema_owner(current_schema()), 'mumble'), false, 'schema_owner_is(non-schema, user)', 'mumble', ' Schema __not__' || current_schema() || ' does not exist' ); SELECT * FROM check_test( schema_owner_is(current_schema(), '__not__' || _get_schema_owner(current_schema()), 'mumble'), false, 'schema_owner_is(schema, non-user)', 'mumble', ' have: ' || _get_schema_owner(current_schema()) || ' want: __not__' || _get_schema_owner(current_schema()) ); /****************************************************************************/ -- Test relation_owner_is() with a table. SELECT * FROM check_test( relation_owner_is('public', 'sometab', current_user, 'mumble'), true, 'relation_owner_is(sch, tab, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('public', 'sometab', current_user), true, 'relation_owner_is(sch, tab, user)', 'Relation public.sometab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__public', 'sometab', current_user, 'mumble'), false, 'relation_owner_is(non-sch, tab, user)', 'mumble', ' Relation __not__public.sometab does not exist' ); SELECT * FROM check_test( relation_owner_is('public', '__not__sometab', current_user, 'mumble'), false, 'relation_owner_is(sch, non-tab, user)', 'mumble', ' Relation public.__not__sometab does not exist' ); SELECT * FROM check_test( relation_owner_is('sometab', current_user, 'mumble'), true, 'relation_owner_is(tab, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('sometab', current_user), true, 'relation_owner_is(tab, user)', 'Relation sometab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__sometab', current_user, 'mumble'), false, 'relation_owner_is(non-tab, user)', 'mumble', ' Relation __not__sometab does not exist' ); /****************************************************************************/ -- Test relation_owner_is() with a partition. SELECT * FROM check_test( relation_owner_is('public', 'apart', current_user, 'mumble'), true, 'relation_owner_is(sch, part, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('public', 'apart', current_user), true, 'relation_owner_is(sch, part, user)', 'Relation public.apart should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__public', 'apart', current_user, 'mumble'), false, 'relation_owner_is(non-sch, part, user)', 'mumble', ' Relation __not__public.apart does not exist' ); SELECT * FROM check_test( relation_owner_is('public', '__not__apart', current_user, 'mumble'), false, 'relation_owner_is(sch, non-part, user)', 'mumble', ' Relation public.__not__apart does not exist' ); SELECT * FROM check_test( relation_owner_is('apart', current_user, 'mumble'), true, 'relation_owner_is(part, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('apart', current_user), true, 'relation_owner_is(part, user)', 'Relation apart should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__apart', current_user, 'mumble'), false, 'relation_owner_is(non-part, user)', 'mumble', ' Relation __not__apart does not exist' ); /****************************************************************************/ -- Test relation_owner_is() with a schema. SELECT * FROM check_test( relation_owner_is('public', 'someseq', current_user, 'mumble'), true, 'relation_owner_is(sch, seq, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('public', 'someseq', current_user), true, 'relation_owner_is(sch, seq, user)', 'Relation public.someseq should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__public', 'someseq', current_user, 'mumble'), false, 'relation_owner_is(non-sch, seq, user)', 'mumble', ' Relation __not__public.someseq does not exist' ); SELECT * FROM check_test( relation_owner_is('public', '__not__someseq', current_user, 'mumble'), false, 'relation_owner_is(sch, non-seq, user)', 'mumble', ' Relation public.__not__someseq does not exist' ); SELECT * FROM check_test( relation_owner_is('someseq', current_user, 'mumble'), true, 'relation_owner_is(seq, user, desc)', 'mumble', '' ); SELECT * FROM check_test( relation_owner_is('someseq', current_user), true, 'relation_owner_is(seq, user)', 'Relation someseq should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( relation_owner_is('__not__someseq', current_user, 'mumble'), false, 'relation_owner_is(non-seq, user)', 'mumble', ' Relation __not__someseq does not exist' ); /****************************************************************************/ -- Test table_owner_is(). SELECT * FROM check_test( table_owner_is('public', 'sometab', current_user, 'mumble'), true, 'table_owner_is(sch, tab, user, desc)', 'mumble', '' ); SELECT * FROM check_test( table_owner_is('public', 'sometab', current_user), true, 'table_owner_is(sch, tab, user)', 'Table public.sometab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( table_owner_is('__not__public', 'sometab', current_user, 'mumble'), false, 'table_owner_is(non-sch, tab, user)', 'mumble', ' Table __not__public.sometab does not exist' ); SELECT * FROM check_test( table_owner_is('public', '__not__sometab', current_user, 'mumble'), false, 'table_owner_is(sch, non-tab, user)', 'mumble', ' Table public.__not__sometab does not exist' ); SELECT * FROM check_test( table_owner_is('sometab', current_user, 'mumble'), true, 'table_owner_is(tab, user, desc)', 'mumble', '' ); SELECT * FROM check_test( table_owner_is('sometab', current_user), true, 'table_owner_is(tab, user)', 'Table sometab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( table_owner_is('__not__sometab', current_user, 'mumble'), false, 'table_owner_is(non-tab, user)', 'mumble', ' Table __not__sometab does not exist' ); -- It should ignore the sequence. SELECT * FROM check_test( table_owner_is('public', 'someseq', current_user, 'mumble'), false, 'table_owner_is(sch, seq, user, desc)', 'mumble', ' Table public.someseq does not exist' ); SELECT * FROM check_test( table_owner_is('someseq', current_user, 'mumble'), false, 'table_owner_is(seq, user, desc)', 'mumble', ' Table someseq does not exist' ); -- But not a partition. SELECT * FROM check_test( table_owner_is('public', 'apart', current_user, 'mumble'), true, 'table_owner_is(sch, part, user, desc)', 'mumble', '' ); SELECT * FROM check_test( table_owner_is('apart', current_user, 'mumble'), true, 'table_owner_is(part, user, desc)', 'mumble', '' ); /****************************************************************************/ -- Test view_owner_is(). SELECT * FROM check_test( view_owner_is('public', 'someview', current_user, 'mumble'), true, 'view_owner_is(sch, view, user, desc)', 'mumble', '' ); SELECT * FROM check_test( view_owner_is('public', 'someview', current_user), true, 'view_owner_is(sch, view, user)', 'View public.someview should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( view_owner_is('__not__public', 'someview', current_user, 'mumble'), false, 'view_owner_is(non-sch, view, user)', 'mumble', ' View __not__public.someview does not exist' ); SELECT * FROM check_test( view_owner_is('public', '__not__someview', current_user, 'mumble'), false, 'view_owner_is(sch, non-view, user)', 'mumble', ' View public.__not__someview does not exist' ); SELECT * FROM check_test( view_owner_is('someview', current_user, 'mumble'), true, 'view_owner_is(view, user, desc)', 'mumble', '' ); SELECT * FROM check_test( view_owner_is('someview', current_user), true, 'view_owner_is(view, user)', 'View someview should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( view_owner_is('__not__someview', current_user, 'mumble'), false, 'view_owner_is(non-view, user)', 'mumble', ' View __not__someview does not exist' ); -- It should ignore the sequence. SELECT * FROM check_test( view_owner_is('public', 'someseq', current_user, 'mumble'), false, 'view_owner_is(sch, seq, user, desc)', 'mumble', ' View public.someseq does not exist' ); SELECT * FROM check_test( view_owner_is('someseq', current_user, 'mumble'), false, 'view_owner_is(seq, user, desc)', 'mumble', ' View someseq does not exist' ); /****************************************************************************/ -- Test sequence_owner_is(). SELECT * FROM check_test( sequence_owner_is('public', 'someseq', current_user, 'mumble'), true, 'sequence_owner_is(sch, sequence, user, desc)', 'mumble', '' ); SELECT * FROM check_test( sequence_owner_is('public', 'someseq', current_user), true, 'sequence_owner_is(sch, sequence, user)', 'Sequence public.someseq should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( sequence_owner_is('__not__public', 'someseq', current_user, 'mumble'), false, 'sequence_owner_is(non-sch, sequence, user)', 'mumble', ' Sequence __not__public.someseq does not exist' ); SELECT * FROM check_test( sequence_owner_is('public', '__not__someseq', current_user, 'mumble'), false, 'sequence_owner_is(sch, non-sequence, user)', 'mumble', ' Sequence public.__not__someseq does not exist' ); SELECT * FROM check_test( sequence_owner_is('someseq', current_user, 'mumble'), true, 'sequence_owner_is(sequence, user, desc)', 'mumble', '' ); SELECT * FROM check_test( sequence_owner_is('someseq', current_user), true, 'sequence_owner_is(sequence, user)', 'Sequence someseq should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( sequence_owner_is('__not__someseq', current_user, 'mumble'), false, 'sequence_owner_is(non-sequence, user)', 'mumble', ' Sequence __not__someseq does not exist' ); -- It should ignore the view. SELECT * FROM check_test( sequence_owner_is('public', 'someview', current_user, 'mumble'), false, 'sequence_owner_is(sch, view, user, desc)', 'mumble', ' Sequence public.someview does not exist' ); SELECT * FROM check_test( sequence_owner_is('someview', current_user, 'mumble'), false, 'sequence_owner_is(view, user, desc)', 'mumble', ' Sequence someview does not exist' ); /****************************************************************************/ -- Test composite_owner_is(). SELECT * FROM check_test( composite_owner_is('public', 'sometype', current_user, 'mumble'), true, 'composite_owner_is(sch, composite, user, desc)', 'mumble', '' ); SELECT * FROM check_test( composite_owner_is('public', 'sometype', current_user), true, 'composite_owner_is(sch, composite, user)', 'Composite type public.sometype should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( composite_owner_is('__not__public', 'sometype', current_user, 'mumble'), false, 'composite_owner_is(non-sch, composite, user)', 'mumble', ' Composite type __not__public.sometype does not exist' ); SELECT * FROM check_test( composite_owner_is('public', '__not__sometype', current_user, 'mumble'), false, 'composite_owner_is(sch, non-composite, user)', 'mumble', ' Composite type public.__not__sometype does not exist' ); SELECT * FROM check_test( composite_owner_is('sometype', current_user, 'mumble'), true, 'composite_owner_is(composite, user, desc)', 'mumble', '' ); SELECT * FROM check_test( composite_owner_is('sometype', current_user), true, 'composite_owner_is(composite, user)', 'Composite type sometype should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( composite_owner_is('__not__sometype', current_user, 'mumble'), false, 'composite_owner_is(non-composite, user)', 'mumble', ' Composite type __not__sometype does not exist' ); -- It should ignore the view. SELECT * FROM check_test( composite_owner_is('public', 'someview', current_user, 'mumble'), false, 'composite_owner_is(sch, view, user, desc)', 'mumble', ' Composite type public.someview does not exist' ); SELECT * FROM check_test( composite_owner_is('someview', current_user, 'mumble'), false, 'composite_owner_is(view, user, desc)', 'mumble', ' Composite type someview does not exist' ); /****************************************************************************/ -- Test foreign_table_owner_is(). CREATE FUNCTION public.test_fdw() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 90100 THEN EXECUTE $E$ CREATE FOREIGN DATA WRAPPER dummy; CREATE SERVER foo FOREIGN DATA WRAPPER dummy; CREATE FOREIGN TABLE public.my_fdw (id int) SERVER foo; $E$; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('public', 'my_fdw', current_user, 'mumble'), true, 'foreign_table_owner_is(sch, tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('public', 'my_fdw', current_user), true, 'foreign_table_owner_is(sch, tab, user)', 'Foreign table public.my_fdw should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('__not__public', 'my_fdw', current_user, 'mumble'), false, 'foreign_table_owner_is(non-sch, tab, user)', 'mumble', ' Foreign table __not__public.my_fdw does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('public', '__not__my_fdw', current_user, 'mumble'), false, 'foreign_table_owner_is(sch, non-tab, user)', 'mumble', ' Foreign table public.__not__my_fdw does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('my_fdw', current_user, 'mumble'), true, 'foreign_table_owner_is(tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('my_fdw', current_user), true, 'foreign_table_owner_is(tab, user)', 'Foreign table my_fdw should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('__not__my_fdw', current_user, 'mumble'), false, 'foreign_table_owner_is(non-tab, user)', 'mumble', ' Foreign table __not__my_fdw does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore the table. FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('public', 'sometab', current_user, 'mumble'), false, 'foreign_table_owner_is(sch, tab, user, desc)', 'mumble', ' Foreign table public.sometab does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( foreign_table_owner_is('sometab', current_user, 'mumble'), false, 'foreign_table_owner_is(tab, user, desc)', 'mumble', ' Foreign table sometab does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'foreign_table_owner_is(sch, tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'foreign_table_owner_is(sch, tab, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'foreign_table_owner_is(non-sch, tab, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'foreign_table_owner_is(sch, non-tab, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'foreign_table_owner_is(tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'foreign_table_owner_is(tab, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'foreign_table_owner_is(non-tab, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore the table. FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'foreign_table_owner_is(sch, tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'foreign_table_owner_is(tab, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE PLPGSQL; SELECT * FROM public.test_fdw(); /****************************************************************************/ -- Test function_owner_is(). SELECT * FROM check_test( function_owner_is('public', 'somefunction', ARRAY['integer'], current_user, 'mumble'), true, 'function_owner_is(sch, function, args[integer], user, desc)', 'mumble', '' ); SELECT * FROM check_test( function_owner_is('public', 'somefunction', ARRAY['integer'], current_user), true, 'function_owner_is(sch, function, args[integer], user)', 'Function public.somefunction(integer) should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( function_owner_is('public', 'test_fdw', '{}'::NAME[], current_user, 'mumble'), true, 'function_owner_is(sch, function, args[], user, desc)', 'mumble', '' ); SELECT * FROM check_test( function_owner_is('public', 'test_fdw', '{}'::NAME[], current_user), true, 'function_owner_is(sch, function, args[], user)', 'Function public.test_fdw() should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( function_owner_is('somefunction', ARRAY['integer'], current_user, 'mumble'), true, 'function_owner_is(function, args[integer], user, desc)', 'mumble', '' ); SELECT * FROM check_test( function_owner_is('somefunction', ARRAY['integer'], current_user), true, 'function_owner_is(function, args[integer], user)', 'Function somefunction(integer) should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( function_owner_is('test_fdw', '{}'::NAME[], current_user, 'mumble'), true, 'function_owner_is(function, args[], user, desc)', 'mumble', '' ); SELECT * FROM check_test( function_owner_is('test_fdw', '{}'::NAME[], current_user), true, 'function_owner_is(function, args[], user)', 'Function test_fdw() should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( function_owner_is('public', '__non__function', ARRAY['integer'], current_user, 'mumble'), false, 'function_owner_is(sch, non-function, args[integer], user, desc)', 'mumble', ' Function public.__non__function(integer) does not exist' ); SELECT * FROM check_test( function_owner_is('__non__public', 'afunction', ARRAY['integer'], current_user, 'mumble'), false, 'function_owner_is(non-sch, function, args[integer], user, desc)', 'mumble', ' Function __non__public.afunction(integer) does not exist' ); SELECT * FROM check_test( function_owner_is('__non__function', ARRAY['integer'], current_user, 'mumble'), false, 'function_owner_is(non-function, args[integer], user, desc)', 'mumble', ' Function __non__function(integer) does not exist' ); SELECT * FROM check_test( function_owner_is('public', 'somefunction', ARRAY['integer'], 'no one', 'mumble'), false, 'function_owner_is(sch, function, args[integer], non-user, desc)', 'mumble', ' have: ' || current_user || ' want: no one' ); SELECT * FROM check_test( function_owner_is('somefunction', ARRAY['integer'], 'no one', 'mumble'), false, 'function_owner_is(function, args[integer], non-user, desc)', 'mumble', ' have: ' || current_user || ' want: no one' ); /****************************************************************************/ -- Test tablespace_owner_is(). SELECT * FROM check_test( tablespace_owner_is('pg_default', _get_tablespace_owner('pg_default'), 'mumble'), true, 'tablespace_owner_is(tablespace, user, desc)', 'mumble', '' ); SELECT * FROM check_test( tablespace_owner_is('pg_default', _get_tablespace_owner('pg_default')), true, 'tablespace_owner_is(tablespace, user)', 'Tablespace ' || quote_ident('pg_default') || ' should be owned by ' || _get_tablespace_owner('pg_default'), '' ); SELECT * FROM check_test( tablespace_owner_is('__not__' || 'pg_default', _get_tablespace_owner('pg_default'), 'mumble'), false, 'tablespace_owner_is(non-tablespace, user)', 'mumble', ' Tablespace __not__' || 'pg_default' || ' does not exist' ); SELECT * FROM check_test( tablespace_owner_is('pg_default', '__not__' || _get_tablespace_owner('pg_default'), 'mumble'), false, 'tablespace_owner_is(tablespace, non-user)', 'mumble', ' have: ' || _get_tablespace_owner('pg_default') || ' want: __not__' || _get_tablespace_owner('pg_default') ); /****************************************************************************/ -- Test index_owner_is(). SELECT * FROM check_test( index_owner_is('someschema', 'anothertab', 'idx_name', current_user, 'mumble'), true, 'index_owner_is(schema, table, index, user, desc)', 'mumble', '' ); SELECT * FROM check_test( index_owner_is('someschema', 'anothertab', 'idx_name', current_user), true, 'index_owner_is(schema, table, index, user)', 'Index idx_name ON someschema.anothertab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( index_owner_is('someschema', 'anothertab', 'idx_foo', current_user, 'mumble'), false, 'index_owner_is(schema, table, non-index, user, desc)', 'mumble', ' Index idx_foo ON someschema.anothertab not found' ); SELECT * FROM check_test( index_owner_is('someschema', 'nonesuch', 'idx_name', current_user, 'mumble'), false, 'index_owner_is(schema, non-table, index, user, desc)', 'mumble', ' Index idx_name ON someschema.nonesuch not found' ); SELECT * FROM check_test( index_owner_is('nonesuch', 'anothertab', 'idx_name', current_user, 'mumble'), false, 'index_owner_is(non-schema, table, index, user, desc)', 'mumble', ' Index idx_name ON nonesuch.anothertab not found' ); SELECT * FROM check_test( index_owner_is('someschema', 'anothertab', 'idx_name', '__noone', 'mumble'), false, 'index_owner_is(schema, table, index, non-user, desc)', 'mumble', ' have: ' || current_user || ' want: __noone' ); SELECT * FROM check_test( index_owner_is('anothertab', 'idx_name', current_user, 'mumble'), false, 'index_owner_is(invisible-table, index, user, desc)', 'mumble', ' Index idx_name ON anothertab not found' ); SELECT * FROM check_test( index_owner_is('sometab', 'idx_hey', current_user, 'mumble'), true, 'index_owner_is(table, index, user, desc)', 'mumble', '' ); SELECT * FROM check_test( index_owner_is('sometab', 'idx_hey', current_user), true, 'index_owner_is(table, index, user)', 'Index idx_hey ON sometab should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( index_owner_is('notab', 'idx_hey', current_user, 'mumble'), false, 'index_owner_is(non-table, index, user)', 'mumble', ' Index idx_hey ON notab not found' ); SELECT * FROM check_test( index_owner_is('sometab', 'idx_foo', current_user, 'mumble'), false, 'index_owner_is(table, non-index, user)', 'mumble', ' Index idx_foo ON sometab not found' ); SELECT * FROM check_test( index_owner_is('sometab', 'idx_hey', '__no-one', 'mumble'), false, 'index_owner_is(table, index, non-user)', 'mumble', ' have: ' || current_user || ' want: __no-one' ); /****************************************************************************/ -- Test language_owner_is(). CREATE FUNCTION test_lang() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 80300 THEN FOR tap IN SELECT * FROM check_test( language_owner_is('plpgsql', _get_language_owner('plpgsql'), 'mumble'), true, 'language_owner_is(language, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( language_owner_is('plpgsql', _get_language_owner('plpgsql')), true, 'language_owner_is(language, user)', 'Language ' || quote_ident('plpgsql') || ' should be owned by ' || _get_language_owner('plpgsql'), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( language_owner_is('__not__plpgsql', _get_language_owner('plpgsql'), 'mumble'), false, 'language_owner_is(non-language, user)', 'mumble', ' Language __not__plpgsql does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( language_owner_is('plpgsql', '__not__' || _get_language_owner('plpgsql'), 'mumble'), false, 'language_owner_is(language, non-user)', 'mumble', ' have: ' || _get_language_owner('plpgsql') || ' want: __not__' || _get_language_owner('plpgsql') ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'language_owner_is(language, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('mumble'), true, 'language_owner_is(language, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'language_owner_is(non-language, user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('mumble'), false, 'language_owner_is(language, non-user)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_lang(); /****************************************************************************/ -- Test opclass_owner_is(). SELECT * FROM check_test( opclass_owner_is( 'pg_catalog', 'int4_ops', _get_opclass_owner('pg_catalog', 'int4_ops'), 'mumble' ), true, 'opclass_owner_is(schema, opclass, user, desc)', 'mumble', '' ); SELECT * FROM check_test( opclass_owner_is( 'pg_catalog', 'int4_ops', _get_opclass_owner('pg_catalog', 'int4_ops') ), true, 'opclass_owner_is(schema, opclass, user)', 'Operator class pg_catalog.int4_ops should be owned by ' || _get_opclass_owner('pg_catalog', 'int4_ops'), '' ); SELECT * FROM check_test( opclass_owner_is( 'not_pg_catalog', 'int4_ops', _get_opclass_owner('pg_catalog', 'int4_ops'), 'mumble' ), false, 'opclass_owner_is(non-schema, opclass, user, desc)', 'mumble', ' Operator class not_pg_catalog.int4_ops not found' ); SELECT * FROM check_test( opclass_owner_is( 'pg_catalog', 'int4_nots', _get_opclass_owner('pg_catalog', 'int4_ops'), 'mumble' ), false, 'opclass_owner_is(schema, not-opclass, user, desc)', 'mumble', ' Operator class pg_catalog.int4_nots not found' ); SELECT * FROM check_test( opclass_owner_is( 'pg_catalog', 'int4_ops', '__no-one', 'mumble' ), false, 'opclass_owner_is(schema, opclass, non-user, desc)', 'mumble', ' have: ' || _get_opclass_owner('pg_catalog', 'int4_ops') || ' want: __no-one' ); SELECT * FROM check_test( opclass_owner_is('int4_ops', _get_opclass_owner('int4_ops'), 'mumble'), true, 'opclass_owner_is(opclass, user, desc)', 'mumble', '' ); SELECT * FROM check_test( opclass_owner_is('int4_ops', _get_opclass_owner('int4_ops')), true, 'opclass_owner_is(opclass, user)', 'Operator class int4_ops should be owned by ' || _get_opclass_owner('int4_ops'), '' ); SELECT * FROM check_test( opclass_owner_is('int4_nots', _get_opclass_owner('int4_ops'), 'mumble'), false, 'opclass_owner_is(non-opclass, user, desc)', 'mumble', ' Operator class int4_nots not found' ); SELECT * FROM check_test( opclass_owner_is('int4_ops', '__no-one', 'mumble'), false, 'opclass_owner_is(opclass, non-user, desc)', 'mumble', ' have: ' || _get_opclass_owner('int4_ops') || ' want: __no-one' ); /****************************************************************************/ -- Test type_owner_is() with a table. SELECT * FROM check_test( type_owner_is('someschema', 'us_postal_code', current_user, 'mumble'), true, 'type_owner_is(schema, type, user, desc)', 'mumble', '' ); SELECT * FROM check_test( type_owner_is('someschema', 'us_postal_code', current_user), true, 'type_owner_is(schema, type, user)', 'Type someschema.us_postal_code should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( type_owner_is('--nonesuch', 'us_postal_code', current_user, 'mumble'), false, 'type_owner_is(non-schema, type, user, desc)', 'mumble', ' Type "--nonesuch".us_postal_code not found' ); SELECT * FROM check_test( type_owner_is('someschema', 'uk_postal_code', current_user, 'mumble'), false, 'type_owner_is(schema, non-type, user, desc)', 'mumble', ' Type someschema.uk_postal_code not found' ); SELECT * FROM check_test( type_owner_is('someschema', 'us_postal_code', '__no-one', 'mumble'), false, 'type_owner_is(schema, type, non-user, desc)', 'mumble', ' have: ' || current_user || ' want: __no-one' ); SELECT * FROM check_test( type_owner_is('us_postal_code', current_user, 'mumble'), false, 'type_owner_is( invisible-type, user, desc)', 'mumble', ' Type us_postal_code not found' ); SELECT * FROM check_test( type_owner_is('sometype', current_user, 'mumble'), true, 'type_owner_is(type, user, desc)', 'mumble', '' ); SELECT * FROM check_test( type_owner_is('sometype', current_user), true, 'type_owner_is(type, user)', 'Type sometype should be owned by ' || quote_ident(current_user), '' ); SELECT * FROM check_test( type_owner_is('__notype', current_user, 'mumble'), false, 'type_owner_is(non-type, user, desc)', 'mumble', ' Type __notype not found' ); SELECT * FROM check_test( type_owner_is('sometype', '__no-one', 'mumble'), false, 'type_owner_is(type, non-user, desc)', 'mumble', ' have: ' || current_user || ' want: __no-one' ); /****************************************************************************/ -- Test materialized_view_owner_is(). CREATE FUNCTION test_materialized_view_owner_is() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 93000 THEN EXECUTE $E$ CREATE MATERIALIZED VIEW public.somemview AS SELECT * FROM public.sometab; $E$; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('public', 'somemview', current_user, 'mumble'), true, 'materialized_view_owner_is(sch, materialized_view, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('public', 'somemview', current_user), true, 'materialized_view_owner_is(sch, materialized_view, user)', 'Materialized view public.somemview should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('__not__public', 'somemview', current_user, 'mumble'), false, 'materialized_view_owner_is(non-sch, materialized_view, user)', 'mumble', ' Materialized view __not__public.somemview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('public', '__not__somemview', current_user, 'mumble'), false, 'materialized_view_owner_is(sch, non-materialized_view, user)', 'mumble', ' Materialized view public.__not__somemview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('somemview', current_user, 'mumble'), true, 'materialized_view_owner_is(materialized_view, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('somemview', current_user), true, 'materialized_view_owner_is(view, user)', 'Materialized view somemview should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('__not__somemview', current_user, 'mumble'), false, 'materialized_view_owner_is(non-materialized_view, user)', 'mumble', ' Materialized view __not__somemview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore the sequence. FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('public', 'someseq', current_user, 'mumble'), false, 'materialized_view_owner_is(sch, seq, user, desc)', 'mumble', ' Materialized view public.someseq does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( materialized_view_owner_is('someseq', current_user, 'mumble'), false, 'materialized_view_owner_is(seq, user, desc)', 'mumble', ' Materialized view someseq does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; else FOR tap IN SELECT * FROM check_test( view_owner_is('public', 'someview', current_user, 'mumble'), true, 'materialized_view_owner_is(sch, materialized_view, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('public', 'someview', current_user), true, 'materialized_view_owner_is(sch, materialized_view, user)', 'View public.someview should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('__not__public', 'someview', current_user, 'mumble'), false, 'materialized_view_owner_is(non-sch, materialized_view, user)', 'mumble', ' View __not__public.someview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('public', '__not__someview', current_user, 'mumble'), false, 'materialized_view_owner_is(sch, non-materialized_view, user)', 'mumble', ' View public.__not__someview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('someview', current_user, 'mumble'), true, 'materialized_view_owner_is(materialized_view, user, desc)', 'mumble', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('someview', current_user), true, 'materialized_view_owner_is(view, user)', 'View someview should be owned by ' || quote_ident(current_user), '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('__not__someview', current_user, 'mumble'), false, 'materialized_view_owner_is(non-materialized_view, user)', 'mumble', ' View __not__someview does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- It should ignore the sequence. FOR tap IN SELECT * FROM check_test( view_owner_is('public', 'someseq', current_user, 'mumble'), false, 'materialized_view_owner_is(sch, seq, user, desc)', 'mumble', ' View public.someseq does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( view_owner_is('someseq', current_user, 'mumble'), false, 'materialized_view_owner_is(seq, user, desc)', 'mumble', ' View someseq does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; end if; return; end; $$language PLPGSQL; SELECT * from test_materialized_view_owner_is(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/partitions.sql000066400000000000000000000220311455775703000173360ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(102); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; -- Create inherited tables (not partitions). CREATE TABLE public.base(id INT PRIMARY KEY); CREATE TABLE public.sub(id INT PRIMARY KEY) INHERITS (public.base); -- Create a partitioned table with two partitions. CREATE TABLE public.parted(id INT NOT NULL) PARTITION BY RANGE (id); CREATE TABLE public.part1 PARTITION OF public.parted FOR VALUES FROM (1) TO (10); CREATE TABLE public.part2 PARTITION OF public.parted FOR VALUES FROM (11) TO (20); -- Create partitions outside of search path. CREATE SCHEMA hide; CREATE TABLE hide.hidden_parted(id INT NOT NULL) PARTITION BY RANGE (id); CREATE TABLE hide.hidden_part1 PARTITION OF hide.hidden_parted FOR VALUES FROM (1) TO (10); CREATE TABLE hide.hidden_part2 PARTITION OF hide.hidden_parted FOR VALUES FROM (11) TO (20); -- Put a partition for the public table in the hidden schema. CREATE TABLE hide.part3 PARTITION OF public.parted FOR VALUES FROM (21) TO (30); -- Put a partition for the hidden table in the public schema. CREATE TABLE public.not_hidden_part3 PARTITION OF hide.hidden_parted FOR VALUES FROM (21) TO (30); RESET client_min_messages; /****************************************************************************/ -- Test is_partition_of(). SELECT * FROM check_test( is_partition_of( 'public', 'part1', 'public', 'parted', 'whatevs' ), true, 'is_partition_of( csch, ctab, psch, ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'public', 'part1', 'public', 'parted' ), true, 'is_partition_of( csch, ctab, psch, ptab )', 'Table public.part1 should be a partition of public.parted', '' ); SELECT * FROM check_test( is_partition_of( 'part1', 'parted', 'whatevs' ), true, 'is_partition_of( ctab, ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'part1', 'parted' ), true, 'is_partition_of( ctab, ptab )', 'Table part1 should be a partition of parted', '' ); -- is_partition_of() should fail for inherited but not partitioned tables. SELECT * FROM check_test( is_partition_of( 'public', 'sub', 'public', 'base', 'whatevs' ), false, 'is_partition_of( csch, non-part ctab, psch, non-part ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'sub', 'base', 'whatevs' ), false, 'is_partition_of( non-part ctab, non-part ptab, desc )', 'whatevs', '' ); -- is_partition_of() should fail for parted table and non-part sub. SELECT * FROM check_test( is_partition_of( 'public', 'sub', 'public', 'parted', 'whatevs' ), false, 'is_partition_of( csch, non-part ctab, psch, ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'sub', 'parted', 'whatevs' ), false, 'is_partition_of( non-part ctab, ptab, desc )', 'whatevs', '' ); -- is_partition_of() should fail for partition sub but wrong base. SELECT * FROM check_test( is_partition_of( 'public', 'part1', 'public', 'base', 'whatevs' ), false, 'is_partition_of( csch, ctab, psch, non-part ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'part1', 'base', 'whatevs' ), false, 'is_partition_of( ctab, non-part ptab, desc )', 'whatevs', '' ); -- Should find tables outside search path for explicit schema. SELECT * FROM check_test( is_partition_of( 'hide', 'hidden_part1', 'hide', 'hidden_parted', 'whatevs' ), true, 'is_partition_of( priv csch, ctab, priv psch, ptab, desc )', 'whatevs', '' ); -- But not when the schema is not specified. SELECT * FROM check_test( is_partition_of( 'hidden_part1', 'hidden_parted', 'whatevs' ), false, 'is_partition_of( priv ctab, priv ptab, desc )', 'whatevs', '' ); -- Should find explicit hidden table for public partition. SELECT * FROM check_test( is_partition_of( 'hide', 'part3', 'public', 'parted', 'whatevs' ), true, 'is_partition_of( priv csch, ctab, psch, ptab, desc )', 'whatevs', '' ); -- But still not when schemas not specified. SELECT * FROM check_test( is_partition_of( 'part3', 'hidden', 'whatevs' ), false, 'is_partition_of( priv ctab, ptab, desc )', 'whatevs', '' ); -- Should find public partition for hidden base. SELECT * FROM check_test( is_partition_of( 'public', 'not_hidden_part3', 'hide', 'hidden_parted', 'whatevs' ), true, 'is_partition_of( csch, ctab, priv psch, ptab, desc )', 'whatevs', '' ); -- But not if no schemas are specified. SELECT * FROM check_test( is_partition_of( 'not_hidden_part3', 'hidden_parted', 'whatevs' ), false, 'is_partition_of( ctab, priv ptab, desc )', 'whatevs', '' ); -- And of course, it should not work for nonexistent partitions. SELECT * FROM check_test( is_partition_of( 'public', 'nonesuch', 'public', 'nothing', 'whatevs' ), false, 'is_partition_of( csch, non-ctab, psch, non-ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'nonesuch', 'nothing', 'whatevs' ), false, 'is_partition_of( non-ctab, non-ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'public', 'part1', 'public', 'nothing', 'whatevs' ), false, 'is_partition_of( csch, ctab, psch, non-ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'nonesuch', 'part1', 'whatevs' ), false, 'is_partition_of( ctab, non-ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'public', 'nonesuch', 'public', 'parted', 'whatevs' ), false, 'is_partition_of( csch, non-ctab, psch, ptab, desc )', 'whatevs', '' ); SELECT * FROM check_test( is_partition_of( 'nonesuch', 'parted', 'whatevs' ), false, 'is_partition_of( non-ctab, ptab, desc )', 'whatevs', '' ); /****************************************************************************/ -- Test partitions_are(). SELECT * FROM check_test( partitions_are( 'public', 'parted', '{part1,part2,hide.part3}', 'hi' ), true, 'partitions_are( sch, tab, parts, desc )', 'hi', '' ); SELECT * FROM check_test( partitions_are( 'public', 'parted', '{part1,part2,hide.part3}'::name[] ), true, 'partitions_are( sch, tab, parts )', 'Table public.parted should have the correct partitions', '' ); SELECT * FROM check_test( partitions_are( 'parted', '{part1,part2,hide.part3}'::name[], 'hi' ), true, 'partitions_are( tab, parts, desc )', 'hi', '' ); SELECT * FROM check_test( partitions_are( 'parted', '{part1,part2,hide.part3}' ), true, 'partitions_are( tab, parts )', 'Table parted should have the correct partitions', '' ); -- Test diagnostics. SELECT * FROM check_test( partitions_are( 'public', 'parted', '{part1,part2of2,hide.part3}', 'hi' ), false, 'partitions_are( sch, tab, bad parts, desc )', 'hi', ' Extra partitions: part2 Missing partitions: part2of2' ); SELECT * FROM check_test( partitions_are( 'parted', '{part1,part2of2,hide.part3}'::name[], 'hi' ), false, 'partitions_are( tab, bad parts, desc )', 'hi', ' Extra partitions: part2 Missing partitions: part2of2' ); -- Test with the hidden schema. SELECT * FROM check_test( partitions_are( 'hide', 'hidden_parted', '{hide.hidden_part1,hide.hidden_part2,not_hidden_part3}', 'hi' ), true, 'partitions_are( hidden sch, tab, parts, desc )', 'hi', '' ); -- Should fail for partitioned table outside search path. SELECT * FROM check_test( partitions_are( 'hidden_parted', '{hide.hidden_part1,hide.hidden_part2,not_hidden_part3}'::name[], 'hi' ), false, 'partitions_are( hidden tab, parts, desc )', 'hi', ' Missing partitions: "hide.hidden_part1" "hide.hidden_part2" not_hidden_part3' ); -- Should not work for unpartitioned but inherited table SELECT * FROM check_test( partitions_are( 'public', 'base', '{sub}', 'hi' ), false, 'partitions_are( sch, non-parted tab, inherited tab, desc )', 'hi', ' Missing partitions: sub' ); SELECT * FROM check_test( partitions_are( 'base', '{sub}'::name[], 'hi' ), false, 'partitions_are( non-parted tab, inherited tab, desc )', 'hi', ' Missing partitions: sub' ); -- Should not work for non-existent table. SELECT * FROM check_test( partitions_are( 'public', 'nonesuch', '{part1}', 'hi' ), false, 'partitions_are( sch, non-existent tab, parts, desc )', 'hi', ' Missing partitions: part1' ); SELECT * FROM check_test( partitions_are( 'nonesuch', '{part1}'::name[], 'hi' ), false, 'partitions_are( non-existent tab, parts, desc )', 'hi', ' Missing partitions: part1' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/performs_ok.sql000066400000000000000000000034011455775703000174700ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(24); --SELECT * FROM no_plan(); /****************************************************************************/ -- Test performs_ok(). SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 500, 'whatever' ), true, 'simple select', 'whatever', '' ); SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 500 ), true, 'simple select no desc', 'Should run in less than 500 ms', '' ); SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 199.99 ), true, 'simple select numeric', 'Should run in less than 199.99 ms', '' ); PREPARE mytest AS SELECT TRUE; SELECT * FROM check_test( performs_ok( 'mytest', 100 ), true, 'simple prepare', 'Should run in less than 100 ms', '' ); SELECT * FROM check_test( performs_ok( 'EXECUTE mytest', 100 ), true, 'simple execute', 'Should run in less than 100 ms', '' ); SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 0, 'whatever' ), false, 'simple select fail', 'whatever', ' runtime: [[:digit:]]+([.][[:digit:]]+)? ms exceeds: 0 ms', true ); SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 0 ), false, 'simple select no desc fail', 'Should run in less than 0 ms', ' runtime: [[:digit:]]+([.][[:digit:]]+)? ms exceeds: 0 ms', true ); SELECT * FROM check_test( performs_ok( 'SELECT TRUE', 0.00 ), false, 'simple select no desc numeric fail', 'Should run in less than 0.00 ms', ' runtime: [[:digit:]]+([.][[:digit:]]+)? ms exceeds: 0.00 ms', true ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/performs_within.sql000066400000000000000000000036751455775703000203760ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(24); --SELECT * FROM no_plan(); /****************************************************************************/ -- Test performs_within(). SELECT * FROM check_test( performs_within( 'SELECT TRUE', 500, 500, 1, 'whatever' ), true, 'simple select', 'whatever', '' ); SELECT * FROM check_test( performs_within( 'SELECT TRUE', 500, 500, 1 ), true, 'simple select no desc', 'Should run within 500 +/- 500 ms', '' ); SELECT * FROM check_test( performs_within( 'SELECT TRUE', 99.99, 99.99 ), true, 'simple select numeric', 'Should run within 99.99 +/- 99.99 ms', '' ); PREPARE mytest AS SELECT TRUE; SELECT * FROM check_test( performs_within( 'mytest', 500, 500 ), true, 'simple prepare', 'Should run within 500 +/- 500 ms', '' ); SELECT * FROM check_test( performs_within( 'EXECUTE mytest', 500, 500 ), true, 'simple execute', 'Should run within 500 +/- 500 ms', '' ); SELECT * FROM check_test( performs_within( 'SELECT TRUE', 0, 0, 'whatever' ), false, 'simple select fail', 'whatever', ' average runtime: [[:digit:]]+([.][[:digit:]]+)? ms' || E'\n' || E' desired average: 0 \\+/- 0 ms', true ); SELECT * FROM check_test( performs_within( 'SELECT TRUE', 0, 0 ), false, 'simple select no desc fail', 'Should run within 0 +/- 0 ms', ' average runtime: [[:digit:]]+([.][[:digit:]]+)? ms' || E'\n' || E' desired average: 0 \\+/- 0 ms', true ); SELECT * FROM check_test( performs_within( 'SELECT TRUE', 0.0, 0.0 ), false, 'simple select no desc numeric fail', 'Should run within 0.0 +/- 0.0 ms', ' average runtime: [[:digit:]]+([.][[:digit:]]+)? ms' || E'\n' || E' desired average: 0.0 \\+/- 0.0 ms', true ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/pg73.sql000066400000000000000000000033531455775703000157300ustar00rootroot00000000000000\unset ECHO \i test/setup.sql select plan(39); select ok(true); select ok(true, 'true'); select ok(NOT false); select ok(NOT false, 'NOT false'); select ok(3 = 3); select ok(3 = 3, 'three'); select ok(1 != 2); select ok(1 <> 2); select isnt(1,2); select isnt(1,2,'1=2'); select is( now(), now(), 'now()=now()'); select is( '1 hour'::interval, '1 hour'::interval, '''1 hour''::interval, ''1 hour''::interval'); select is( now()::date, now()::date); select is( now()::date, now()::date, 'now=now date' ); select isnt( now()::date, now()::date + 1, 'now!=now+1' ); select is( now()::timestamp, now()::timestamp, 'now()=now() timestamp'); select is( now()::date, now()::date, 'now()=now() date'); select is( TRUE, TRUE, 'TRUE=TRUE' ); select isnt( TRUE, FALSE, 'TRUE!=FALSE' ); select is('a'::char, 'a'::char, 'a=a char'); select isnt('a'::char, 'b'::char, 'a!=b char'); select is('a'::text, 'a'::text, 'a=a text'); select isnt('a'::text, 'b'::text, 'a!=b text'); select is(3::int, 3::int, '3=3 int'); select isnt(3::int, 4::int, '3!=4 int'); select is(3::integer, 3::integer, '3=3 integer'); select isnt(3::integer, 4::integer, '3!=4 integer'); select is(3::int2, 3::int2, '3=3 int2'); select isnt(3::int2, 4::int2, '3!=4 int2'); select is(3::int4, 3::int4, '3=3 int4'); select isnt(3::int4, 4::int4, '3!=4 int4'); select is(3::int8, 3::int8, '3=3 int8'); select isnt(3::int8, 4::int8, '3!=4 int8'); select is(3.2::float, 3.2::float, '3.2=3.2 float'); select isnt(3.2::float, 4.5::float, '3.2!=4.5 float'); select is(3.2::float4, 3.2::float4, '3.2=3.2 float4'); select isnt(3.2::float4, 4.5::float4, '3.2!=4.5 float4'); select is(3.2::float8, 3.2::float8, '3.2=3.2 float8'); select isnt(3.2::float8, 4.5::float8, '3.2!=4.5 float8'); select * from finish(); ROLLBACK; pgtap-1.3.2/test/sql/pktap.sql000066400000000000000000000176111455775703000162710ustar00rootroot00000000000000\unset ECHO \i test/setup.sql -- \i sql/pgtap.sql SELECT plan(96); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), myint NUMERIC(8) ); -- This table has no pk CREATE TABLE public.pkless( id INT NOT NULL UNIQUE ); CREATE SCHEMA hide; CREATE TABLE hide.hidesometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), myint NUMERIC(8) ); RESET client_min_messages; /****************************************************************************/ -- Test has_pk(). SELECT * FROM check_test( has_pk( 'public', 'sometab', 'public.sometab should have a pk' ), true, 'has_pk( schema, table, description )', 'public.sometab should have a pk', '' ); SELECT * FROM check_test( has_pk( 'public', 'sometab'::name ), true, 'has_pk( schema, table )', 'Table public.sometab should have a primary key', '' ); SELECT * FROM check_test( has_pk( 'hide', 'hidesometab', 'hide.sometab should have a pk' ), true, 'has_pk( hideschema, hidetable, description )', 'hide.sometab should have a pk', '' ); SELECT * FROM check_test( has_pk( 'hide', 'hidesometab'::name ), true, 'has_pk( hideschema, hidetable )', 'Table hide.hidesometab should have a primary key', '' ); SELECT * FROM check_test( has_pk( 'sometab', 'sometab should have a pk' ), true, 'has_pk( table, description )', 'sometab should have a pk', '' ); SELECT * FROM check_test( has_pk( 'hidesometab', 'hidesometab should have a pk' ), false, 'has_pk( hidetable, description ) fail', 'hidesometab should have a pk', '' ); SELECT * FROM check_test( has_pk( 'sometab' ), true, 'has_pk( table )', 'Table sometab should have a primary key', '' ); SELECT * FROM check_test( has_pk( 'public', 'pkless', 'public.pkless should have a pk' ), false, 'has_pk( schema, table, description ) fail', 'public.pkless should have a pk', '' ); SELECT * FROM check_test( has_pk( 'pkless', 'pkless should have a pk' ), false, 'has_pk( table, description ) fail', 'pkless should have a pk', '' ); /****************************************************************************/ -- Test hasnt_pk(). SELECT * FROM check_test( hasnt_pk( 'public', 'sometab', 'public.sometab should not have a pk' ), false, 'hasnt_pk( schema, table, description )', 'public.sometab should not have a pk', '' ); SELECT * FROM check_test( hasnt_pk( 'sometab', 'sometab should not have a pk' ), false, 'hasnt_pk( table, description )', 'sometab should not have a pk', '' ); SELECT * FROM check_test( hasnt_pk( 'sometab' ), false, 'hasnt_pk( table )', 'Table sometab should not have a primary key', '' ); SELECT * FROM check_test( hasnt_pk( 'public', 'pkless', 'public.pkless should not have a pk' ), true, 'hasnt_pk( schema, table, description ) pass', 'public.pkless should not have a pk', '' ); SELECT * FROM check_test( hasnt_pk( 'pkless', 'pkless should not have a pk' ), true, 'hasnt_pk( table, description ) pass', 'pkless should not have a pk', '' ); /****************************************************************************/ -- Test col_is_pk(). SELECT * FROM check_test( col_is_pk( 'public', 'sometab', 'id', 'public.sometab.id should be a pk' ), true, 'col_is_pk( schema, table, column, description )', 'public.sometab.id should be a pk', '' ); SELECT * FROM check_test( col_is_pk( 'public', 'sometab', 'id'::name ), true, 'col_is_pk( schema, table, column )', 'Column public.sometab(id) should be a primary key', '' ); SELECT * FROM check_test( col_is_pk( 'sometab', 'id', 'sometab.id should be a pk' ), true, 'col_is_pk( table, column, description )', 'sometab.id should be a pk', '' ); SELECT * FROM check_test( col_is_pk( 'sometab', 'id' ), true, 'col_is_pk( table, column )', 'Column sometab(id) should be a primary key', '' ); SELECT * FROM check_test( col_is_pk( 'public', 'sometab', 'name', 'public.sometab.name should be a pk' ), false, 'col_is_pk( schema, table, column, description ) fail', 'public.sometab.name should be a pk', ' have: {id} want: {name}' ); SELECT * FROM check_test( col_is_pk( 'sometab', 'name', 'sometab.name should be a pk' ), false, 'col_is_pk( table, column, description ) fail', 'sometab.name should be a pk', ' have: {id} want: {name}' ); /****************************************************************************/ -- Test col_is_pk() with an array of columns. SET client_min_messages = warning; CREATE TABLE public.argh ( id INT NOT NULL, name TEXT NOT NULL, PRIMARY KEY (id, name) ); RESET client_min_messages; SELECT * FROM check_test( col_is_pk( 'public', 'argh', ARRAY['id', 'name'], 'id + name should be a pk' ), true, 'col_is_pk( schema, table, column[], description )', 'id + name should be a pk', '' ); SELECT * FROM check_test( col_is_pk( 'public', 'argh', ARRAY['id', 'name']::name[] ), true, 'col_is_pk( schema, table, column[] )', 'Columns public.argh(id, name) should be a primary key', '' ); SELECT * FROM check_test( col_is_pk( 'argh', ARRAY['id', 'name'], 'id + name should be a pk' ), true, 'col_is_pk( table, column[], description )', 'id + name should be a pk', '' ); SELECT * FROM check_test( col_is_pk( 'argh', ARRAY['id', 'name'] ), true, 'col_is_pk( table, column[] )', 'Columns argh(id, name) should be a primary key', '' ); /****************************************************************************/ -- Test col_isnt_pk(). SELECT * FROM check_test( col_isnt_pk( 'public', 'sometab', 'id', 'public.sometab.id should not be a pk' ), false, 'col_isnt_pk( schema, table, column, description )', 'public.sometab.id should not be a pk', ' have: {id} want: anything else' ); SELECT * FROM check_test( col_isnt_pk( 'sometab', 'id', 'sometab.id should not be a pk' ), false, 'col_isnt_pk( table, column, description )', 'sometab.id should not be a pk', ' have: {id} want: anything else' ); SELECT * FROM check_test( col_isnt_pk( 'sometab', 'id' ), false, 'col_isnt_pk( table, column )', 'Column sometab(id) should not be a primary key', ' have: {id} want: anything else' ); SELECT * FROM check_test( col_isnt_pk( 'public', 'sometab', 'name', 'public.sometab.name should not be a pk' ), true, 'col_isnt_pk( schema, table, column, description ) pass', 'public.sometab.name should not be a pk', '' ); SELECT * FROM check_test( col_isnt_pk( 'sometab', 'name', 'sometab.name should not be a pk' ), true, 'col_isnt_pk( table, column, description ) pass', 'sometab.name should not be a pk', '' ); /****************************************************************************/ -- Test col_isnt_pk() with an array of columns. SELECT * FROM check_test( col_isnt_pk( 'public', 'argh', ARRAY['id', 'foo'], 'id + foo should not be a pk' ), true, 'col_isnt_pk( schema, table, column[], description )', 'id + foo should not be a pk', '' ); SELECT * FROM check_test( col_isnt_pk( 'argh', ARRAY['id', 'foo'], 'id + foo should not be a pk' ), true, 'col_isnt_pk( table, column[], description )', 'id + foo should not be a pk', '' ); SELECT * FROM check_test( col_isnt_pk( 'argh', ARRAY['id', 'foo'] ), true, 'col_isnt_pk( table, column[] )', 'Columns argh(id, foo) should not be a primary key', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/policy.sql000066400000000000000000000431171455775703000164510ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(180); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.passwd( user_name TEXT UNIQUE NOT NULL, pwhash TEXT NOT NULL, uid INT PRIMARY KEY, gid INT NOT NULL, real_name TEXT NOT NULL, home_phone TEXT, extra_info TEXT, home_dir TEXT NOT NULL, shell TEXT NOT NULL ); CREATE ROLE root; CREATE ROLE bob; CREATE ROLE alice; CREATE ROLE daemon; INSERT INTO public.passwd VALUES ('admin','xxx',0,0,'Admin','111-222-3333',null,'/root','/bin/dash'); INSERT INTO public.passwd VALUES ('bob','xxx',1,1,'Bob','123-456-7890',null,'/home/bob','/bin/zsh'); INSERT INTO public.passwd VALUES ('alice','xxx',2,1,'Alice','098-765-4321',null,'/home/alice','/bin/zsh'); INSERT INTO public.passwd VALUES ('daemon','xxx',3,2,'daemon server',null,null,'/var/lib/daemon','/usr/sbin/nologin'); ALTER TABLE public.passwd ENABLE ROW LEVEL SECURITY; -- Create policies -- Administrator can see all rows and add any rows CREATE POLICY root_all ON public.passwd TO root USING (true) WITH CHECK (true); -- Normal users can view all rows CREATE POLICY all_view ON public.passwd FOR SELECT TO root, bob, daemon USING (true); -- Normal users can update their own records, but -- limit which shells a normal user is allowed to set CREATE POLICY user_mod ON public.passwd FOR UPDATE USING (current_user = user_name) WITH CHECK ( current_user = user_name AND shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh') ); -- Daemons can insert and delete records with gid > 100 CREATE POLICY daemon_insert ON public.passwd FOR INSERT TO daemon WITH CHECK (gid > 100); CREATE POLICY daemon_delete ON public.passwd FOR DELETE TO daemon USING (gid > 100); RESET client_min_messages; /****************************************************************************/ -- Test policies_are(). SELECT * FROM check_test( policies_are( 'public', 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete'], 'whatever' ), true, 'policies_are(schema, table, policies, desc)', 'whatever', '' ); SELECT * FROM check_test( policies_are( 'public', 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete'] ), true, 'policies_are(schema, table, policies)', 'Table public.passwd should have the correct policies', '' ); SELECT * FROM check_test( policies_are( 'public', 'passwd', ARRAY['all_view', 'user_mod', 'daemon_insert', 'daemon_delete'] ), false, 'policies_are(schema, table, policies) + extra', 'Table public.passwd should have the correct policies', ' Extra policies: root_all' ); SELECT * FROM check_test( policies_are( 'public', 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete', 'extra_policy'] ), false, 'policies_are(schema, table, policies) + missing', 'Table public.passwd should have the correct policies', ' Missing policies: extra_policy' ); SELECT * FROM check_test( policies_are( 'public', 'passwd', ARRAY['all_view', 'user_mod', 'daemon_insert', 'daemon_delete', 'extra_policy'] ), false, 'policies_are(schema, table, policies) + extra & missing', 'Table public.passwd should have the correct policies', ' Extra policies: root_all Missing policies: extra_policy' ); SELECT * FROM check_test( policies_are( 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete'], 'whatever' ), true, 'policies_are(table, policies, desc)', 'whatever', '' ); SELECT * FROM check_test( policies_are( 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete'] ), true, 'policies_are(table, policies)', 'Table passwd should have the correct policies', '' ); SELECT * FROM check_test( policies_are( 'passwd', ARRAY['all_view', 'user_mod', 'daemon_insert', 'daemon_delete'] ), false, 'policies_are(table, policies) + extra', 'Table passwd should have the correct policies', ' Extra policies: root_all' ); SELECT * FROM check_test( policies_are( 'passwd', ARRAY['root_all', 'all_view', 'user_mod', 'daemon_insert', 'daemon_delete', 'extra_policy'] ), false, 'policies_are(table, policies) + missing', 'Table passwd should have the correct policies', ' Missing policies: extra_policy' ); SELECT * FROM check_test( policies_are( 'passwd', ARRAY['all_view', 'user_mod', 'daemon_insert', 'daemon_delete', 'extra_policy'] ), false, 'policies_are(table, policies) + extra & missing', 'Table passwd should have the correct policies', ' Extra policies: root_all Missing policies: extra_policy' ); /****************************************************************************/ -- Test policy_roles_are(). SELECT * FROM check_test( policy_roles_are( 'public', 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon'], 'whatever' ), true, 'policy_roles_are(schema, table, policy, roles, desc)', 'whatever', '' ); SELECT * FROM check_test( policy_roles_are( 'public', 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon'] ), true, 'policy_roles_are(schema, table, policy, roles)', 'Policy all_view for table public.passwd should have the correct roles', '' ); SELECT * FROM check_test( policy_roles_are( 'public', 'passwd', 'all_view', ARRAY['bob', 'daemon'] ), false, 'policy_roles_are(schema, table, policy, roles) + extra', 'Policy all_view for table public.passwd should have the correct roles', ' Extra policy roles: root' ); SELECT * FROM check_test( policy_roles_are( 'public', 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon', 'alice'] ), false, 'policy_roles_are(schema, table, policy, roles) + missing', 'Policy all_view for table public.passwd should have the correct roles', ' Missing policy roles: alice' ); SELECT * FROM check_test( policy_roles_are( 'public', 'passwd', 'all_view', ARRAY['bob', 'daemon', 'alice'] ), false, 'policy_roles_are(schema, table, policy, roles) + extra & missing', 'Policy all_view for table public.passwd should have the correct roles', ' Extra policy roles: root Missing policy roles: alice' ); SELECT * FROM check_test( policy_roles_are( 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon'], 'whatever' ), true, 'policy_roles_are(table, policy, roles, desc)', 'whatever', '' ); SELECT * FROM check_test( policy_roles_are( 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon'] ), true, 'policy_roles_are(table, policy, roles)', 'Policy all_view for table passwd should have the correct roles', '' ); SELECT * FROM check_test( policy_roles_are( 'passwd', 'all_view', ARRAY['bob', 'daemon'] ), false, 'policy_roles_are(table, policy, roles) + extra', 'Policy all_view for table passwd should have the correct roles', ' Extra policy roles: root' ); SELECT * FROM check_test( policy_roles_are( 'passwd', 'all_view', ARRAY['root', 'bob', 'daemon', 'alice'] ), false, 'policy_roles_are(table, policy, roles) + missing', 'Policy all_view for table passwd should have the correct roles', ' Missing policy roles: alice' ); SELECT * FROM check_test( policy_roles_are( 'passwd', 'all_view', ARRAY['bob', 'daemon', 'alice'] ), false, 'policy_roles_are(table, policy, roles) + extra & missing', 'Policy all_view for table passwd should have the correct roles', ' Extra policy roles: root Missing policy roles: alice' ); /****************************************************************************/ -- Test policy_cmd_is(). SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'all_view', 'select', 'whatever' ), true, 'policy_cmd_is(schema, table, policy, command, desc) for SELECT', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'all_view'::NAME, 'select' ), true, 'policy_cmd_is(schema, table, policy, command) for SELECT', 'Policy all_view for table public.passwd should apply to SELECT command', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'all_view', 'select', 'whatever' ), true, 'policy_cmd_is(table, policy, command, desc) for SELECT', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'all_view', 'select' ), true, 'policy_cmd_is(table, policy, command) for SELECT', 'Policy all_view for table passwd should apply to SELECT command', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'all_view', 'delete', 'whatever' ), false, 'policy_cmd_is(schema, table, policy, command, desc) for SELECT should fail', 'whatever', ' have: SELECT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'all_view'::NAME, 'delete' ), false, 'policy_cmd_is(schema, table, policy, command) for SELECT should fail', 'Policy all_view for table public.passwd should apply to DELETE command', ' have: SELECT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'all_view', 'delete', 'whatever' ), false, 'policy_cmd_is(table, policy, command, desc) for SELECT should fail', 'whatever', ' have: SELECT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'all_view', 'delete' ), false, 'policy_cmd_is(table, policy, command) for SELECT should fail', 'Policy all_view for table passwd should apply to DELETE command', ' have: SELECT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_insert', 'insert', 'whatever' ), true, 'policy_cmd_is(schema, table, policy, command, desc) for INSERT', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_insert'::NAME, 'insert' ), true, 'policy_cmd_is(schema, table, policy, command) for INSERT', 'Policy daemon_insert for table public.passwd should apply to INSERT command', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_insert', 'insert', 'whatever' ), true, 'policy_cmd_is(table, policy, command, desc) for INSERT', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_insert', 'insert' ), true, 'policy_cmd_is(table, policy, command) for INSERT', 'Policy daemon_insert for table passwd should apply to INSERT command', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_insert', 'delete', 'whatever' ), false, 'policy_cmd_is(schema, table, policy, command, desc) for INSERT should fail', 'whatever', ' have: INSERT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_insert'::NAME, 'delete' ), false, 'policy_cmd_is(schema, table, policy, command) for INSERT should fail', 'Policy daemon_insert for table public.passwd should apply to DELETE command', ' have: INSERT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_insert', 'delete', 'whatever' ), false, 'policy_cmd_is(table, policy, command, desc) for INSERT should fail', 'whatever', ' have: INSERT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_insert', 'delete' ), false, 'policy_cmd_is(table, policy, command) for INSERT should fail', 'Policy daemon_insert for table passwd should apply to DELETE command', ' have: INSERT want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'user_mod', 'update', 'whatever' ), true, 'policy_cmd_is(schema, table, policy, command, desc) for UPDATE', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'user_mod'::NAME, 'update' ), true, 'policy_cmd_is(schema, table, policy, command) for UPDATE', 'Policy user_mod for table public.passwd should apply to UPDATE command', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'user_mod', 'update', 'whatever' ), true, 'policy_cmd_is(table, policy, command, desc) for UPDATE', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'user_mod', 'update' ), true, 'policy_cmd_is(table, policy, command) for UPDATE', 'Policy user_mod for table passwd should apply to UPDATE command', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'user_mod', 'delete', 'whatever' ), false, 'policy_cmd_is(schema, table, policy, command, desc) for UPDATE should fail', 'whatever', ' have: UPDATE want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'user_mod'::NAME, 'all' ), false, 'policy_cmd_is(schema, table, policy, command) for UPDATE should fail', 'Policy user_mod for table public.passwd should apply to ALL command', ' have: UPDATE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'user_mod', 'all', 'whatever' ), false, 'policy_cmd_is(table, policy, command, desc) for UPDATE should fail', 'whatever', ' have: UPDATE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'user_mod', 'all' ), false, 'policy_cmd_is(table, policy, command) for UPDATE should fail', 'Policy user_mod for table passwd should apply to ALL command', ' have: UPDATE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_delete', 'delete', 'whatever' ), true, 'policy_cmd_is(schema, table, policy, command, desc) for DELETE', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_delete'::NAME, 'delete' ), true, 'policy_cmd_is(schema, table, policy, command) for DELETE', 'Policy daemon_delete for table public.passwd should apply to DELETE command', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_delete', 'delete', 'whatever' ), true, 'policy_cmd_is(table, policy, command, desc) for DELETE', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_delete', 'delete' ), true, 'policy_cmd_is(table, policy, command) for DELETE', 'Policy daemon_delete for table passwd should apply to DELETE command', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_delete', 'all', 'whatever' ), false, 'policy_cmd_is(schema, table, policy, command, desc) for DELETE should fail', 'whatever', ' have: DELETE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'daemon_delete'::NAME, 'all' ), false, 'policy_cmd_is(schema, table, policy, command) for DELETE should fail', 'Policy daemon_delete for table public.passwd should apply to ALL command', ' have: DELETE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_delete', 'all', 'whatever' ), false, 'policy_cmd_is(table, policy, command, desc) for DELETE should fail', 'whatever', ' have: DELETE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'daemon_delete', 'all' ), false, 'policy_cmd_is(table, policy, command) for DELETE should fail', 'Policy daemon_delete for table passwd should apply to ALL command', ' have: DELETE want: ALL' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'root_all', 'all', 'whatever' ), true, 'policy_cmd_is(schema, table, policy, command, desc) for ALL', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'root_all'::NAME, 'all' ), true, 'policy_cmd_is(schema, table, policy, command) for ALL', 'Policy root_all for table public.passwd should apply to ALL command', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'root_all', 'all', 'whatever' ), true, 'policy_cmd_is(table, policy, command, desc) for ALL', 'whatever', '' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'root_all', 'all' ), true, 'policy_cmd_is(table, policy, command) for ALL', 'Policy root_all for table passwd should apply to ALL command', '' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'root_all', 'delete', 'whatever' ), false, 'policy_cmd_is(schema, table, policy, command, desc) for ALL should fail', 'whatever', ' have: ALL want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'public', 'passwd', 'root_all'::NAME, 'delete' ), false, 'policy_cmd_is(schema, table, policy, command) for ALL should fail', 'Policy root_all for table public.passwd should apply to DELETE command', ' have: ALL want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'root_all', 'delete', 'whatever' ), false, 'policy_cmd_is(table, policy, command, desc) for ALL should fail', 'whatever', ' have: ALL want: DELETE' ); SELECT * FROM check_test( policy_cmd_is( 'passwd', 'root_all', 'delete' ), false, 'policy_cmd_is(table, policy, command) for ALL should fail', 'Policy root_all for table passwd should apply to DELETE command', ' have: ALL want: DELETE' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/privs.sql000066400000000000000000001765301455775703000163230ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(372); --SELECT * FROM no_plan(); SET client_min_messages = warning; CREATE SCHEMA ha; CREATE TABLE ha.sometab(id INT); CREATE SEQUENCE ha.someseq; CREATE SCHEMA "LOL"; CREATE TABLE "LOL"."ATable"("AColumn" INT); CREATE SEQUENCE "LOL"."ASeq"; -- Include the new schemas in the path. CREATE OR REPLACE FUNCTION set_search_path() returns setof text as $$ BEGIN IF pg_version_num() < 80200 THEN EXECUTE 'SET search_path = ha, "LOL", ' || regexp_replace(current_setting('search_path'), '[$][^,]+,', '') || ', pg_catalog'; RETURN; ELSE EXECUTE 'SET search_path = ha, "LOL", ' || current_setting('search_path') || ', pg_catalog'; END IF; END; $$ language plpgsql; SELECT * FROM set_search_path(); RESET client_min_messages; /****************************************************************************/ -- Test table_privs_are(). SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', current_user, _table_privs(), 'whatever' ), true, 'table_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( table_privs_are( 'LOL', 'ATable', current_user, _table_privs(), 'whatever' ), true, 'table_privs_are(LOL, ATable, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', current_user, _table_privs() ), true, 'table_privs_are(sch, tab, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(_table_privs(), ', ') || ' on table ha.sometab' , '' ); SELECT * FROM check_test( table_privs_are( 'LOL', 'ATable', current_user, _table_privs() ), true, 'table_privs_are(LOL, ATable, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(_table_privs(), ', ') || ' on table "LOL"."ATable"' , '' ); SELECT * FROM check_test( table_privs_are( 'sometab', current_user, _table_privs(), 'whatever' ), true, 'table_privs_are(tab, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( table_privs_are( 'ATable', current_user, _table_privs(), 'whatever' ), true, 'table_privs_are(ATable, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( table_privs_are( 'sometab', current_user, _table_privs() ), true, 'table_privs_are(tab, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(_table_privs(), ', ') || ' on table sometab' , '' ); SELECT * FROM check_test( table_privs_are( 'ATable', current_user, _table_privs() ), true, 'table_privs_are(ATable, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(_table_privs(), ', ') || ' on table "ATable"' , '' ); CREATE OR REPLACE FUNCTION run_extra_fails() RETURNS SETOF TEXT LANGUAGE plpgsql AS $$ DECLARE allowed_privs TEXT[]; test_privs TEXT[] := '{}'; missing_privs TEXT[] := '{}'; tap record; last_index INTEGER; BEGIN -- Test table failure. allowed_privs := _table_privs(); last_index := array_upper(allowed_privs, 1); FOR i IN 1..last_index - 2 LOOP test_privs := test_privs || allowed_privs[i]; END LOOP; FOR i IN last_index - 1..last_index LOOP missing_privs := missing_privs || allowed_privs[i]; END LOOP; FOR tap IN SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', current_user, test_privs, 'whatever' ), false, 'table_privs_are(sch, tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( table_privs_are( 'sometab', current_user, test_privs, 'whatever' ), false, 'table_privs_are(tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; END; $$; SELECT * FROM run_extra_fails(); -- Create another role. CREATE USER __someone_else; SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', '__someone_else', _table_privs(), 'whatever' ), false, 'table_privs_are(sch, tab, other, privs, desc)', 'whatever', ' Missing privileges: ' || array_to_string(_table_privs(), E'\n ') ); -- Grant them some permission. GRANT SELECT, INSERT, UPDATE, DELETE ON ha.sometab TO __someone_else; SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[ 'SELECT', 'INSERT', 'UPDATE', 'DELETE' ], 'whatever'), true, 'table_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ); -- Try a non-existent table. SELECT * FROM check_test( table_privs_are( 'ha', 'nonesuch', current_user, _table_privs(), 'whatever' ), false, 'table_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Table ha.nonesuch does not exist' ); -- Try a non-existent user. SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', '__nonesuch', _table_privs(), 'whatever' ), false, 'table_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Role __nonesuch does not exist' ); -- Test default description with no permissions. SELECT * FROM check_test( table_privs_are( 'ha', 'sometab', '__nonesuch', '{}'::text[] ), false, 'table_privs_are(sch, tab, role, no privs)', 'Role __nonesuch should be granted no privileges on table ha.sometab' , ' Role __nonesuch does not exist' ); SELECT * FROM check_test( table_privs_are( 'sometab', '__nonesuch', '{}'::text[] ), false, 'table_privs_are(tab, role, no privs)', 'Role __nonesuch should be granted no privileges on table sometab' , ' Role __nonesuch does not exist' ); /****************************************************************************/ -- Test database_privileges_are(). SELECT * FROM check_test( database_privs_are( current_database(), current_user, _db_privs(), 'whatever' ), true, 'database_privs_are(db, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( database_privs_are( current_database(), current_user, _db_privs() ), true, 'database_privs_are(db, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(_db_privs(), ', ') || ' on database ' || quote_ident( current_database() ), '' ); -- Try nonexistent database. SELECT * FROM check_test( database_privs_are( '__nonesuch', current_user, _db_privs(), 'whatever' ), false, 'database_privs_are(non-db, role, privs, desc)', 'whatever', ' Database __nonesuch does not exist' ); -- Try nonexistent user. SELECT * FROM check_test( database_privs_are( current_database(), '__noone', _db_privs(), 'whatever' ), false, 'database_privs_are(db, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ); -- Try another user. SELECT * FROM check_test( database_privs_are( current_database(), '__someone_else', _db_privs(), 'whatever' ), false, 'database_privs_are(db, ungranted, privs, desc)', 'whatever', ' Missing privileges: CREATE' ); -- Try a subset of privs. SELECT * FROM check_test( database_privs_are( current_database(), current_user, CASE WHEN pg_version_num() < 80200 THEN ARRAY['CREATE'] ELSE ARRAY['CREATE', 'CONNECT'] END, 'whatever' ), false, 'database_privs_are(db, ungranted, privs, desc)', 'whatever', ' Extra privileges: TEMPORARY' ); -- Try testing default description for no permissions. SELECT * FROM check_test( database_privs_are( current_database(), '__noone', '{}'::text[] ), false, 'database_privs_are(db, non-role, no privs)', 'Role __noone should be granted no privileges on database ' || quote_ident( current_database() ), ' Role __noone does not exist' ); /****************************************************************************/ -- Test function_privs_are(). CREATE OR REPLACE FUNCTION public.foo(int, text) RETURNS VOID LANGUAGE SQL AS ''; CREATE OR REPLACE FUNCTION "LOL"."DoIt"(int, text) RETURNS VOID LANGUAGE SQL AS ''; SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(sch, func, args, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'LOL', 'DoIt', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(LOL, DoIt, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'] ), true, 'function_privs_are(sch, func, args, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function public.foo(integer, text)' '' ); SELECT * FROM check_test( function_privs_are( 'LOL', 'DoIt', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'] ), true, 'function_privs_are(LOL, DoIt, args, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function "LOL"."DoIt"(integer, text)' '' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(func, args, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'DoIt', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(DoIt, args, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'] ), true, 'function_privs_are(func, args, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function foo(integer, text)' '' ); SELECT * FROM check_test( function_privs_are( 'DoIt', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'] ), true, 'function_privs_are(DoIt, args, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted EXECUTE on function "DoIt"(integer, text)' '' ); -- Try a nonexistent funtion. SELECT * FROM check_test( function_privs_are( 'public', '__nonesuch', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(sch, non-func, args, role, privs, desc)', 'whatever', ' Function public.__nonesuch(integer, text) does not exist' ); SELECT * FROM check_test( function_privs_are( '__nonesuch', ARRAY['integer', 'text'], current_user, ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(non-func, args, role, privs, desc)', 'whatever', ' Function __nonesuch(integer, text) does not exist' ); -- Try a nonexistent user. SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], '__noone', ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(sch, func, args, noone, privs, desc)', 'whatever', ' Role __noone does not exist' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], '__noone', ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(func, args, noone, privs, desc)', 'whatever', ' Role __noone does not exist' ); -- Try an unprivileged user. SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], '__someone_else', ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(sch, func, args, other, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], '__someone_else', ARRAY['EXECUTE'], 'whatever' ), true, 'function_privs_are(func, args, other, privs, desc)', 'whatever', '' ); REVOKE EXECUTE ON FUNCTION public.foo(int, text) FROM PUBLIC; -- Now fail. SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], '__someone_else', ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(sch, func, args, unpriv, privs, desc)', 'whatever', ' Missing privileges: EXECUTE' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], '__someone_else', ARRAY['EXECUTE'], 'whatever' ), false, 'function_privs_are(func, args, unpriv, privs, desc)', 'whatever', ' Missing privileges: EXECUTE' ); -- It should work for an empty array. SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], '__someone_else', '{}'::text[], 'whatever' ), true, 'function_privs_are(sch, func, args, unpriv, empty, desc)', 'whatever', '' ); SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], '__someone_else', '{}'::text[] ), true, 'function_privs_are(sch, func, args, unpriv, empty)', 'Role __someone_else should be granted no privileges on function public.foo(integer, text)' '' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], '__someone_else', '{}'::text[] ), true, 'function_privs_are(func, args, unpriv, empty)', 'Role __someone_else should be granted no privileges on function foo(integer, text)' '' ); -- Empty for the current user should yeild an extra permission. SELECT * FROM check_test( function_privs_are( 'public', 'foo', ARRAY['integer', 'text'], current_user, '{}'::text[], 'whatever' ), false, 'function_privs_are(sch, func, args, unpriv, privs, desc)', 'whatever', ' Extra privileges: EXECUTE' ); SELECT * FROM check_test( function_privs_are( 'foo', ARRAY['integer', 'text'], current_user, '{}'::text[], 'whatever' ), false, 'function_privs_are(func, args, unpriv, privs, desc)', 'whatever', ' Extra privileges: EXECUTE' ); -- Try a really long function signature. CREATE OR REPLACE FUNCTION public.function_with_a_moderate_signature( anyelement, date, text[], boolean ) RETURNS VOID LANGUAGE SQL AS ''; SELECT * FROM check_test( function_privs_are( 'public', 'function_with_a_moderate_signature', ARRAY['anyelement','date','text[]','boolean'], current_user, ARRAY['EXECUTE'], 'whatever' ), true, 'long function signature', 'whatever', '' ); /****************************************************************************/ -- Test language_privilege_is(). SELECT * FROM check_test( language_privs_are( 'plpgsql', current_user, '{USAGE}', 'whatever' ), true, 'language_privs_are(lang, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( language_privs_are( 'plpgsql', current_user, '{USAGE}' ), true, 'language_privs_are(lang, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted USAGE on language plpgsql', '' ); -- Try nonexistent language. SELECT * FROM check_test( language_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ), false, 'language_privs_are(non-lang, role, privs, desc)', 'whatever', ' Language __nonesuch does not exist' ); -- Try nonexistent user. SELECT * FROM check_test( language_privs_are( 'plpgsql', '__noone', '{USAGE}', 'whatever' ), false, 'language_privs_are(lang, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ); -- Try another user. REVOKE USAGE ON LANGUAGE plpgsql FROM public; SELECT * FROM check_test( language_privs_are( 'plpgsql', '__someone_else', '{USAGE}', 'whatever' ), false, 'language_privs_are(lang, ungranted, privs, desc)', 'whatever', ' Missing privileges: USAGE' ); -- Try testing default description for no permissions. SELECT * FROM check_test( language_privs_are( 'plpgsql', '__someone_else', '{}'::text[] ), true, 'language_privs_are(lang, role, no privs)', 'Role __someone_else should be granted no privileges on language plpgsql', '' ); /****************************************************************************/ -- Test schema_privileges_are(). SELECT * FROM check_test( schema_privs_are( current_schema(), current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ), true, 'schema_privs_are(schema, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( schema_privs_are( 'LOL', current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ), true, 'schema_privs_are(LOL, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( schema_privs_are( current_schema(), current_user, ARRAY['CREATE', 'USAGE'] ), true, 'schema_privs_are(schema, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['CREATE', 'USAGE'], ', ') || ' on schema ' || current_schema(), '' ); SELECT * FROM check_test( schema_privs_are( 'LOL', current_user, ARRAY['CREATE', 'USAGE'] ), true, 'schema_privs_are(LOL, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['CREATE', 'USAGE'], ', ') || ' on schema "LOL"', '' ); -- Try nonexistent schema. SELECT * FROM check_test( schema_privs_are( '__nonesuch', current_user, ARRAY['CREATE', 'USAGE'], 'whatever' ), false, 'schema_privs_are(non-schema, role, privs, desc)', 'whatever', ' Schema __nonesuch does not exist' ); -- Try nonexistent user. SELECT * FROM check_test( schema_privs_are( current_schema(), '__noone', ARRAY['CREATE', 'USAGE'], 'whatever' ), false, 'schema_privs_are(schema, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ); -- Try another user. SELECT * FROM check_test( schema_privs_are( current_schema(), '__someone_else', ARRAY['CREATE', 'USAGE'], 'whatever' ), false, 'schema_privs_are(schema, ungranted, privs, desc)', 'whatever', ' Missing privileges: CREATE USAGE' ); -- Try a subset of privs. SELECT * FROM check_test( schema_privs_are( current_schema(), current_user, ARRAY['CREATE'], 'whatever' ), false, 'schema_privs_are(schema, ungranted, privs, desc)', 'whatever', ' Extra privileges: USAGE' ); -- Try testing default description for no permissions. SELECT * FROM check_test( schema_privs_are( current_schema(), '__noone', '{}'::text[] ), false, 'schema_privs_are(schema, non-role, no privs)', 'Role __noone should be granted no privileges on schema ' || current_schema(), ' Role __noone does not exist' ); /****************************************************************************/ -- Test tablespace_privilege_is(). SELECT * FROM check_test( tablespace_privs_are( 'pg_default', current_user, '{CREATE}', 'whatever' ), true, 'tablespace_privs_are(tablespace, role, privs, desc)', 'whatever', '' ); SELECT * FROM check_test( tablespace_privs_are( 'pg_default', current_user, '{CREATE}' ), true, 'tablespace_privs_are(tablespace, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted CREATE on tablespace pg_default', '' ); -- Try nonexistent tablespace. SELECT * FROM check_test( tablespace_privs_are( '__nonesuch', current_user, '{CREATE}', 'whatever' ), false, 'tablespace_privs_are(non-tablespace, role, privs, desc)', 'whatever', ' Tablespace __nonesuch does not exist' ); -- Try nonexistent user. SELECT * FROM check_test( tablespace_privs_are( 'pg_default', '__noone', '{CREATE}', 'whatever' ), false, 'tablespace_privs_are(tablespace, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ); -- Try another user. REVOKE CREATE ON TABLESPACE pg_default FROM public; SELECT * FROM check_test( tablespace_privs_are( 'pg_default', '__someone_else', '{CREATE}', 'whatever' ), false, 'tablespace_privs_are(tablespace, ungranted, privs, desc)', 'whatever', ' Missing privileges: CREATE' ); -- Try testing default description for no permissions. SELECT * FROM check_test( tablespace_privs_are( 'pg_default', '__someone_else', '{}'::text[] ), true, 'tablespace_privs_are(tablespace, role, no privs)', 'Role __someone_else should be granted no privileges on tablespace pg_default', '' ); /****************************************************************************/ -- Test sequence_privilege_is(). CREATE FUNCTION test_sequence() RETURNS SETOF TEXT AS $$ DECLARE allowed_privs TEXT[]; test_privs TEXT[]; missing_privs TEXT[]; tap record; last_index INTEGER; BEGIN IF pg_version_num() >= 90000 THEN FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', current_user, ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'LOL', 'ASeq', current_user, ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'sequence_privs_are(LOL, ASeq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ), true, 'sequence_privs_are(sch, seq, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ') || ' on sequence ha.someseq' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'LOL', 'ASeq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ), true, 'sequence_privs_are(sch, seq, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ') || ' on sequence "LOL"."ASeq"' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'someseq', current_user, ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'sequence_privs_are(seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ASeq', current_user, ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'sequence_privs_are(ASeq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'someseq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ), true, 'sequence_privs_are(seq, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ') || ' on sequence someseq' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ASeq', current_user, ARRAY['USAGE', 'SELECT', 'UPDATE'] ), true, 'sequence_privs_are(seq, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['USAGE', 'SELECT', 'UPDATE'], ', ') || ' on sequence "ASeq"' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test sequence failure. allowed_privs := ARRAY['USAGE', 'SELECT', 'UPDATE']; last_index := array_upper(allowed_privs, 1); FOR i IN 1..last_index - 2 LOOP test_privs := test_privs || allowed_privs[i]; END LOOP; FOR i IN last_index - 1..last_index LOOP missing_privs := missing_privs || allowed_privs[i]; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', current_user, test_privs, 'whatever' ), false, 'sequence_privs_are(sch, seq, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'someseq', current_user, test_privs, 'whatever' ), false, 'sequence_privs_are(seq, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', '__someone_else', ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'sequence_privs_are(sch, seq, other, privs, desc)', 'whatever', ' Missing privileges: ' || array_to_string(ARRAY['SELECT', 'UPDATE', 'USAGE'], E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Grant them some permission. GRANT SELECT, UPDATE ON ha.someseq TO __someone_else; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', '__someone_else', ARRAY[ 'SELECT', 'UPDATE' ], 'whatever'), true, 'sequence_privs_are(sch, seq, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent sequence. FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'nonesuch', current_user, ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', ' Sequence ha.nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', '__nonesuch', ARRAY[ 'USAGE', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'ha', 'someseq', '__nonesuch', '{}'::text[] ), false, 'sequence_privs_are(sch, seq, role, no privs)', 'Role __nonesuch should be granted no privileges on sequence ha.someseq' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( sequence_privs_are( 'someseq', '__nonesuch', '{}'::text[] ), false, 'sequence_privs_are(seq, role, no privs)', 'Role __nonesuch should be granted no privileges on sequence someseq' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(LOL, ASeq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(sch, seq, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(sch, seq, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(ASeq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(seq, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(seq, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(sch, seq, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(seq, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(sch, seq, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Grant them some permission. FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'sequence_privs_are(sch, seq, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent sequence. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(sch, seq, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(sch, seq, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'sequence_privs_are(seq, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_sequence(); /****************************************************************************/ -- Test any_column_privs_are(). CREATE FUNCTION test_anycols() RETURNS SETOF TEXT AS $$ DECLARE allowed_privs TEXT[]; test_privs TEXT[]; missing_privs TEXT[]; tap record; last_index INTEGER; BEGIN IF pg_version_num() >= 80400 THEN FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'any_column_privs_are(sch, tab, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on any column in ha.sometab' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'sometab', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'any_column_privs_are(tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'sometab', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'any_column_privs_are(tab, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on any column in sometab' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test table failure. allowed_privs := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; last_index := array_upper(allowed_privs, 1); FOR i IN 1..last_index - 2 LOOP test_privs := test_privs || allowed_privs[i]; END LOOP; FOR i IN last_index - 1..last_index LOOP missing_privs := missing_privs || allowed_privs[i]; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', current_user, test_privs, 'whatever' ), false, 'any_column_privs_are(sch, tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'sometab', current_user, test_privs, 'whatever' ), false, 'any_column_privs_are(tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'any_column_privs_are(sch, tab, other, privs, desc)', 'whatever', ' Missing privileges: ' || array_to_string(ARRAY['REFERENCES'], E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', '__someone_else', ARRAY[ 'SELECT', 'INSERT', 'UPDATE' ], 'whatever'), true, 'any_column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent table. FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'nonesuch', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Table ha.nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', '__nonesuch', ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'ha', 'sometab', '__nonesuch', '{}'::text[] ), false, 'any_column_privs_are(sch, tab, role, no privs)', 'Role __nonesuch should be granted no privileges on any column in ha.sometab' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( any_column_privs_are( 'sometab', '__nonesuch', '{}'::text[] ), false, 'any_column_privs_are(tab, role, no privs)', 'Role __nonesuch should be granted no privileges on any column in sometab' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'any_column_privs_are(sch, tab, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'any_column_privs_are(tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'any_column_privs_are(tab, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(sch, tab, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(tab, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'any_column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent table. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(sch, tab, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'any_column_privs_are(tab, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_anycols(); /****************************************************************************/ -- Test column_privs_are(). CREATE FUNCTION test_cols() RETURNS SETOF TEXT AS $$ DECLARE allowed_privs TEXT[]; test_privs TEXT[]; missing_privs TEXT[]; tap record; last_index INTEGER; BEGIN IF pg_version_num() >= 80400 THEN FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'column_privs_are(sch, tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'LOL', 'ATable', 'AColumn', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'column_privs_are(LOL, ATable, AColumn, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'column_privs_are(sch, tab, col, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on column ha.sometab.id' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'LOL', 'ATable', 'AColumn', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'column_privs_are(LOL, ATable, AColumn, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on column "LOL"."ATable"."AColumn"' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'sometab', 'id', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'column_privs_are(tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ATable', 'AColumn', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), true, 'column_privs_are(tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'sometab', 'id', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'column_privs_are(tab, col, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on column sometab.id' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ATable', 'AColumn', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ] ), true, 'column_privs_are(tab, col, role, privs)', 'Role ' || quote_ident(current_user) || ' should be granted ' || array_to_string(ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE'], ', ') || ' on column "ATable"."AColumn"' , '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test table failure. allowed_privs := ARRAY['INSERT', 'REFERENCES', 'SELECT', 'UPDATE']; last_index := array_upper(allowed_privs, 1); FOR i IN 1..last_index - 2 LOOP test_privs := test_privs || allowed_privs[i]; END LOOP; FOR i IN last_index - 1..last_index LOOP missing_privs := missing_privs || allowed_privs[i]; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', current_user, test_privs, 'whatever' ), false, 'column_privs_are(sch, tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'sometab', 'id', current_user, test_privs, 'whatever' ), false, 'column_privs_are(tab, role, some privs, desc)', 'whatever', ' Extra privileges: ' || array_to_string(missing_privs, E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', '__someone_else', ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'column_privs_are(sch, tab, other, privs, desc)', 'whatever', ' Missing privileges: ' || array_to_string(ARRAY['REFERENCES'], E'\n ') ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Grant them some permission. EXECUTE 'GRANT SELECT, INSERT, UPDATE (id) ON ha.sometab TO __someone_else;'; FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', '__someone_else', ARRAY[ 'SELECT', 'INSERT', 'UPDATE' ], 'whatever'), true, 'column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent table. FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'nonesuch', 'id', current_user, ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'column_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Table ha.nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', '__nonesuch', ARRAY[ 'INSERT', 'REFERENCES', 'SELECT', 'UPDATE' ], 'whatever' ), false, 'column_privs_are(sch, tab, role, privs, desc)', 'whatever', ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( column_privs_are( 'ha', 'sometab', 'id', '__nonesuch', '{}'::text[] ), false, 'column_privs_are(sch, tab, role, no privs)', 'Role __nonesuch should be granted no privileges on column ha.sometab.id' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( column_privs_are( 'sometab', 'id', '__nonesuch', '{}'::text[] ), false, 'column_privs_are(tab, role, no privs)', 'Role __nonesuch should be granted no privileges on column sometab.id' , ' Role __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it. FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(sch, tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(LOL, ATable, AColumn, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(sch, tab, col, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(LOL, ATable, AColumn, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(tab, col, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(tab, col, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(tab, col, role, privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(sch, tab, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(tab, role, some privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'column_privs_are(sch, tab, other, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent table. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try a non-existent user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(sch, tab, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Test default description with no permissions. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(sch, tab, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'column_privs_are(tab, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_cols(); /****************************************************************************/ -- Test fdw_privs_are(). CREATE FUNCTION test_fdw() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 80400 THEN EXECUTE 'CREATE FOREIGN DATA WRAPPER dummy;'; EXECUTE 'CREATE FOREIGN DATA WRAPPER "SomeFDW";'; FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'dummy', current_user, '{USAGE}', 'whatever' ), true, 'fdw_privs_are(fdw, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'SomeFDW', current_user, '{USAGE}', 'whatever' ), true, 'fdw_privs_are(SomeFDW, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'dummy', current_user, '{USAGE}' ), true, 'fdw_privs_are(fdw, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted USAGE on FDW dummy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'SomeFDW', current_user, '{USAGE}' ), true, 'fdw_privs_are(SomeFDW, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted USAGE on FDW "SomeFDW"', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent fdw. FOR tap IN SELECT * FROM check_test( fdw_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ), false, 'fdw_privs_are(non-fdw, role, privs, desc)', 'whatever', ' FDW __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent user. FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'dummy', '__noone', '{USAGE}', 'whatever' ), false, 'fdw_privs_are(fdw, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try another user. FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'dummy', '__someone_else', '{USAGE}', 'whatever' ), false, 'fdw_privs_are(fdw, ungranted, privs, desc)', 'whatever', ' Missing privileges: USAGE' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try testing default description for no permissions. FOR tap IN SELECT * FROM check_test( fdw_privs_are( 'dummy', '__someone_else', '{}'::text[] ), true, 'fdw_privs_are(fdw, role, no privs)', 'Role __someone_else should be granted no privileges on FDW dummy', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'fdw_privs_are(fdw, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'fdw_privs_are(SomeFDW, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'fdw_privs_are(fdw, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'fdw_privs_are(SomeFDW, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent fdw. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'fdw_privs_are(non-fdw, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'fdw_privs_are(fdw, non-role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try another user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'fdw_privs_are(fdw, ungranted, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try testing default description for no permissions. FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'fdw_privs_are(fdw, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM test_fdw(); CREATE FUNCTION test_server() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN IF pg_version_num() >= 80400 THEN EXECUTE 'CREATE SERVER foo FOREIGN DATA WRAPPER dummy;'; EXECUTE 'CREATE SERVER "SomeServer" FOREIGN DATA WRAPPER "SomeFDW";'; FOR tap IN SELECT * FROM check_test( server_privs_are( 'foo', current_user, '{USAGE}', 'whatever' ), true, 'server_privs_are(server, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( server_privs_are( 'SomeServer', current_user, '{USAGE}', 'whatever' ), true, 'server_privs_are(SomeServer, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( server_privs_are( 'foo', current_user, '{USAGE}' ), true, 'server_privs_are(server, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted USAGE on server foo', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( server_privs_are( 'SomeServer', current_user, '{USAGE}' ), true, 'server_privs_are(SomeServer, role, privs, desc)', 'Role ' || quote_ident(current_user) || ' should be granted USAGE on server "SomeServer"', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent server. FOR tap IN SELECT * FROM check_test( server_privs_are( '__nonesuch', current_user, '{USAGE}', 'whatever' ), false, 'server_privs_are(non-server, role, privs, desc)', 'whatever', ' Server __nonesuch does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent user. FOR tap IN SELECT * FROM check_test( server_privs_are( 'foo', '__noone', '{USAGE}', 'whatever' ), false, 'server_privs_are(server, non-role, privs, desc)', 'whatever', ' Role __noone does not exist' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try another user. FOR tap IN SELECT * FROM check_test( server_privs_are( 'foo', '__someone_else', '{USAGE}', 'whatever' ), false, 'server_privs_are(server, ungranted, privs, desc)', 'whatever', ' Missing privileges: USAGE' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try testing default description for no permissions. FOR tap IN SELECT * FROM check_test( server_privs_are( 'foo', '__someone_else', '{}'::text[] ), true, 'server_privs_are(server, role, no privs)', 'Role __someone_else should be granted no privileges on server foo', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; ELSE -- Fake it with pass() and fail(). FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'server_privs_are(server, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'server_privs_are(SomeServer, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'server_privs_are(server, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'server_privs_are(SomeServer, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent server. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'server_privs_are(non-server, role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try nonexistent user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'server_privs_are(server, non-role, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try another user. FOR tap IN SELECT * FROM check_test( fail('whatever'), false, 'server_privs_are(server, ungranted, privs, desc)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; -- Try testing default description for no permissions. FOR tap IN SELECT * FROM check_test( pass('whatever'), true, 'server_privs_are(server, role, no privs)', 'whatever', '' ) AS b LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM test_server(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/proctap.sql000066400000000000000000000330311455775703000166140ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(192); -- SELECT * FROM no_plan(); CREATE SCHEMA procschema; CREATE FUNCTION procschema.afunc() RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL; CREATE FUNCTION procschema.argfunc(int, text) RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL; CREATE PROCEDURE procschema.aproc() AS 'SELECT TRUE' LANGUAGE SQL; CREATE PROCEDURE procschema.argproc(int, text) AS 'SELECT TRUE' LANGUAGE SQL; CREATE FUNCTION public.pubfunc() RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL; CREATE FUNCTION public.argpubfunc(int, text) RETURNS BOOL AS 'SELECT TRUE' LANGUAGE SQL; CREATE PROCEDURE public.pubproc() AS 'SELECT TRUE' LANGUAGE SQL; CREATE PROCEDURE public.argpubproc(int, text) AS 'SELECT TRUE' LANGUAGE SQL; -- is_procedure ( NAME, NAME, NAME[], TEXT ) -- isnt_procedure ( NAME, NAME, NAME[], TEXT ) SELECT * FROM check_test( is_procedure( 'procschema', 'aproc', '{}'::name[], 'whatever' ), true, 'is_procedure(schema, proc, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'aproc', '{}'::name[], 'whatever' ), false, 'isnt_procedure(schema, proc, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'afunc', '{}'::name[], 'whatever' ), false, 'is_procedure(schema, func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'afunc', '{}'::name[], 'whatever' ), true, 'isnt_procedure(schema, func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argproc', ARRAY['integer', 'text'], 'whatever' ), true, 'is_procedure(schema, proc, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argproc', ARRAY['integer', 'text'], 'whatever' ), false, 'isnt_procedure(schema, proc, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argfunc', ARRAY['integer', 'text'], 'whatever' ), false, 'is_procedure(schema, func, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argfunc', ARRAY['integer', 'text'], 'whatever' ), true, 'isnt_procedure(schema, func, args, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'procschema', 'nope', '{}'::name[], 'whatever' ), false, 'is_procedure(schema, noproc, noargs, desc)', 'whatever', ' Function procschema.nope() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'nope', '{}'::name[], 'whatever' ), false, 'isnt_procedure(schema, noproc, noargs, desc)', 'whatever', ' Function procschema.nope() does not exist' ); -- is_procedure( NAME, NAME, NAME[] ) -- isnt_procedure( NAME, NAME, NAME[] ) SELECT * FROM check_test( is_procedure( 'procschema', 'aproc', '{}'::name[] ), true, 'is_procedure(schema, proc, noargs)', 'Function procschema.aproc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'aproc', '{}'::name[] ), false, 'isnt_procedure(schema, proc, noargs)', 'Function procschema.aproc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'afunc', '{}'::name[] ), false, 'is_procedure(schema, func, noargs)', 'Function procschema.afunc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'afunc', '{}'::name[] ), true, 'isnt_procedure(schema, func, noargs)', 'Function procschema.afunc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argproc', ARRAY['integer', 'text'] ), true, 'is_procedure(schema, proc, args)', 'Function procschema.argproc(integer, text) should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argproc', ARRAY['integer', 'text'] ), false, 'isnt_procedure(schema, proc, args)', 'Function procschema.argproc(integer, text) should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argfunc', ARRAY['integer', 'text'] ), false, 'is_procedure(schema, func, args)', 'Function procschema.argfunc(integer, text) should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argfunc', ARRAY['integer', 'text'] ), true, 'isnt_procedure(schema, func, args)', 'Function procschema.argfunc(integer, text) should not be a procedure', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'procschema', 'nada', '{}'::name[] ), false, 'is_procedure(schema, noproc, noargs)', 'Function procschema.nada() should be a procedure', ' Function procschema.nada() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'nada', '{}'::name[] ), false, 'isnt_procedure(schema, noproc, noargs)', 'Function procschema.nada() should not be a procedure', ' Function procschema.nada() does not exist' ); -- is_procedure ( NAME, NAME, TEXT ) -- isnt_procedure ( NAME, NAME, TEXT ) SELECT * FROM check_test( is_procedure( 'procschema', 'argproc', 'whatever' ), true, 'is_procedure(schema, proc, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argproc', 'whatever' ), false, 'isnt_procedure(schema, proc, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argfunc', 'whatever' ), false, 'is_procedure(schema, func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argfunc', 'whatever' ), true, 'isnt_procedure(schema, func, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'procschema', 'nork', 'whatever' ), false, 'is_procedure(schema, noproc, desc)', 'whatever', ' Function procschema.nork() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'nork', 'whatever' ), false, 'isnt_procedure(schema, noproc, desc)', 'whatever', ' Function procschema.nork() does not exist' ); -- is_procedure( NAME, NAME ) -- isnt_procedure( NAME, NAME ) SELECT * FROM check_test( is_procedure( 'procschema', 'argproc'::name ), true, 'is_procedure(schema, proc)', 'Function procschema.argproc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argproc'::name ), false, 'isnt_procedure(schema, proc)', 'Function procschema.argproc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'procschema', 'argfunc'::name ), false, 'is_procedure(schema, func)', 'Function procschema.argfunc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'argfunc'::name ), true, 'isnt_procedure(schema, func)', 'Function procschema.argfunc() should not be a procedure', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'procschema', 'zippo'::name ), false, 'is_procedure(schema, noproc)', 'Function procschema.zippo() should be a procedure', ' Function procschema.zippo() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'procschema', 'zippo'::name ), false, 'isnt_procedure(schema, noproc)', 'Function procschema.zippo() should not be a procedure', ' Function procschema.zippo() does not exist' ); -- is_procedure ( NAME, NAME[], TEXT ) -- isnt_procedure ( NAME, NAME[], TEXT ) SELECT * FROM check_test( is_procedure( 'pubproc', '{}'::name[], 'whatever' ), true, 'is_procedure(proc, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'pubproc', '{}'::name[], 'whatever' ), false, 'isnt_procedure(proc, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'pubfunc', '{}'::name[], 'whatever' ), false, 'is_procedure(func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'pubfunc', '{}'::name[], 'whatever' ), true, 'isnt_procedure(schema, func, noargs, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'argpubproc', ARRAY['integer', 'text'], 'whatever' ), true, 'is_procedure(proc, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubproc', ARRAY['integer', 'text'], 'whatever' ), false, 'isnt_procedure(proc, args, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'argpubfunc', ARRAY['integer', 'text'], 'whatever' ), false, 'is_procedure(unc, args, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubfunc', ARRAY['integer', 'text'], 'whatever' ), true, 'isnt_procedure(func, args, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'nonesuch', '{}'::name[], 'whatever' ), false, 'is_procedure(noproc, noargs, desc)', 'whatever', ' Function nonesuch() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'nonesuch', '{}'::name[], 'whatever' ), false, 'isnt_procedure(noproc, noargs, desc)', 'whatever', ' Function nonesuch() does not exist' ); -- is_procedure( NAME, NAME[] ) -- isnt_procedure( NAME, NAME[] ) SELECT * FROM check_test( is_procedure( 'pubproc', '{}'::name[] ), true, 'is_procedure(proc, noargs)', 'Function pubproc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'pubproc', '{}'::name[] ), false, 'isnt_procedure(proc, noargs)', 'Function pubproc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'pubfunc', '{}'::name[] ), false, 'is_procedure(func, noargs)', 'Function pubfunc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'pubfunc', '{}'::name[] ), true, 'isnt_procedure(schema, func, noargs)', 'Function pubfunc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'argpubproc', ARRAY['integer', 'text'] ), true, 'is_procedure(proc, args)', 'Function argpubproc(integer, text) should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubproc', ARRAY['integer', 'text'] ), false, 'isnt_procedure(proc, args)', 'Function argpubproc(integer, text) should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'argpubfunc', ARRAY['integer', 'text'] ), false, 'is_procedure(unc, args)', 'Function argpubfunc(integer, text) should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubfunc', ARRAY['integer', 'text'] ), true, 'isnt_procedure(func, args)', 'Function argpubfunc(integer, text) should not be a procedure', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'nix', '{}'::name[] ), false, 'is_procedure(noproc, noargs)', 'Function nix() should be a procedure', ' Function nix() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'nix', '{}'::name[] ), false, 'isnt_procedure(noproc, noargs)', 'Function nix() should not be a procedure', ' Function nix() does not exist' ); -- is_procedure( NAME, TEXT ) -- isnt_procedure( NAME, TEXT ) SELECT * FROM check_test( is_procedure( 'argpubproc', 'whatever' ), true, 'is_procedure(proc, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubproc', 'whatever' ), false, 'isnt_procedure(proc, desc)', 'whatever', '' ); SELECT * FROM check_test( is_procedure( 'argpubfunc', 'whatever' ), false, 'is_procedure(func, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubfunc', 'whatever' ), true, 'isnt_procedure(func, desc)', 'whatever', '' ); -- Test diagnostics SELECT * FROM check_test( is_procedure( 'zilch', 'whatever' ), false, 'is_procedure(noproc, desc)', 'whatever', ' Function zilch() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'zilch', 'whatever' ), false, 'isnt_procedure(noproc, desc)', 'whatever', ' Function zilch() does not exist' ); -- is_procedure( NAME ) -- isnt_procedure( NAME ) SELECT * FROM check_test( is_procedure( 'argpubproc' ), true, 'is_procedure(proc)', 'Function argpubproc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubproc' ), false, 'isnt_procedure(proc)', 'Function argpubproc() should not be a procedure', '' ); SELECT * FROM check_test( is_procedure( 'argpubfunc' ), false, 'is_procedure(func)', 'Function argpubfunc() should be a procedure', '' ); SELECT * FROM check_test( isnt_procedure( 'argpubfunc' ), true, 'isnt_procedure(func)', 'Function argpubfunc() should not be a procedure', '' ); -- Test diagnosics SELECT * FROM check_test( is_procedure( 'nope' ), false, 'is_procedure(noproc)', 'Function nope() should be a procedure', ' Function nope() does not exist' ); SELECT * FROM check_test( isnt_procedure( 'nope' ), false, 'isnt_procedure(noproc)', 'Function nope() should not be a procedure', ' Function nope() does not exist' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/resultset.sql000066400000000000000000001776051455775703000172160ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(545); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE names ( id SERIAL NOT NULL PRIMARY KEY, name TEXT DEFAULT '' ); CREATE TABLE someat ( id SERIAL PRIMARY KEY, ts timestamp DEFAULT NOW(), active BOOLEAN DEFAULT TRUE ); RESET client_min_messages; -- Top 100 boy an 100 girl names in 2005. https://www.ssa.gov/OACT/babynames/ INSERT INTO names (name) VALUES ('Jacob'); INSERT INTO names (name) VALUES ('Emily'); INSERT INTO names (name) VALUES ('Michael'); INSERT INTO names (name) VALUES ('Emma'); INSERT INTO names (name) VALUES ('Joshua'); INSERT INTO names (name) VALUES ('Madison'); INSERT INTO names (name) VALUES ('Matthew'); INSERT INTO names (name) VALUES ('Abigail'); INSERT INTO names (name) VALUES ('Ethan'); INSERT INTO names (name) VALUES ('Olivia'); INSERT INTO names (name) VALUES ('Andrew'); INSERT INTO names (name) VALUES ('Isabella'); INSERT INTO names (name) VALUES ('Daniel'); INSERT INTO names (name) VALUES ('Hannah'); INSERT INTO names (name) VALUES ('Anthony'); INSERT INTO names (name) VALUES ('Samantha'); INSERT INTO names (name) VALUES ('Christopher'); INSERT INTO names (name) VALUES ('Ava'); INSERT INTO names (name) VALUES ('Joseph'); INSERT INTO names (name) VALUES ('Ashley'); INSERT INTO names (name) VALUES ('William'); INSERT INTO names (name) VALUES ('Elizabeth'); INSERT INTO names (name) VALUES ('Alexander'); INSERT INTO names (name) VALUES ('Sophia'); INSERT INTO names (name) VALUES ('David'); INSERT INTO names (name) VALUES ('Alexis'); INSERT INTO names (name) VALUES ('Ryan'); INSERT INTO names (name) VALUES ('Grace'); INSERT INTO names (name) VALUES ('Nicholas'); INSERT INTO names (name) VALUES ('Sarah'); INSERT INTO names (name) VALUES ('Tyler'); INSERT INTO names (name) VALUES ('Alyssa'); INSERT INTO names (name) VALUES ('James'); INSERT INTO names (name) VALUES ('Mia'); INSERT INTO names (name) VALUES ('John'); INSERT INTO names (name) VALUES ('Natalie'); INSERT INTO names (name) VALUES ('Jonathan'); INSERT INTO names (name) VALUES ('Chloe'); INSERT INTO names (name) VALUES ('Nathan'); INSERT INTO names (name) VALUES ('Brianna'); INSERT INTO names (name) VALUES ('Samuel'); INSERT INTO names (name) VALUES ('Lauren'); INSERT INTO names (name) VALUES ('Christian'); INSERT INTO names (name) VALUES ('Anna'); INSERT INTO names (name) VALUES ('Noah'); INSERT INTO names (name) VALUES ('Ella'); INSERT INTO names (name) VALUES ('Dylan'); INSERT INTO names (name) VALUES ('Taylor'); INSERT INTO names (name) VALUES ('Benjamin'); INSERT INTO names (name) VALUES ('Kayla'); INSERT INTO names (name) VALUES ('Logan'); INSERT INTO names (name) VALUES ('Hailey'); INSERT INTO names (name) VALUES ('Brandon'); INSERT INTO names (name) VALUES ('Jessica'); INSERT INTO names (name) VALUES ('Gabriel'); INSERT INTO names (name) VALUES ('Victoria'); INSERT INTO names (name) VALUES ('Zachary'); INSERT INTO names (name) VALUES ('Jasmine'); INSERT INTO names (name) VALUES ('Jose'); INSERT INTO names (name) VALUES ('Sydney'); INSERT INTO names (name) VALUES ('Elijah'); INSERT INTO names (name) VALUES ('Julia'); INSERT INTO names (name) VALUES ('Angel'); INSERT INTO names (name) VALUES ('Destiny'); INSERT INTO names (name) VALUES ('Kevin'); INSERT INTO names (name) VALUES ('Morgan'); INSERT INTO names (name) VALUES ('Jack'); INSERT INTO names (name) VALUES ('Kaitlyn'); INSERT INTO names (name) VALUES ('Caleb'); INSERT INTO names (name) VALUES ('Savannah'); INSERT INTO names (name) VALUES ('Justin'); INSERT INTO names (name) VALUES ('Katherine'); INSERT INTO names (name) VALUES ('Robert'); INSERT INTO names (name) VALUES ('Alexandra'); INSERT INTO names (name) VALUES ('Austin'); INSERT INTO names (name) VALUES ('Rachel'); INSERT INTO names (name) VALUES ('Evan'); INSERT INTO names (name) VALUES ('Lily'); INSERT INTO names (name) VALUES ('Thomas'); INSERT INTO names (name) VALUES ('Kaylee'); INSERT INTO names (name) VALUES ('Luke'); INSERT INTO names (name) VALUES ('Megan'); INSERT INTO names (name) VALUES ('Mason'); INSERT INTO names (name) VALUES ('Jennifer'); INSERT INTO names (name) VALUES ('Aidan'); INSERT INTO names (name) VALUES ('Angelina'); INSERT INTO names (name) VALUES ('Jackson'); INSERT INTO names (name) VALUES ('Makayla'); INSERT INTO names (name) VALUES ('Isaiah'); INSERT INTO names (name) VALUES ('Allison'); INSERT INTO names (name) VALUES ('Jordan'); INSERT INTO names (name) VALUES ('Maria'); INSERT INTO names (name) VALUES ('Gavin'); INSERT INTO names (name) VALUES ('Brooke'); INSERT INTO names (name) VALUES ('Connor'); INSERT INTO names (name) VALUES ('Trinity'); INSERT INTO names (name) VALUES ('Isaac'); INSERT INTO names (name) VALUES ('Faith'); INSERT INTO names (name) VALUES ('Aiden'); INSERT INTO names (name) VALUES ('Lillian'); INSERT INTO names (name) VALUES ('Jason'); INSERT INTO names (name) VALUES ('Mackenzie'); INSERT INTO names (name) VALUES ('Cameron'); INSERT INTO names (name) VALUES ('Sofia'); INSERT INTO names (name) VALUES ('Hunter'); INSERT INTO names (name) VALUES ('Riley'); INSERT INTO names (name) VALUES ('Jayden'); INSERT INTO names (name) VALUES ('Haley'); INSERT INTO names (name) VALUES ('Juan'); INSERT INTO names (name) VALUES ('Gabrielle'); INSERT INTO names (name) VALUES ('Charles'); INSERT INTO names (name) VALUES ('Nicole'); INSERT INTO names (name) VALUES ('Aaron'); INSERT INTO names (name) VALUES ('Kylie'); INSERT INTO names (name) VALUES ('Lucas'); INSERT INTO names (name) VALUES ('Zoe'); INSERT INTO names (name) VALUES ('Luis'); INSERT INTO names (name) VALUES ('Katelyn'); INSERT INTO names (name) VALUES ('Owen'); INSERT INTO names (name) VALUES ('Paige'); INSERT INTO names (name) VALUES ('Landon'); INSERT INTO names (name) VALUES ('Gabriella'); INSERT INTO names (name) VALUES ('Diego'); INSERT INTO names (name) VALUES ('Jenna'); INSERT INTO names (name) VALUES ('Brian'); INSERT INTO names (name) VALUES ('Kimberly'); INSERT INTO names (name) VALUES ('Adam'); INSERT INTO names (name) VALUES ('Stephanie'); INSERT INTO names (name) VALUES ('Adrian'); INSERT INTO names (name) VALUES ('Andrea'); INSERT INTO names (name) VALUES ('Eric'); INSERT INTO names (name) VALUES ('Alexa'); INSERT INTO names (name) VALUES ('Kyle'); INSERT INTO names (name) VALUES ('Avery'); INSERT INTO names (name) VALUES ('Ian'); INSERT INTO names (name) VALUES ('Leah'); INSERT INTO names (name) VALUES ('Nathaniel'); INSERT INTO names (name) VALUES ('Nevaeh'); INSERT INTO names (name) VALUES ('Carlos'); INSERT INTO names (name) VALUES ('Madeline'); INSERT INTO names (name) VALUES ('Alex'); INSERT INTO names (name) VALUES ('Evelyn'); INSERT INTO names (name) VALUES ('Bryan'); INSERT INTO names (name) VALUES ('Mary'); INSERT INTO names (name) VALUES ('Jesus'); INSERT INTO names (name) VALUES ('Maya'); INSERT INTO names (name) VALUES ('Julian'); INSERT INTO names (name) VALUES ('Michelle'); INSERT INTO names (name) VALUES ('Sean'); INSERT INTO names (name) VALUES ('Sara'); INSERT INTO names (name) VALUES ('Hayden'); INSERT INTO names (name) VALUES ('Jada'); INSERT INTO names (name) VALUES ('Carter'); INSERT INTO names (name) VALUES ('Audrey'); INSERT INTO names (name) VALUES ('Jeremiah'); INSERT INTO names (name) VALUES ('Brooklyn'); INSERT INTO names (name) VALUES ('Cole'); INSERT INTO names (name) VALUES ('Vanessa'); INSERT INTO names (name) VALUES ('Brayden'); INSERT INTO names (name) VALUES ('Amanda'); INSERT INTO names (name) VALUES ('Wyatt'); INSERT INTO names (name) VALUES ('Rebecca'); INSERT INTO names (name) VALUES ('Chase'); INSERT INTO names (name) VALUES ('Caroline'); INSERT INTO names (name) VALUES ('Steven'); INSERT INTO names (name) VALUES ('Ariana'); INSERT INTO names (name) VALUES ('Timothy'); INSERT INTO names (name) VALUES ('Amelia'); INSERT INTO names (name) VALUES ('Dominic'); INSERT INTO names (name) VALUES ('Mariah'); INSERT INTO names (name) VALUES ('Sebastian'); INSERT INTO names (name) VALUES ('Jordan'); INSERT INTO names (name) VALUES ('Xavier'); INSERT INTO names (name) VALUES ('Jocelyn'); INSERT INTO names (name) VALUES ('Jaden'); INSERT INTO names (name) VALUES ('Arianna'); INSERT INTO names (name) VALUES ('Jesse'); INSERT INTO names (name) VALUES ('Isabel'); INSERT INTO names (name) VALUES ('Seth'); INSERT INTO names (name) VALUES ('Marissa'); INSERT INTO names (name) VALUES ('Devin'); INSERT INTO names (name) VALUES ('Autumn'); INSERT INTO names (name) VALUES ('Antonio'); INSERT INTO names (name) VALUES ('Melanie'); INSERT INTO names (name) VALUES ('Miguel'); INSERT INTO names (name) VALUES ('Aaliyah'); INSERT INTO names (name) VALUES ('Richard'); INSERT INTO names (name) VALUES ('Gracie'); INSERT INTO names (name) VALUES ('Colin'); INSERT INTO names (name) VALUES ('Claire'); INSERT INTO names (name) VALUES ('Cody'); INSERT INTO names (name) VALUES ('Isabelle'); INSERT INTO names (name) VALUES ('Alejandro'); INSERT INTO names (name) VALUES ('Molly'); INSERT INTO names (name) VALUES ('Caden'); INSERT INTO names (name) VALUES ('Mya'); INSERT INTO names (name) VALUES ('Blake'); INSERT INTO names (name) VALUES ('Diana'); INSERT INTO names (name) VALUES ('Kaden'); INSERT INTO names (name) VALUES ('Katie'); CREATE TABLE annames AS SELECT id, name FROM names WHERE name like 'An%'; -- We'll use these prepared statements. PREPARE anames AS SELECT id, name FROM names WHERE name like 'An%'; CREATE TABLE toexpect (id int, name text); INSERT INTO toexpect (id, name) VALUES(11, 'Andrew'); INSERT INTO toexpect (id, name) VALUES(44, 'Anna'); INSERT INTO toexpect (id, name) VALUES(15, 'Anthony'); INSERT INTO toexpect (id, name) VALUES(183, 'Antonio'); INSERT INTO toexpect (id, name) VALUES(86, 'Angelina'); INSERT INTO toexpect (id, name) VALUES(130, 'Andrea'); INSERT INTO toexpect (id, name) VALUES(63, 'Angel'); PREPARE expect AS SELECT id, name FROM toexpect; /****************************************************************************/ -- First, test _temptable. SELECT is( _temptable('SELECT * FROM names', '__foonames__'), '__foonames__', 'Should create temp table with simple query' ); SELECT has_table('__foonames__' ); SELECT is( _temptable( 'anames', '__somenames__' ), '__somenames__', 'Should create a temp table for a prepared statement' ); SELECT has_table('__somenames__' ); PREPARE "something cool" AS SELECT 1 AS a, 2 AS b; SELECT is( _temptable( '"something cool"', '__spacenames__' ), '__spacenames__', 'Should create a temp table for a prepared statement with space' ); SELECT has_table('__somenames__' ); SELECT has_table('__spacenames__' ); /****************************************************************************/ -- Now test set_eq(). SELECT * FROM check_test( set_eq( 'anames', 'expect', 'whatever' ), true, 'set_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( set_eq( 'anames', 'expect' ), true, 'set_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( set_eq( 'EXECUTE anames', 'EXECUTE expect' ), true, 'set_eq(execute, execute, desc)', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( set_eq( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM annames' ), true, 'set_eq(select, select)', '', '' ); -- Make sure that dupes are disregarded. SELECT * FROM check_test( set_eq( 'SELECT 1 AS a, ''Anna''::text AS b', 'SELECT 1 AS a, ''Anna''::text AS b UNION ALL SELECT 1, ''Anna''' ), true, 'set_eq(values, dupe values)', '', '' ); -- Try some failures. SELECT * FROM check_test( set_eq( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''' ), false, 'set_eq(prepared, select) fail extra', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( set_eq( 'anames', 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')' ), false, 'set_eq(prepared, select) fail extras', '', ' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); SELECT * FROM check_test( set_eq( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'set_eq(select, prepared) fail missing', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( set_eq( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'set_eq(select, prepared) fail missings', '', ' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); SELECT * FROM check_test( set_eq( 'SELECT id, name FROM names WHERE name ~ ''^(An|Jacob)'' AND name <> ''Anna''', 'SELECT id, name FROM annames' ), false, 'set_eq(select, select) fail extra & missing', '', ' Extra records: (1,Jacob) Missing records: (44,Anna)' ); SELECT * FROM check_test( set_eq( 'SELECT id, name FROM names WHERE name ~ ''^(An|Jacob|Jacks)'' AND name NOT IN (''Anna'', ''Angelina'')', 'SELECT id, name FROM annames' ), false, 'set_eq(select, select) fail extras & missings', '', ' Extra records: [(](1,Jacob|87,Jackson)[)] [(](1,Jacob|87,Jackson)[)] Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_eq( 'SELECT 1 AS a, ''foo''::text AS b UNION ALL SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 AS b UNION ALL SELECT ''bar'', 2' ), false, 'set_eq(values, values) fail mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_eq( 'SELECT 1 AS a UNION ALL SELECT 2 AS b', 'SELECT ''foo''::text AS a, 1 AS b UNION ALL SELECT ''bar'', 2' ), false, 'set_eq(values, values) fail column count', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Handle failure with column mismatch with a column type in a schema not in -- the search path. This is a regression. CREATE SCHEMA __myfoo; CREATE DOMAIN __myfoo.text AS TEXT CHECK(TRUE); CREATE TABLE __yowza( foo text, bar __myfoo.text, baz integer ); INSERT INTO __yowza VALUES ('abc', 'xyz', 1); INSERT INTO __yowza VALUES ('def', 'utf', 2); SELECT * FROM check_test( set_eq( 'SELECT foo, bar from __yowza', 'SELECT foo, bar, baz from __yowza' ), false, 'set_eq(sql, sql) fail type schema visibility', '', ' Columns differ between queries: have: (text,__myfoo.text) want: (text,__myfoo.text,integer)' ); /****************************************************************************/ -- Now test bag_eq(). SELECT * FROM check_test( bag_eq( 'anames', 'expect', 'whatever' ), true, 'bag_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_eq( 'anames', 'expect' ), true, 'bag_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( bag_eq( 'EXECUTE anames', 'EXECUTE expect' ), true, 'bag_eq(execute, execute)', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM annames' ), true, 'bag_eq(select, select)', '', '' ); -- Compare with dupes. SELECT * FROM check_test( bag_eq( 'SELECT 1 AS a, ''Anna''::text AS b UNION ALL SELECT 86, ''Angelina'' UNION ALL SELECT 1, ''Anna''', 'SELECT 1 AS a, ''Anna''::text AS b UNION ALL SELECT 1, ''Anna'' UNION ALL SELECT 86, ''Angelina''' ), true, 'bag_eq(dupe values, dupe values)', '', '' ); -- And now some failures. SELECT * FROM check_test( bag_eq( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''' ), false, 'bag_eq(prepared, select) fail extra', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( bag_eq( 'anames', 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')' ), false, 'bag_eq(prepared, select) fail extras', '', ' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'bag_eq(select, prepared) fail missing', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'bag_eq(select, prepared) fail missings', '', ' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM names WHERE name ~ ''^(An|Jacob)'' AND name <> ''Anna''', 'SELECT id, name FROM annames' ), false, 'bag_eq(select, select) fail extra & missing', '', ' Extra records: (1,Jacob) Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM names WHERE name ~ ''^(An|Jacob|Jacks)'' AND name NOT IN (''Anna'', ''Angelina'')', 'SELECT id, name FROM annames' ), false, 'bag_eq(select, select) fail extras & missings', '', ' Extra records: [(](1,Jacob|87,Jackson)[)] [(](1,Jacob|87,Jackson)[)] Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_eq( 'SELECT 1 AS a, ''foo''::text AS b UNION ALL SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 AS b UNION ALL SELECT ''bar'', 2' ), false, 'bag_eq(values, values) fail mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_eq( 'SELECT 1 AS a UNION ALL SELECT 2 AS b', 'SELECT ''foo''::text AS a, 1 AS b UNION ALL SELECT ''bar'', 2' ), false, 'bag_eq(values, values) fail column count', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Handle failure due to missing dupe. SELECT * FROM check_test( bag_eq( 'SELECT 1 AS a, ''Anna''::text AS b UNION ALL SELECT 86, ''Angelina'' UNION ALL SELECT 1, ''Anna''', 'SELECT 1 AS a, ''Anna''::TEXT AS b UNION ALL SELECT 86, ''Angelina''' ), false, 'bag_eq(values, values) fail missing dupe', '', ' Extra records: (1,Anna)' ); /****************************************************************************/ -- Now test set_eq(). SELECT * FROM check_test( set_ne( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'whatever' ), true, 'set_ne(prepared, select, desc)', 'whatever', '' ); SELECT * FROM check_test( set_ne( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''' ), true, 'set_ne(prepared, select)', '', '' ); SELECT * FROM check_test( set_ne( 'anames', 'expect' ), false, 'set_ne(prepared, prepared) fail', '', '' ); -- Handle fail with column mismatch. SELECT * FROM check_test( set_ne( 'SELECT 1 AS a, ''foo''::text AS b UNION ALL SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 AS b UNION ALL SELECT ''bar'', 2' ), false, 'set_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_ne( 'SELECT 1 UNION ALL SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION ALL SELECT ''bar'', 2' ), false, 'set_ne fail with different col counts', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Handle fail with a dupe. SELECT * FROM check_test( set_ne( 'SELECT 1 AS a, ''Anna''::text UNION ALL SELECT 86, ''Angelina'' UNION ALL SELECT 1, ''Anna''', 'SELECT 1 AS a, ''Anna''::text UNION ALL SELECT 86, ''Angelina''' ), false, 'set_ne fail with dupe', '', '' ); /****************************************************************************/ -- Now test bag_ne(). SELECT * FROM check_test( bag_ne( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'whatever' ), true, 'bag_ne(prepared, select, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_ne( 'anames', 'SELECT id, name FROM annames WHERE name <> ''Anna''' ), true, 'bag_ne(prepared, select)', '', '' ); SELECT * FROM check_test( bag_ne( 'anames', 'expect' ), false, 'bag_ne(prepared, prepared) fail', '', '' ); SELECT * FROM check_test( bag_ne( 'SELECT 1 AS a, ''foo''::text UNION ALL SELECT 2, ''bar''', 'SELECT ''foo'' AS a, 1 UNION ALL SELECT ''bar'', 2' ), false, 'bag_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle pass with a dupe. SELECT * FROM check_test( bag_ne( 'SELECT 1 AS a, ''Anna''::text UNION ALL SELECT 86, ''Angelina'' UNION ALL SELECT 1, ''Anna''', 'SELECT 1 AS a, ''Anna''::text UNION ALL SELECT 86, ''Angelina''' ), true, 'set_ne pass with dupe', '', '' ); -- Handle fail with column mismatch. SELECT * FROM check_test( bag_ne( 'SELECT 1 AS a, ''foo''::text UNION ALL SELECT 2, ''bar''', 'SELECT ''foo'' AS a, 1 UNION ALL SELECT ''bar'', 2' ), false, 'bag_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_ne( 'SELECT 1 UNION SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'bag_ne fail with different col counts', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test results_eq(). PREPARE anames_ord AS SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; PREPARE expect_ord AS SELECT id, name FROM toexpect ORDER BY id; SELECT * FROM check_test( results_eq( 'anames_ord', 'expect_ord', 'whatever' ), true, 'results_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( results_eq( 'anames_ord', 'expect_ord' ), true, 'results_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( results_eq( 'EXECUTE anames_ord', 'EXECUTE expect_ord' ), true, 'results_eq(execute, execute)', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( results_eq( 'SELECT id, name FROM names WHERE name like ''An%'' ORDER BY id', 'SELECT id, name FROM annames ORDER BY id' ), true, 'results_eq(select, select)', '', '' ); -- Compare with dupes. SET client_min_messages = warning; CREATE table dupes (pk SERIAL PRIMARY KEY, id int, name text); RESET client_min_messages; INSERT INTO dupes (id, name) VALUES(1, 'Anna'); INSERT INTO dupes (id, name) VALUES(86, 'Angelina'); INSERT INTO dupes (id, name) VALUES(1, 'Anna'); SELECT * FROM check_test( results_eq( 'SELECT id, name FROM dupes ORDER BY pk', 'SELECT id, name FROM dupes ORDER BY pk' ), true, 'results_eq(dupe values, dupe values)', '', '' ); UPDATE dupes SET name = NULL WHERE pk = 1; -- Compare with nulls. SELECT * FROM check_test( results_eq( 'SELECT id, name FROM dupes ORDER BY pk', 'SELECT id, name FROM dupes ORDER BY pk' ), true, 'results_eq(values with null, values with null)', '', '' ); UPDATE dupes SET id = NULL, name = NULL; -- Compare only NULLs SELECT * FROM check_test( results_eq( 'SELECT id, name FROM dupes LIMIT 2', 'SELECT id, name FROM dupes LIMIT 2' ), true, 'results_eq(nulls, nulls)', '', '' ); -- Compare differnt rows of NULLs SELECT * FROM check_test( results_eq( 'SELECT id, name FROM dupes LIMIT 2', 'SELECT id, name FROM dupes LIMIT 1' ), false, 'results_eq(nulls, nulls) fail', '', ' Results differ beginning at row 2: have: (,) want: NULL' ); -- And now some failures. SELECT * FROM check_test( results_eq( 'anames_ord', 'SELECT id, name FROM annames WHERE name <> ''Anna''' ), false, 'results_eq(prepared, select) fail', '', ' Results differ beginning at row 3: have: (44,Anna) want: (63,Angel)' ); -- Now when the last row is missing. SELECT * FROM check_test( results_eq( 'SELECT id, name FROM annames WHERE name <> ''Antonio''', 'anames_ord' ), false, 'results_eq(select, prepared) fail missing last row', '', ' Results differ beginning at row 7: have: NULL want: (183,Antonio)' ); -- Invert that. SELECT * FROM check_test( results_eq( 'anames_ord', 'SELECT id, name FROM annames WHERE name <> ''Antonio''' ), false, 'results_eq(prepared, select) fail missing first row', '', ' Results differ beginning at row 7: have: (183,Antonio) want: NULL' ); -- Compare with missing dupe. SET client_min_messages = warning; CREATE table dubs (pk SERIAL PRIMARY KEY, id int, name text); RESET client_min_messages; INSERT INTO dubs (id, name) VALUES(1, 'Anna'); INSERT INTO dubs (id, name) VALUES(86, 'Angelina'); INSERT INTO dubs (id, name) VALUES(1, 'Anna'); SELECT * FROM check_test( results_eq( 'SELECT id, name from dubs ORDER BY pk', 'SELECT id, name from dubs ORDER BY pk LIMIT 2' ), false, 'results_eq(values dupe, values)', '', ' Results differ beginning at row 3: have: (1,Anna) want: NULL' ); UPDATE dubs SET name = NULL WHERE pk = 1; -- Handle failure with null. SELECT * FROM check_test( results_eq( 'SELECT id, name from dubs ORDER BY pk LIMIT 2', 'SELECT id, name from dubs ORDER BY pk DESC LIMIT 2' ), false, 'results_eq(values null, values)', '', ' Results differ beginning at row 1: have: (1,) want: (1,Anna)' ); UPDATE dubs SET name = 'foo' WHERE pk = 1; UPDATE dubs SET name = 'bar' WHERE pk = 2; -- Handle failure due to column mismatch. SELECT * FROM check_test( results_eq( 'SELECT pk, name from dubs ORDER BY pk LIMIT 2', 'SELECT name, pk from dubs ORDER BY pk LIMIT 2' ), false, 'results_eq(values, values) mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: cannot compare dissimilar column types integer and text at record column 1' ELSE ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to more subtle column mismatch SELECT * FROM check_test( results_eq( 'VALUES (1, ''foo''::varchar), (2, ''bar''::varchar)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_eq(values, values) subtle mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries ERROR: cannot compare dissimilar column types character varying and text at record column 2' ELSE ' Number of columns or their types differ between the queries ERROR: details not available in pg <= 9.1' END ); SELECT * FROM check_test( results_eq( 'VALUES (1::int), (2::int)', 'VALUES (1::bigint), (2::bigint)' ), false, 'results_eq(values, values) integer type mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries ERROR: cannot compare dissimilar column types integer and bigint at record column 1' ELSE ' Number of columns or their types differ between the queries ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( results_eq( 'SELECT pk from dubs ORDER BY pk LIMIT 2', 'SELECT pk, name from dubs ORDER BY pk LIMIT 2' ), false, 'results_eq(values, values) fail column count', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: cannot compare record types with different numbers of columns' ELSE ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: details not available in pg <= 9.1' END ); -- Compare with cursors. DECLARE cwant CURSOR FOR SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; DECLARE chave CURSOR FOR SELECT id, name from annames ORDER BY id; SELECT * FROM check_test( results_eq( 'cwant'::refcursor, 'chave'::refcursor ), true, 'results_eq(cursor, cursor)', '', '' ); -- Mix cursors and prepared statements PREPARE annames_ord AS SELECT id, name FROM annames ORDER BY id; MOVE BACKWARD ALL IN cwant; SELECT * FROM check_test( results_eq( 'cwant'::refcursor, 'annames_ord' ), true, 'results_eq(cursor, prepared)', '', '' ); MOVE BACKWARD ALL IN chave; SELECT * FROM check_test( results_eq( 'annames_ord', 'chave'::refcursor ), true, 'results_eq(prepared, cursor)', '', '' ); -- Mix cursor and SQL. MOVE BACKWARD ALL IN cwant; SELECT * FROM check_test( results_eq( 'cwant'::refcursor, 'SELECT id, name FROM annames ORDER BY id' ), true, 'results_eq(cursor, sql)', '', '' ); MOVE BACKWARD ALL IN chave; SELECT * FROM check_test( results_eq( 'SELECT id, name FROM annames ORDER BY id', 'chave'::refcursor ), true, 'results_eq(sql, cursor)', '', '' ); /****************************************************************************/ -- Now test set_has(). SELECT * FROM check_test( set_has( 'anames', 'expect', 'whatever' ), true, 'set_has( prepared, prepared, description )', 'whatever', '' ); PREPARE subset AS SELECT id, name FROM toexpect WHERE id IN (11, 44, 63); SELECT * FROM check_test( set_has( 'anames', 'subset' ), true, 'set_has( prepared, subprepared )', '', '' ); SELECT * FROM check_test( set_has( 'EXECUTE anames', 'EXECUTE subset' ), true, 'set_has( execute, execute )', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( set_has( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM annames' ), true, 'set_has( select, select )', '', '' ); -- Try an empty set in the second arg. SELECT * FROM check_test( set_has( 'anames', 'SELECT id, name FROM annames WHERE false' ), true, 'set_has( prepared, empty )', '', '' ); -- Make sure that dupes are ignored. SELECT * FROM check_test( set_has( 'anames', 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''' ), true, 'set_has( prepared, dupes )', '', '' ); SELECT * FROM check_test( set_has( 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''', 'SELECT 44 AS a, ''Anna''::text' ), true, 'set_has( dupes, values )', '', '' ); -- Check failures. SELECT * FROM check_test( set_has( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'set_has( missing1, expect )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( set_has( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'set_has(missing2, expect )', '', ' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_has( 'SELECT 1 AS a, ''foo''::text UNION ALL SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 UNION ALL SELECT ''bar'', 2' ), false, 'set_has((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_has( 'SELECT 1 UNION SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'set_has((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test bag_has(). SELECT * FROM check_test( bag_has( 'anames', 'expect', 'whatever' ), true, 'bag_has( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( bag_has( 'anames', 'subset' ), true, 'bag_has( prepared, subprepared )', '', '' ); SELECT * FROM check_test( bag_has( 'EXECUTE anames', 'EXECUTE subset' ), true, 'bag_has( execute, execute )', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( bag_has( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM annames' ), true, 'bag_has( select, select )', '', '' ); -- Try an empty set in the second arg. SELECT * FROM check_test( bag_has( 'anames', 'SELECT id, name FROM annames WHERE false' ), true, 'bag_has( prepared, empty )', '', '' ); -- Make sure that dupes are not ignored. SELECT * FROM check_test( bag_has( 'anames', 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''' ), false, 'bag_has( prepared, dupes )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_has( 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''', 'SELECT 44 AS a, ''Anna''::text' ), true, 'bag_has( dupes, values )', '', '' ); SELECT * FROM check_test( bag_has( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'bag_has( missing1, expect )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_has( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'bag_has(missing2, expect )', '', ' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_has( 'SELECT 1 AS a, ''foo''::text UNION SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'bag_has((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_has( 'SELECT 1 UNION SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'bag_has((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test set_hasnt(). CREATE TABLE folk (id int, name text); INSERT INTO folk (id, name) VALUES ( 44, 'Larry' ); INSERT INTO folk (id, name) VALUES (52, 'Tom'); INSERT INTO folk (id, name) VALUES (23, 'Damian' ); PREPARE others AS SELECT id, name FROM folk; SELECT * FROM check_test( set_hasnt( 'anames', 'others', 'whatever' ), true, 'set_hasnt( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( set_hasnt( 'anames', 'others' ), true, 'set_hasnt( prepared, prepared, description )', '', '' ); SELECT * FROM check_test( set_hasnt( 'EXECUTE anames', 'EXECUTE others' ), true, 'set_hasnt( execute, execute )', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( set_hasnt( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM names WHERE name like ''B%''' ), true, 'set_hasnt( select, select )', '', '' ); -- Try an empty set in the second arg. SELECT * FROM check_test( set_hasnt( 'anames', 'SELECT id, name FROM annames WHERE false' ), true, 'set_hasnt( prepared, empty )', '', '' ); -- Make sure that dupes are ignored. SELECT * FROM check_test( set_hasnt( 'anames', 'SELECT 44 AS a, ''Bob''::text UNION ALL SELECT 44, ''Bob''' ), true, 'set_hasnt( prepared, dupes )', '', '' ); SELECT * FROM check_test( set_hasnt( 'anames', 'SELECT 44 AS a, ''Anna''::text' ), false, 'set_hasnt( prepared, value )', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( set_hasnt( 'anames', 'SELECT 44 AS a, ''Anna''::text UNION SELECT 86, ''Angelina''' ), false, 'set_hasnt( prepared, values )', '', ' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_hasnt( 'SELECT 1 AS a, ''foo''::text UNION SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'set_hasnt((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_hasnt( 'SELECT 1 UNION SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'set_hasnt((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test bag_hasnt(). SELECT * FROM check_test( bag_hasnt( 'anames', 'others', 'whatever' ), true, 'bag_hasnt( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'others' ), true, 'bag_hasnt( prepared, prepared, description )', '', '' ); SELECT * FROM check_test( bag_hasnt( 'EXECUTE anames', 'EXECUTE others' ), true, 'bag_hasnt( execute, execute )', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( bag_hasnt( 'SELECT id, name FROM names WHERE name like ''An%''', 'SELECT id, name FROM names WHERE name like ''B%''' ), true, 'bag_hasnt( select, select )', '', '' ); -- Try an empty bag in the second arg. SELECT * FROM check_test( bag_hasnt( 'anames', 'SELECT id, name FROM annames WHERE false' ), true, 'bag_hasnt( prepared, empty )', '', '' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'SELECT 44 AS a, ''Anna''::text' ), false, 'bag_hasnt( prepared, value )', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'SELECT 44 AS a, ''Anna''::text UNION SELECT 86, ''Angelina''' ), false, 'bag_hasnt( prepared, values )', '', ' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_hasnt( 'SELECT 1 AS a, ''foo''::text UNION SELECT 2, ''bar''', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'bag_hasnt((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_hasnt( 'SELECT 1 UNION SELECT 2', 'SELECT ''foo''::text AS a, 1 UNION SELECT ''bar'', 2' ), false, 'bag_hasnt((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Make sure that dupes are not ignored. SELECT * FROM check_test( bag_hasnt( 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''', 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''' ), false, 'bag_hasnt( dupes, dupes )', '', ' Extra records: (44,Anna) (44,Anna)' ); -- But a dupe that appears only once should be in the list only once. SELECT * FROM check_test( bag_hasnt( 'SELECT 44 AS a, ''Anna''::text', 'SELECT 44 AS a, ''Anna''::text UNION ALL SELECT 44, ''Anna''' ), false, 'bag_hasnt( value, dupes )', '', ' Extra records: (44,Anna)' ); /****************************************************************************/ -- Test set_eq() with an array argument. SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ], 'whatever' ), true, 'set_eq(sql, array, desc)', 'whatever', '' ); SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), true, 'set_eq(sql, array)', '', '' ); SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Andrew', 'Anna' ] ), true, 'set_eq(sql, dupe array)', '', '' ); -- Fail with an extra record. SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_eq(sql, array) extra record', '', ' Extra records: (Anthony)' ); -- Fail with a missing record. SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Alan', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_eq(sql, array) missing record', '', ' Missing records: (Alan)' ); -- Fail with incompatible columns. SELECT * FROM check_test( set_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY[1, 2, 3] ), false, 'set_eq(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); -- Fail with invalid column counts. SELECT * FROM check_test( set_eq( 'anames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_eq(sql, array) incompatible types', '', ' Columns differ between queries: have: (integer,text) want: (text)' ); /****************************************************************************/ -- Test bag_eq() with an array argument. SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ], 'whatever' ), true, 'bag_eq(sql, array, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), true, 'bag_eq(sql, array)', '', '' ); SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), false, 'bag_eq(sql, dupe array) fail', '', ' Missing records: (Anna)' ); -- Fail with an extra record. SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_eq(sql, array) extra record', '', ' Extra records: (Anthony)' ); -- Fail with a missing record. SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Alan', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_eq(sql, array) missing record', '', ' Missing records: (Alan)' ); -- Fail with incompatible columns. SELECT * FROM check_test( bag_eq( 'SELECT name FROM names WHERE name like ''An%''', ARRAY[1, 2, 3] ), false, 'bag_eq(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); -- Fail with invalid column counts. SELECT * FROM check_test( bag_eq( 'anames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_eq(sql, array) incompatible types', '', ' Columns differ between queries: have: (integer,text) want: (text)' ); /****************************************************************************/ -- Test set_ne() with an array argument. SELECT * FROM check_test( set_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna' ], 'whatever' ), true, 'set_ne(sql, array, desc)', 'whatever', '' ); SELECT * FROM check_test( set_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna' ] ), true, 'set_ne(sql, array)', '', '' ); SELECT * FROM check_test( set_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_ne(sql, array) fail', '', '' ); -- Fail with dupes. SELECT * FROM check_test( set_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), false, 'set_ne(sql, dupes array) fail', '', '' ); -- Fail with incompatible columns. SELECT * FROM check_test( set_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY[1, 2, 3] ), false, 'set_ne(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); -- Fail with invalid column counts. SELECT * FROM check_test( set_ne( 'anames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_ne(sql, array) incompatible types', '', ' Columns differ between queries: have: (integer,text) want: (text)' ); /****************************************************************************/ -- Test bag_ne() with an array argument. SELECT * FROM check_test( bag_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna' ], 'whatever' ), true, 'bag_ne(sql, array, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna' ] ), true, 'bag_ne(sql, array)', '', '' ); SELECT * FROM check_test( bag_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_ne(sql, array) fail', '', '' ); -- Pass with dupes. SELECT * FROM check_test( bag_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), true, 'bag_ne(sql, dupes array)', '', '' ); -- Fail with incompatible columns. SELECT * FROM check_test( bag_ne( 'SELECT name FROM names WHERE name like ''An%''', ARRAY[1, 2, 3] ), false, 'bag_ne(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); -- Fail with invalid column counts. SELECT * FROM check_test( bag_ne( 'anames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_ne(sql, array) incompatible types', '', ' Columns differ between queries: have: (integer,text) want: (text)' ); /****************************************************************************/ -- Now test results_eq() with an array argument. PREPARE anames_only AS SELECT name FROM names WHERE name like 'An%' ORDER BY name; SELECT * FROM check_test( results_eq( 'anames_only', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ], 'whatever' ), true, 'results_eq(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( results_eq( 'anames_only', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ] ), true, 'results_eq(prepared, array)', '', '' ); SELECT * FROM check_test( results_eq( 'SELECT name FROM names WHERE name like ''An%'' ORDER BY name', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ], 'whatever' ), true, 'results_eq(sql, array, desc)', 'whatever', '' ); SELECT * FROM check_test( results_eq( 'SELECT name FROM names WHERE name like ''An%'' ORDER BY name', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ] ), true, 'results_eq(sql, array, desc)', '', '' ); SELECT * FROM check_test( results_eq( 'anames_only', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony' ] ), false, 'results_eq(prepared, array) extra record', '', ' Results differ beginning at row 7: have: (Antonio) want: NULL' ); SELECT * FROM check_test( results_eq( 'SELECT name FROM names WHERE name like ''An%'' AND name <> ''Anna'' ORDER BY name', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ] ), false, 'results_eq(select, array) missing record', '', ' Results differ beginning at row 5: have: (Anthony) want: (Anna)' ); /****************************************************************************/ -- Now test results_eq(). PREPARE nenames_ord AS SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; SET client_min_messages = warning; CREATE TEMPORARY TABLE nord (pk SERIAL PRIMARY KEY, id int, name text); RESET client_min_messages; INSERT INTO nord (id, name ) VALUES(15, 'Anthony'); INSERT INTO nord (id, name ) VALUES(44, 'Anna'); INSERT INTO nord (id, name ) VALUES(11, 'Andrew'); INSERT INTO nord (id, name ) VALUES(63, 'Angel'); INSERT INTO nord (id, name ) VALUES(86, 'Angelina'); INSERT INTO nord (id, name ) VALUES(130, 'Andrea'); INSERT INTO nord (id, name ) VALUES(183, 'Antonio'); PREPARE nexpect_ord AS SELECT id, name FROM nord ORDER BY pk; SELECT * FROM check_test( results_ne( 'nenames_ord', 'nexpect_ord', 'whatever' ), true, 'results_ne(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( results_ne( 'nenames_ord', 'nexpect_ord' ), true, 'results_ne(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( results_ne( 'EXECUTE nenames_ord', 'EXECUTE nexpect_ord' ), true, 'results_ne(execute, execute)', '', '' ); -- Compare actual SELECT statements. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM names WHERE name like ''An%'' ORDER BY id', 'SELECT id, name FROM annames WHERE name <> ''Anna'' ORDER BY id' ), true, 'results_ne(select, select)', '', '' ); UPDATE dubs SET name = 'Anna' WHERE pk = 1; UPDATE dubs SET name = 'Angelina', id = 86 WHERE pk = 2; SET client_min_messages = warning; CREATE table buds (pk SERIAL PRIMARY KEY, id int, name text); RESET client_min_messages; INSERT INTO buds (id, name) VALUES(2, 'Anna'); INSERT INTO buds (id, name) VALUES(86, 'Angelina'); INSERT INTO buds (id, name) VALUES(2, 'Anna'); -- Compare with dupes. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM dubs ORDER BY pk', 'SELECT id, name FROM buds ORDER BY pk' ), true, 'results_ne(dupe values, dupe values)', '', '' ); UPDATE dubs SET id = 4, name = NULL WHERE pk = 1; UPDATE dubs SET name = NULL WHERE pk = 3; UPDATE buds SET id = 4, name = NULL WHERE pk = 1; -- Compare with nulls. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM dubs ORDER BY pk', 'SELECT id, name FROM buds ORDER BY pk' ), true, 'results_ne(values with null, values with null)', '', '' ); -- Compare only NULLs SELECT * FROM check_test( results_ne( 'SELECT id, name FROM dupes LIMIT 3', 'SELECT id, name FROM dupes LIMIT 2' ), true, 'results_ne(nulls, nulls)', '', '' ); -- And now a failure. SELECT * FROM check_test( results_ne( 'nenames_ord', 'SELECT id, name FROM annames' ), false, 'results_ne(prepared, select) fail', '', '' ); -- Now when the last row is missing. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM annames WHERE name <> ''Antonio''', 'nenames_ord' ), true, 'results_ne(select, prepared) missing last row', '', '' ); -- Invert that. SELECT * FROM check_test( results_ne( 'nenames_ord', 'SELECT id, name FROM annames WHERE name <> ''Antonio''' ), true, 'results_ne(prepared, select) missing first row', '', '' ); UPDATE dubs SET id = 1, name = 'Anna' WHERE pk IN (1, 3); -- Compare with missing dupe. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM dubs ORDER BY pk', 'SELECT id, name FROM dubs ORDER BY pk LIMIT 2' ), true, 'results_ne(values dupe, values)', '', '' ); UPDATE dubs SET name = NULL where PK = 2; -- Handle pass with null. SELECT * FROM check_test( results_ne( 'SELECT id, name FROM dubs ORDER BY pk LIMIT 2', 'SELECT id, name FROM buds ORDER BY pk LIMIT 2' ), true, 'results_ne(values null, values)', '', '' ); -- Handle failure due to column mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'results_ne(values, values) mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: cannot compare dissimilar column types integer and text at record column 1' ELSE ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to subtle column mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1, ''foo''::varchar), (2, ''bar''::varchar)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_ne(values, values) subtle mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries ERROR: cannot compare dissimilar column types character varying and text at record column 2' ELSE ' Number of columns or their types differ between the queries ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1), (2)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_ne(values, values) fail column count', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: cannot compare record types with different numbers of columns' ELSE ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: details not available in pg <= 9.1' END ); -- Compare with cursors. CLOSE cwant; CLOSE chave; DECLARE cwant CURSOR FOR SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; DECLARE chave CURSOR FOR SELECT id, name from annames ORDER BY id; SELECT * FROM check_test( results_ne( 'cwant'::refcursor, 'chave'::refcursor ), false, 'results_ne(cursor, cursor)', '', '' ); -- Mix cursors and prepared statements DEALLOCATE annames_ord; PREPARE annames_ord AS SELECT id, name FROM annames ORDER BY id; MOVE BACKWARD ALL IN cwant; SELECT * FROM check_test( results_ne( 'cwant'::refcursor, 'annames_ord' ), false, 'results_ne(cursor, prepared)', '', '' ); MOVE BACKWARD ALL IN chave; SELECT * FROM check_test( results_ne( 'annames_ord', 'chave'::refcursor ), false, 'results_ne(prepared, cursor)', '', '' ); -- Mix cursor and SQL. SELECT * FROM check_test( results_ne( 'cwant'::refcursor, 'SELECT id, name FROM annames ORDER BY id' ), true, 'results_ne(cursor, sql)', '', '' ); MOVE BACKWARD ALL IN chave; SELECT * FROM check_test( results_ne( 'SELECT id, name FROM annames ORDER BY id', 'chave'::refcursor ), false, 'results_ne(sql, cursor)', '', '' ); /****************************************************************************/ -- Now test is_empty(). SELECT * FROM check_test( is_empty( 'SELECT 1 WHERE FALSE', 'whatever' ), true, 'is_empty(sql, desc)', 'whatever', '' ); SELECT * FROM check_test( is_empty( 'SELECT 1 WHERE FALSE' ), true, 'is_empty(sql)', '', '' ); PREPARE emptyset AS SELECT * FROM names WHERE FALSE; SELECT * FROM check_test( is_empty( 'emptyset', 'whatever' ), true, 'is_empty(prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( is_empty( 'emptyset' ), true, 'is_empty(prepared)', '', '' ); CREATE FUNCTION test_empty_fail() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN PREPARE notempty AS SELECT id, name FROM names WHERE name IN ('Jacob', 'Emily') ORDER BY ID; FOR tap IN SELECT * FROM check_test( is_empty( 'notempty', 'whatever' ), false, 'is_empty(prepared, desc) fail', 'whatever', ' Unexpected records: (1,Jacob) (2,Emily)' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( is_empty( 'notempty' ), false, 'is_empty(prepared) fail', '', ' Unexpected records: (1,Jacob) (2,Emily)' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; RETURN; END; $$ LANGUAGE PLPGSQL; SELECT * FROM test_empty_fail(); /****************************************************************************/ -- Now test isnt_empty(). SELECT * FROM check_test( isnt_empty( 'SELECT 1', 'whatever' ), true, 'isnt_empty(sql, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_empty( 'SELECT 1 WHERE FALSE', 'whatever' ), false, 'isnt_empty(sql, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_empty( 'SELECT 1 WHERE FALSE' ), false, 'isnt_empty(sql)', '', '' ); SELECT * FROM check_test( isnt_empty( 'SELECT 1' ), true, 'isnt_empty(sql)', '', '' ); PREPARE someset(boolean) AS SELECT * FROM names WHERE $1; SELECT * FROM check_test( isnt_empty( 'EXECUTE someset(true)', 'whatever' ), true, 'isnt_empty(prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_empty( 'EXECUTE someset(false)', 'whatever' ), false, 'isnt_empty(prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_empty( 'EXECUTE someset(true)' ), true, 'isnt_empty(prepared)', '', '' ); SELECT * FROM check_test( isnt_empty( 'EXECUTE someset(false)' ), false, 'isnt_empty(prepared)', '', '' ); /****************************************************************************/ -- Test row_eq(). PREPARE arow AS SELECT id, name FROM names WHERE name = 'Jacob'; CREATE TYPE sometype AS ( id INT, name TEXT ); CREATE FUNCTION test_row_eq() RETURNS SETOF TEXT AS $$ DECLARE tap record; BEGIN FOR tap IN SELECT * FROM check_test( row_eq('arow', ROW(1, 'Jacob')::names, 'whatever'), true, 'row_eq(prepared, record, desc)', 'whatever', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( row_eq('SELECT id, name FROM names WHERE id = 1', ROW(1, 'Jacob')::names, 'whatever'), true, 'row_eq(sql, record, desc)', 'whatever', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( row_eq('arow', ROW(1, 'Jacob')::names), true, 'row_eq(prepared, record, desc)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( row_eq('arow', ROW(1, 'Larry')::names), false, 'row_eq(prepared, record, desc)', '', ' have: (1,Jacob) want: (1,Larry)' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( row_eq('arow', ROW(1, 'Jacob')::sometype), true, 'row_eq(prepared, sometype, desc)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( row_eq('SELECT 1, ''Jacob''::text', ROW(1, 'Jacob')::sometype), true, 'row_eq(sqlrow, sometype, desc)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; INSERT INTO someat (ts) values ('2009-12-04T07:22:52'); IF pg_version_num() < 110000 THEN -- Prior to 11, one cannot pass a bare RECORD. RETURN NEXT throws_ok( 'SELECT row_eq( ''SELECT id, ts FROM someat'', ROW(1, ''2009-12-04T07:22:52''::timestamp) )', '0A000' -- 'PL/pgSQL functions cannot accept type record' ); RETURN NEXT pass('row_eq(qry, record) should pass'); RETURN NEXT pass('row_eq(qry, record) should have the proper description'); RETURN NEXT pass('row_eq(qry, record) should have the proper diagnostics'); ELSE -- Postgres 11 supports record arguments! RETURN NEXT pass('threw 0A000'); FOR tap IN SELECT * FROM check_test( row_eq('SELECT id, ts FROM someat', ROW(1, '2009-12-04T07:22:52'::timestamp)), true, 'row_eq(qry, record)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; END IF; RETURN; END; $$ LANGUAGE plpgsql; SELECT * FROM test_row_eq(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/roletap.sql000066400000000000000000000055311455775703000166160ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(39); --SELECT * FROM no_plan(); /****************************************************************************/ -- Test has_role() and hasnt_role(). SELECT * FROM check_test( has_role(current_role), true, 'has_role(current role)', 'Role ' || quote_ident(current_role) || ' should exist', '' ); SELECT * FROM check_test( has_role(current_role, 'whatever'), true, 'has_role(current role, desc)', 'whatever', '' ); SELECT * FROM check_test( has_role('aoijaoisjfaoidfjaisjdfosjf'), false, 'has_role(nonexistent role)', 'Role aoijaoisjfaoidfjaisjdfosjf should exist', '' ); SELECT * FROM check_test( has_role('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'has_role(nonexistent role, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_role(current_role), false, 'hasnt_role(current role)', 'Role ' || quote_ident(current_role) || ' should not exist', '' ); SELECT * FROM check_test( hasnt_role(current_role, 'whatever'), false, 'hasnt_role(current role, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_role('aoijaoisjfaoidfjaisjdfosjf'), true, 'hasnt_role(nonexistent role)', 'Role aoijaoisjfaoidfjaisjdfosjf should not exist', '' ); SELECT * FROM check_test( hasnt_role('aoijaoisjfaoidfjaisjdfosjf', 'desc'), true, 'hasnt_role(nonexistent role, desc)', 'desc', '' ); /****************************************************************************/ -- Test roles_are(). CREATE FUNCTION ___myroles(ex text) RETURNS NAME[] AS $$ SELECT COALESCE(ARRAY( SELECT rolname FROM pg_catalog.pg_roles WHERE rolname <> $1 ), '{}'::name[]);; $$ LANGUAGE SQL; SELECT * FROM check_test( roles_are( ___myroles(''), 'whatever' ), true, 'roles_are(roles, desc)', 'whatever', '' ); SELECT * FROM check_test( roles_are( ___myroles('') ), true, 'roles_are(roles)', 'There should be the correct roles', '' ); SELECT * FROM check_test( roles_are( array_append(___myroles(''), '__howdy__'), 'whatever' ), false, 'roles_are(roles, desc) missing', 'whatever', ' Missing roles: __howdy__' ); SELECT * FROM check_test( roles_are( ___myroles(current_role), 'whatever' ), false, 'roles_are(roles, desc) extras', 'whatever', ' Extra roles: ' || quote_ident(current_role) ); SELECT * FROM check_test( roles_are( array_append(___myroles(current_role), '__howdy__'), 'whatever' ), false, 'roles_are(roles, desc) missing and extras', 'whatever', ' Extra roles: ' || quote_ident(current_role) || ' Missing roles: __howdy__' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/ruletap.sql000066400000000000000000000224241455775703000166240ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(132); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '', numb NUMERIC(10, 2), myint NUMERIC(8) ); CREATE RULE ins_me AS ON INSERT TO public.sometab DO NOTHING; CREATE RULE upd_me AS ON UPDATE TO public.sometab DO ALSO SELECT now(); CREATE TABLE public.sprockets ( id INT ); CREATE RULE ins_me AS ON INSERT TO public.sprockets DO INSTEAD NOTHING; CREATE RULE del_me AS ON delete TO public.sprockets DO INSTEAD NOTHING; CREATE TABLE public.widgets (id int); CREATE RULE del_me AS ON DELETE TO public.widgets DO NOTHING; CREATE RULE ins_me AS ON INSERT TO public.widgets DO NOTHING; RESET client_min_messages; /****************************************************************************/ -- Test has_rule() and hasnt_rule(). SELECT * FROM check_test( has_rule( 'public', 'sometab', 'ins_me', 'whatever' ), true, 'has_rule(schema, table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( has_rule( 'public', 'sometab', 'ins_me'::name ), true, 'has_rule(schema, table, rule)', 'Relation public.sometab should have rule ins_me', '' ); SELECT * FROM check_test( has_rule( 'public', 'sometab', 'del_me', 'whatever' ), false, 'has_rule(schema, table, rule, desc) fail', 'whatever', '' ); SELECT * FROM check_test( has_rule( 'sometab', 'ins_me', 'whatever' ), true, 'has_rule(table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( has_rule( 'sometab', 'ins_me'::name ), true, 'has_rule(table, rule)', 'Relation sometab should have rule ins_me', '' ); SELECT * FROM check_test( has_rule( 'sometab', 'del_me', 'whatever' ), false, 'has_rule(table, rule, desc) fail', 'whatever', '' ); SELECT * FROM check_test( hasnt_rule( 'public', 'sometab', 'ins_me', 'whatever' ), false, 'hasnt_rule(schema, table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_rule( 'public', 'sometab', 'ins_me'::name ), false, 'hasnt_rule(schema, table, rule)', 'Relation public.sometab should not have rule ins_me', '' ); SELECT * FROM check_test( hasnt_rule( 'public', 'sometab', 'del_me', 'whatever' ), true, 'hasnt_rule(schema, table, rule, desc) fail', 'whatever', '' ); SELECT * FROM check_test( hasnt_rule( 'sometab', 'ins_me', 'whatever' ), false, 'hasnt_rule(table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_rule( 'sometab', 'ins_me'::name ), false, 'hasnt_rule(table, rule)', 'Relation sometab should not have rule ins_me', '' ); SELECT * FROM check_test( hasnt_rule( 'sometab', 'del_me', 'whatever' ), true, 'hasnt_rule(table, rule, desc) fail', 'whatever', '' ); /****************************************************************************/ -- Test rule_is_instead(). SELECT * FROM check_test( rule_is_instead( 'public', 'sprockets', 'ins_me', 'whatever' ), true, 'rule_is_instead(schema, table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_instead( 'public', 'sprockets', 'ins_me'::name ), true, 'rule_is_instead(schema, table, rule)', 'Rule ins_me on relation public.sprockets should be an INSTEAD rule', '' ); SELECT * FROM check_test( rule_is_instead( 'public', 'sometab', 'ins_me', 'whatever' ), false, 'rule_is_instead(schema, table, nothing rule, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_instead( 'public', 'sometab', 'upd_me', 'whatever' ), false, 'rule_is_instead(schema, table, also rule, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_instead( 'sprockets', 'ins_me', 'whatever' ), true, 'rule_is_instead(table, rule, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_instead( 'sprockets', 'ins_me'::name ), true, 'rule_is_instead(table, rule)', 'Rule ins_me on relation sprockets should be an INSTEAD rule', '' ); SELECT * FROM check_test( rule_is_instead( 'sometab', 'ins_me', 'whatever' ), false, 'rule_is_instead(table, nothing rule, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_instead( 'sometab', 'upd_me', 'whatever' ), false, 'rule_is_instead(table, also rule, desc)', 'whatever', '' ); -- Check failure diagnostics for non-existent rules. SELECT * FROM check_test( rule_is_instead( 'public', 'sometab', 'blah', 'whatever' ), false, 'rule_is_instead(schema, table, non-existent rule, desc)', 'whatever', ' Rule blah does not exist' ); SELECT * FROM check_test( rule_is_instead( 'sometab', 'blah', 'whatever' ), false, 'rule_is_instead(table, non-existent rule, desc)', 'whatever', ' Rule blah does not exist' ); /****************************************************************************/ -- Test rule_is_on(). SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(schema, table, rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'upd_me', 'update', 'whatever' ), true, 'rule_is_on(schema, table, rule, update, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sprockets', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(schema, table, rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'widgets', 'del_me', 'delete', 'whatever' ), true, 'rule_is_on(schema, table, rule, delete, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'widgets', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(schema, table, dupe rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me', 'INSERT', 'whatever' ), true, 'rule_is_on(schema, table, rule, INSERT, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me', 'i', 'whatever' ), true, 'rule_is_on(schema, table, rule, i, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me', 'indigo', 'whatever' ), true, 'rule_is_on(schema, table, rule, indigo, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me'::name, 'i' ), true, 'rule_is_on(schema, table, rule, i, desc)', 'Rule ins_me should be on INSERT to public.sometab', '' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'ins_me'::name, 'u' ), false, 'rule_is_on(schema, table, rule, u, desc) fail', 'Rule ins_me should be on UPDATE to public.sometab', ' have: INSERT want: UPDATE' ); SELECT * FROM check_test( rule_is_on( 'public', 'sometab', 'foo_me'::name, 'u' ), false, 'rule_is_on(schema, table, invalid rule, u, desc)', 'Rule foo_me should be on UPDATE to public.sometab', ' Rule foo_me does not exist on public.sometab' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(table, rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'upd_me', 'update', 'whatever' ), true, 'rule_is_on(table, rule, update, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sprockets', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(table, rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'widgets', 'del_me', 'delete', 'whatever' ), true, 'rule_is_on(table, rule, delete, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'widgets', 'ins_me', 'insert', 'whatever' ), true, 'rule_is_on(table, dupe rule, insert, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me', 'INSERT', 'whatever' ), true, 'rule_is_on(table, rule, INSERT, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me', 'i', 'whatever' ), true, 'rule_is_on(table, rule, i, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me', 'indigo', 'whatever' ), true, 'rule_is_on(table, rule, indigo, desc)', 'whatever', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me'::name, 'i' ), true, 'rule_is_on(table, rule, i, desc)', 'Rule ins_me should be on INSERT to sometab', '' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'ins_me'::name, 'u' ), false, 'rule_is_on(table, rule, u, desc) fail', 'Rule ins_me should be on UPDATE to sometab', ' have: INSERT want: UPDATE' ); SELECT * FROM check_test( rule_is_on( 'sometab', 'foo_me'::name, 'u' ), false, 'rule_is_on(table, invalid rule, u, desc)', 'Rule foo_me should be on UPDATE to sometab', ' Rule foo_me does not exist on sometab' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/runjusttests.sql000066400000000000000000000065561455775703000177550ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SET client_min_messages = warning; CREATE SCHEMA whatever; CREATE TABLE whatever.foo ( id serial primary key ); -- Make sure we get test function names. SET client_min_messages = notice; CREATE OR REPLACE FUNCTION whatever.testthis() RETURNS SETOF TEXT AS $$ SELECT collect_tap(ARRAY[ pass('simple pass'), pass('another simple pass') ]); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.testplpgsql() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); RETURN NEXT pass( 'plpgsql simple 2' ); INSERT INTO whatever.foo VALUES(1); RETURN NEXT is( MAX(id), 1, 'Should be a 1 in the test table') FROM whatever.foo; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION whatever.testplpgsqldie() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); -- Won't appear in results. RETURN NEXT pass( 'plpgsql simple 2' ); -- Won't appear in results. INSERT INTO whatever.foo VALUES(1); RETURN NEXT is( MAX(id), 1, 'Should be a 1 in the test table') FROM whatever.foo; IF pg_version_num() >= 90300 THEN EXECUTE $E$ CREATE OR REPLACE FUNCTION __die() RETURNS VOID LANGUAGE plpgsql AS $F$ BEGIN RAISE EXCEPTION 'This test should die, but not halt execution. Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself.' USING DETAIL = 'DETAIL', COLUMN = 'COLUMN', CONSTRAINT = 'CONSTRAINT', DATATYPE = 'TYPE', TABLE = 'TABLE', SCHEMA = 'SCHEMA'; END; $F$; $E$; ELSIF pg_version_num() >= 80400 THEN EXECUTE $E$ CREATE OR REPLACE FUNCTION __die() RETURNS VOID LANGUAGE plpgsql AS $F$ BEGIN RAISE EXCEPTION 'This test should die, but not halt execution. Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself.' USING DETAIL = 'DETAIL'; END; $F$; $E$; ELSE EXECUTE $E$ CREATE OR REPLACE FUNCTION __die() RETURNS VOID LANGUAGE plpgsql AS $F$ BEGIN RAISE EXCEPTION 'This test should die, but not halt execution. Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself.'; END; $F$; $E$; END IF; EXECUTE 'SELECT __die();'; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION whatever.testy() RETURNS SETOF TEXT AS $$ SELECT collect_tap(ARRAY[ pass('pass'), fail('this test intentionally fails') ]); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.testnada() RETURNS SETOF TEXT AS $$ BEGIN -- Do nothing. END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION whatever.testz() RETURNS SETOF TEXT AS $$ SELECT is( MAX(id), NULL, 'Late test should find nothing in the test table') FROM whatever.foo; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever."test ident"() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'ident' ); RETURN NEXT pass( 'ident 2' ); END; $$ LANGUAGE plpgsql; -- Run the actual tests. Yes, it's a one-liner! SELECT * FROM runtests('whatever'::name); ROLLBACK; pgtap-1.3.2/test/sql/runnotests.sql000066400000000000000000000004131455775703000173660ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SET client_min_messages = warning; CREATE SCHEMA whatever; CREATE OR REPLACE FUNCTION whatever.testthis() RETURNS SETOF TEXT AS $$ BEGIN -- Do nothing. END; $$ LANGUAGE plpgsql; SELECT * FROM runtests('whatever'::name); ROLLBACK; pgtap-1.3.2/test/sql/runtests.sql000066400000000000000000000107001455775703000170310ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SET client_min_messages = warning; CREATE SCHEMA whatever; CREATE TABLE whatever.foo ( id serial primary key ); /* Expected output: runtests.out: 9.6 and up runtests_1.out: 9.5 runtests_2.out: 9.3 - 9.4 runtests_3.out: 9.2 runtests_4.out: 9.1 */ -- Make sure we get test function names. SET client_min_messages = notice; CREATE OR REPLACE FUNCTION whatever.startup() RETURNS SETOF TEXT AS $$ SELECT pass('starting up'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.startupmore() RETURNS SETOF TEXT AS $$ SELECT pass('starting up some more'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.setup() RETURNS SETOF TEXT AS $$ SELECT collect_tap(ARRAY[ pass('setup'), (SELECT is( MAX(id), NULL, 'Should be nothing in the test table') FROM whatever.foo) ]); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.setupmore() RETURNS SETOF TEXT AS $$ SELECT pass('setup more'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.teardown() RETURNS SETOF TEXT AS $$ SELECT pass('teardown'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.teardownmore() RETURNS SETOF TEXT AS $$ SELECT pass('teardown more'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.shutdown() RETURNS SETOF TEXT AS $$ SELECT pass('shutting down'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.shutdownmore() RETURNS SETOF TEXT AS $$ SELECT pass('shutting down more'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.testthis() RETURNS SETOF TEXT AS $$ SELECT collect_tap(ARRAY[ pass('simple pass'), pass('another simple pass') ]); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.testplpgsql() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); RETURN NEXT pass( 'plpgsql simple 2' ); INSERT INTO whatever.foo VALUES(1); RETURN NEXT is( MAX(id), 1, 'Should be a 1 in the test table') FROM whatever.foo; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION whatever.testplpgsqldie() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'plpgsql simple' ); -- Won't appear in results. RETURN NEXT pass( 'plpgsql simple 2' ); -- Won't appear in results. INSERT INTO whatever.foo VALUES(1); RETURN NEXT is( MAX(id), 1, 'Should be a 1 in the test table') FROM whatever.foo; IF pg_version_num() >= 90300 THEN EXECUTE $E$ CREATE OR REPLACE FUNCTION __die() RETURNS VOID LANGUAGE plpgsql AS $F$ BEGIN RAISE EXCEPTION 'This test should die, but not halt execution. Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself.' USING DETAIL = 'DETAIL', COLUMN = 'COLUMN', CONSTRAINT = 'CONSTRAINT', DATATYPE = 'TYPE', TABLE = 'TABLE', SCHEMA = 'SCHEMA'; END; $F$; $E$; EXECUTE 'SELECT __die();'; ELSIF pg_version_num() >= 80400 THEN EXECUTE $E$ CREATE OR REPLACE FUNCTION __die() RETURNS VOID LANGUAGE plpgsql AS $F$ BEGIN RAISE EXCEPTION 'This test should die, but not halt execution. Note that in some cases we get what appears to be a duplicate context message, but that is due to Postgres itself.' USING DETAIL = 'DETAIL'; END; $F$; $E$; EXECUTE 'SELECT __die();'; ELSE RAISE EXCEPTION 'This test should die, but not halt execution'; END IF; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION whatever.testdividebyzero() RETURNS SETOF TEXT AS $$ select cast(1/0 as text) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION whatever.testy() RETURNS SETOF TEXT AS $$ SELECT fail('this test intentionally fails'); $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever.testz() RETURNS SETOF TEXT AS $$ SELECT is( MAX(id), NULL, 'Late test should find nothing in the test table') FROM whatever.foo; $$ LANGUAGE SQL; CREATE OR REPLACE FUNCTION whatever."test ident"() RETURNS SETOF TEXT AS $$ BEGIN RETURN NEXT pass( 'ident' ); RETURN NEXT pass( 'ident 2' ); END; $$ LANGUAGE plpgsql; -- Run the actual tests. Yes, it's a one-liner! SELECT * FROM runtests('whatever'::name); -- Verify that startup, shutdown, etc aren't run as normal tests SELECT * FROM runtests('whatever'::name, '.*') WHERE pg_version_num() >= 80300; ROLLBACK; pgtap-1.3.2/test/sql/throwtap.sql000066400000000000000000000253231455775703000170210ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(97); --SELECT * FROM no_plan(); /****************************************************************************/ -- test throws_ok(). SELECT * FROM check_test( throws_ok( 'SELECT * FROM todo_end()', 'P0001', 'todo_end() called without todo_start()', 'whatever' ), true, 'four-argument form', 'whatever', '' ); SELECT * FROM check_test( throws_ok( 'SELECT * FROM todo_end()', 'P0001', 'todo_end() called without todo_start()'), true, 'three-argument errcode', 'threw P0001: todo_end() called without todo_start()', '' ); SELECT * FROM check_test( throws_ok( 'SELECT 1 / 0', '22012' ), true, 'two-argument errcode', 'threw 22012' '' ); SELECT * FROM check_test( throws_ok( 'SELECT * FROM todo_end()', 'todo_end() called without todo_start()', 'whatever'), true, 'three argument errmsg', 'whatever', '' ); SELECT * FROM check_test( throws_ok( 'SELECT * FROM todo_end()', 'todo_end() called without todo_start()'), true, 'two-argument errmsg', 'threw todo_end() called without todo_start()', '' ); SELECT * FROM check_test( throws_ok( 'SELECT 1 / 0' ), true, 'single-argument form', 'threw an exception', '' ); -- Try using a prepared statement. PREPARE mytest AS SELECT * FROM todo_end(); SELECT * FROM check_test( throws_ok( 'mytest', 'P0001'), true, 'prepared statement & errcode', 'threw P0001' '' ); SELECT * FROM check_test( throws_ok( 'EXECUTE mytest', 'P0001'), true, 'execute & errcode', 'threw P0001' '' ); -- Check its diagnostics for an invalid error code. SELECT * FROM check_test( throws_ok( 'SELECT * FROM todo_end()', 97212 ), false, 'invalid errcode', 'threw 97212', ' caught: P0001: todo_end() called without todo_start() wanted: 97212' ); SELECT throws_ok( 'SELECT 1 / 0', NULL, NULL, 'throws_ok(1/0, NULL) should work' ); -- Check its diagnostics no error. SELECT * FROM check_test( throws_ok( 'SELECT 1', NULL ), false, 'throws_ok diagnostics', 'threw an exception', ' caught: no exception wanted: an exception' ); /****************************************************************************/ -- test lives_ok(). SELECT lives_ok( 'SELECT 1', 'lives_ok() should work' ); PREPARE livetest AS SELECT 1; SELECT * FROM check_test( lives_ok( 'livetest'), true, 'lives_ok(prepared)' '', '' ); SELECT * FROM check_test( lives_ok( 'EXECUTE livetest'), true, 'lives_ok(execute)' '', '' ); -- Check its diagnostics when there is an exception. SELECT * FROM check_test( lives_ok( 'SELECT * FROM todo_end()' ), false, 'lives_ok failure diagnostics', '', ' died: P0001: todo_end() called without todo_start()' || CASE WHEN pg_version_num() < 90200 THEN '' ELSE ' CONTEXT:' || CASE WHEN pg_version_num() < 90600 THEN '' ELSE ' PL/pgSQL function todo_end() line 7 at RAISE' END || ' SQL statement "SELECT * FROM todo_end()" PL/pgSQL function lives_ok(text,text) line 14 at EXECUTE' || CASE WHEN pg_version_num() >= 90500 THEN '' ELSE ' statement' END END ); /****************************************************************************/ -- test throws_like(). SELECT * FROM check_test( throws_like( 'SELECT * FROM todo_end()', '%end() called without todo%', 'whatever' ), true, 'throws_like(sql, pattern, desc)', 'whatever', '' ); SELECT * FROM check_test( throws_like( 'SELECT * FROM todo_end()', '%end() called without todo%' ), true, 'throws_like(sql, pattern)', 'Should throw exception like ''%end() called without todo%''', '' ); SELECT * FROM check_test( throws_like( 'SELECT * FROM todo_end()', '%huh%', 'whatever' ), false, 'throws_like(sql, pattern, desc) fail', 'whatever', ' error message: ''todo_end() called without todo_start()'' doesn''t match: ''%huh%''' ); SELECT * FROM check_test( throws_like( 'SELECT 1', '%huh%', 'whatever' ), false, 'throws_like(valid sql, pattern, desc)', 'whatever', ' no exception thrown' ); /****************************************************************************/ -- test throws_ilike(). SELECT * FROM check_test( throws_ilike( 'SELECT * FROM todo_end()', '%END() called without todo%', 'whatever' ), true, 'throws_ilike(sql, pattern, desc)', 'whatever', '' ); SELECT * FROM check_test( throws_ilike( 'SELECT * FROM todo_end()', '%END() called without todo%' ), true, 'throws_ilike(sql, pattern)', 'Should throw exception like ''%END() called without todo%''', '' ); SELECT * FROM check_test( throws_ilike( 'SELECT * FROM todo_end()', '%HUH%', 'whatever' ), false, 'throws_ilike(sql, pattern, desc) fail', 'whatever', ' error message: ''todo_end() called without todo_start()'' doesn''t match: ''%HUH%''' ); SELECT * FROM check_test( throws_ilike( 'SELECT 1', '%HUH%', 'whatever' ), false, 'throws_ilike(valid sql, pattern, desc)', 'whatever', ' no exception thrown' ); /****************************************************************************/ -- test throws_matching(). SELECT * FROM check_test( throws_matching( 'SELECT * FROM todo_end()', '.*end[(][)] called without todo.+', 'whatever' ), true, 'throws_matching(sql, regex, desc)', 'whatever', '' ); SELECT * FROM check_test( throws_matching( 'SELECT * FROM todo_end()', '.*end[(][)] called without todo.+' ), true, 'throws_matching(sql, regex, desc)', 'Should throw exception matching ''.*end[(][)] called without todo.+''', '' ); SELECT * FROM check_test( throws_matching( 'SELECT * FROM todo_end()', 'huh.+', 'whatever' ), false, 'throws_matching(sql, regex, desc)', 'whatever', ' error message: ''todo_end() called without todo_start()'' doesn''t match: ''huh.+''' ); SELECT * FROM check_test( throws_matching( 'SELECT 1', 'huh.+', 'whatever' ), false, 'throws_matching(valid sql, regex, desc)', 'whatever', ' no exception thrown' ); /****************************************************************************/ -- test throws_imatching(). SELECT * FROM check_test( throws_imatching( 'SELECT * FROM todo_end()', '.*end[(][)] CALLED without todo.+', 'whatever' ), true, 'throws_imatching(sql, regex, desc)', 'whatever', '' ); SELECT * FROM check_test( throws_imatching( 'SELECT * FROM todo_end()', '.*end[(][)] CALLED without todo.+' ), true, 'throws_imatching(sql, regex, desc)', 'Should throw exception matching ''.*end[(][)] CALLED without todo.+''', '' ); SELECT * FROM check_test( throws_imatching( 'SELECT * FROM todo_end()', 'HUH.+', 'whatever' ), false, 'throws_imatching(sql, regex, desc)', 'whatever', ' error message: ''todo_end() called without todo_start()'' doesn''t match: ''HUH.+''' ); SELECT * FROM check_test( throws_imatching( 'SELECT 1', 'HUH.+', 'whatever' ), false, 'throws_imatching(valid sql, regex, desc)', 'whatever', ' no exception thrown' ); /****************************************************************************/ -- Test ASSERTs SELECT lives_ok( CASE WHEN pg_version_num() < 90500 THEN $exec$ CREATE FUNCTION check_assert(b boolean) RETURNS void LANGUAGE plpgsql AS $body$ BEGIN RAISE EXCEPTION 'this code should never be called!'; END $body$; $exec$ ELSE $exec$ CREATE FUNCTION check_assert(b boolean) RETURNS void LANGUAGE plpgsql AS $body$ BEGIN ASSERT b IS TRUE, 'assert description'; END $body$; $exec$ END , 'Create check_assert function' ); CREATE FUNCTION test_assert() RETURNS SETOF text LANGUAGE plpgsql AS $body$ DECLARE tap record; BEGIN IF pg_version_num() >= 90500 THEN FOR tap IN SELECT * FROM check_test( throws_ok( 'SELECT check_assert(false)', 'P0004', 'assert description' ), true, 'throws_ok catches assert', 'threw P0004: assert description', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( throws_ok( 'SELECT check_assert(true)', 'P0004' ), false, 'throws_ok does not accept passing assert', 'threw P0004', ' caught: no exception wanted: P0004' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( lives_ok( 'SELECT check_assert(true)' ), true, 'lives_ok calling check_assert(true)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; -- Check its diagnostics when there is an exception. FOR tap IN SELECT * FROM check_test( lives_ok( 'SELECT check_assert(false)' ), false, 'lives_ok with check_assert(false)', '', ' died: P0004: assert description CONTEXT: PL/pgSQL function check_assert(boolean) line 3 at ASSERT SQL statement "SELECT check_assert(false)" PL/pgSQL function lives_ok(text,text) line 14 at EXECUTE PL/pgSQL function test_assert() line 38 at FOR over SELECT rows' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; ELSE FOR tap IN SELECT * FROM check_test( pass(''), true, 'throws_ok catches assert', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( fail(''), false, 'throws_ok does not accept passing assert', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; FOR tap IN SELECT * FROM check_test( pass(''), true, 'lives_ok calling check_assert(true)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; -- Check its diagnostics when there is an exception. FOR tap IN SELECT * FROM check_test( fail(''), false, 'lives_ok with check_assert(false)', '', '' ) AS a(b) LOOP RETURN NEXT tap.b; END LOOP; END IF; END; $body$; SELECT * FROM test_assert(); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/todotap.sql000066400000000000000000000117161455775703000166240ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(36); --SELECT * FROM no_plan(); /****************************************************************************/ -- Test todo tests. \echo ok 1 - todo fail \echo ok 2 - todo pass SELECT * FROM todo('just because', 2 ); SELECT is( fail('This is a todo test' ) || ' ' || pass('This is a todo test that unexpectedly passes' ), 'not ok 1 - This is a todo test # TODO just because # Failed (TODO) test 1: "This is a todo test" ok 2 - This is a todo test that unexpectedly passes # TODO just because', 'TODO tests should display properly' ); -- Try just a reason. \echo ok 4 - todo fail SELECT * FROM todo( 'for whatever reason' ); SELECT is( fail('Another todo test'), 'not ok 4 - Another todo test # TODO for whatever reason # Failed (TODO) test 4: "Another todo test"', 'Single default todo test should display properly' ); -- Try just a number. \echo ok 6 - todo fail \echo ok 7 - todo pass SELECT * FROM todo( 2 ); SELECT is( fail('This is a todo test' ) || ' ' || pass('This is a todo test that unexpectedly passes' ), 'not ok 6 - This is a todo test # TODO # Failed (TODO) test 6: "This is a todo test" ok 7 - This is a todo test that unexpectedly passes # TODO ', 'TODO tests should display properly' ); /****************************************************************************/ -- Test skipping tests. SELECT * FROM check_test( skip('Just because'), true, 'simple skip', '', 'SKIP Just because' ); SELECT * FROM check_test( skip('Just because', 1), true, 'skip with num', '', 'SKIP Just because' ); \echo ok 15 - Skip multiple \echo ok 16 - Skip multiple \echo ok 17 - Skip multiple SELECT is( skip( 'Whatever', 3 ), 'ok 15 # SKIP Whatever ok 16 # SKIP Whatever ok 17 # SKIP Whatever', 'We should get the proper output for multiple skips' ); -- Test inversion. SELECT * FROM check_test( skip(1, 'Just because'), true, 'inverted skip', '', 'SKIP Just because' ); -- Test num only. SELECT * FROM check_test( skip(1), true, 'num only', '', 'SKIP' ); /****************************************************************************/ -- Try nesting todo tests. \echo ok 25 - todo fail \echo ok 26 - todo fail \echo ok 27 - todo fail SELECT * FROM todo('just because', 2 ); SELECT is( ARRAY( SELECT fail('This is a todo test 1') AS stuff UNION SELECT todo::text FROM todo('inside') UNION SELECT fail('This is a todo test 2') UNION SELECT fail('This is a todo test 3') ORDER BY stuff ), ARRAY[ 'not ok 25 - This is a todo test 1 # TODO just because # Failed (TODO) test 25: "This is a todo test 1"', 'not ok 26 - This is a todo test 2 # TODO inside # Failed (TODO) test 26: "This is a todo test 2"', 'not ok 27 - This is a todo test 3 # TODO just because # Failed (TODO) test 27: "This is a todo test 3"' ], 'Nested todos should work properly' ); /****************************************************************************/ -- Test todo_start() and todo_end(). \echo ok 29 - todo fail \echo ok 30 - todo fail \echo ok 31 - todo fail SELECT * FROM todo_start('some todos'); SELECT is( ARRAY( SELECT fail('This is a todo test 1') AS stuff UNION SELECT in_todo()::text UNION SELECT todo::text FROM todo('inside') UNION SELECT fail('This is a todo test 2') UNION SELECT fail('This is a todo test 3') UNION SELECT todo_end::text FROM todo_end() UNION SELECT in_todo()::text ORDER BY stuff ), ARRAY[ 'false', 'not ok 29 - This is a todo test 1 # TODO some todos # Failed (TODO) test 29: "This is a todo test 1"', 'not ok 30 - This is a todo test 2 # TODO inside # Failed (TODO) test 30: "This is a todo test 2"', 'not ok 31 - This is a todo test 3 # TODO some todos # Failed (TODO) test 31: "This is a todo test 3"', 'true' ], 'todo_start() and todo_end() should work properly with in_todo()' ); /****************************************************************************/ -- Make sure we can reverse the arguments. \echo ok 33 - todo fail \echo ok 34 - todo pass SELECT * FROM todo(2, 'just because' ); SELECT is( fail('This is a todo test' ) || ' ' || fail('Another todo test'), 'not ok 33 - This is a todo test # TODO just because # Failed (TODO) test 33: "This is a todo test" not ok 34 - Another todo test # TODO just because # Failed (TODO) test 34: "Another todo test"', 'Should be able to revers the arguments to todo()' ); -- Test the exception. SELECT throws_ok( 'SELECT todo_end()', 'P0001', 'todo_end() called without todo_start()', 'Should get an exception when todo_end() is called without todo_start()' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/trigger.sql000066400000000000000000000155771455775703000166260ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(84); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.users( nick text NOT NULL PRIMARY KEY, pass text NOT NULL ); CREATE FUNCTION public.hash_pass() RETURNS TRIGGER AS ' BEGIN NEW.pass := MD5( NEW.pass ); RETURN NEW; END; ' LANGUAGE plpgsql; CREATE TRIGGER set_users_pass BEFORE INSERT ON public.users FOR EACH ROW EXECUTE PROCEDURE hash_pass(); CREATE TRIGGER upd_users_pass BEFORE UPDATE ON public.users FOR EACH ROW EXECUTE PROCEDURE hash_pass(); RESET client_min_messages; /****************************************************************************/ -- Test has_trigger() and hasnt_trigger(). SELECT * FROM check_test( has_trigger( 'public', 'users', 'set_users_pass', 'whatever' ), true, 'has_trigger(schema, table, trigger, desc)', 'whatever', '' ); SELECT * FROM check_test( has_trigger( 'public', 'users', 'set_users_pass'::name ), true, 'has_trigger(schema, table, trigger)', 'Table public.users should have trigger set_users_pass', '' ); SELECT * FROM check_test( has_trigger( 'users', 'set_users_pass', 'whatever' ), true, 'has_trigger(table, trigger, desc)', 'whatever', '' ); SELECT * FROM check_test( has_trigger( 'users', 'set_users_pass' ), true, 'has_trigger(table, trigger)', 'Table users should have trigger set_users_pass', '' ); SELECT * FROM check_test( has_trigger( 'public', 'users', 'nosuch', 'whatever' ), false, 'has_trigger(schema, table, nonexistent, desc)', 'whatever', '' ); SELECT * FROM check_test( has_trigger( 'users', 'nosuch' ), false, 'has_trigger(table, nonexistent) no schema fail', 'Table users should have trigger nosuch', '' ); SELECT * FROM check_test( hasnt_trigger( 'public', 'users', 'set_users_pass', 'whatever' ), false, 'hasnt_trigger(schema, table, trigger, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_trigger( 'public', 'users', 'set_users_pass'::name ), false, 'hasnt_trigger(schema, table, trigger)', 'Table public.users should not have trigger set_users_pass', '' ); SELECT * FROM check_test( hasnt_trigger( 'users', 'set_users_pass', 'whatever' ), false, 'hasnt_trigger(table, trigger, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_trigger( 'users', 'set_users_pass' ), false, 'hasnt_trigger(table, trigger)', 'Table users should not have trigger set_users_pass', '' ); SELECT * FROM check_test( hasnt_trigger( 'public', 'users', 'nosuch', 'whatever' ), true, 'hasnt_trigger(schema, table, nonexistent, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_trigger( 'users', 'nosuch' ), true, 'hasnt_trigger(table, nonexistent) no schema fail', 'Table users should not have trigger nosuch', '' ); /****************************************************************************/ -- test trigger_is() SELECT * FROM check_test( trigger_is( 'public', 'users', 'set_users_pass', 'public', 'hash_pass', 'whatever' ), true, 'trigger_is()', 'whatever', '' ); SELECT * FROM check_test( trigger_is( 'public', 'users', 'set_users_pass', 'public', 'hash_pass' ), true, 'trigger_is() no desc', 'Trigger set_users_pass should call public.hash_pass()', '' ); SELECT * FROM check_test( trigger_is( 'users', 'set_users_pass', 'hash_pass', 'whatever' ), true, 'trigger_is() no schema', 'whatever', '' ); SELECT * FROM check_test( trigger_is( 'users', 'set_users_pass', 'hash_pass' ), true, 'trigger_is() no schema or desc', 'Trigger set_users_pass should call hash_pass()', '' ); SELECT * FROM check_test( trigger_is( 'public', 'users', 'set_users_pass', 'public', 'oops', 'whatever' ), false, 'trigger_is() fail', 'whatever', ' have: public.hash_pass want: public.oops' ); SELECT * FROM check_test( trigger_is( 'users', 'set_users_pass', 'oops' ), false, 'trigger_is() no schema fail', 'Trigger set_users_pass should call oops()', ' have: hash_pass want: oops' ); /****************************************************************************/ -- Test triggers_are(). SELECT * FROM check_test( triggers_are( 'public', 'users', ARRAY['set_users_pass', 'upd_users_pass'], 'whatever' ), true, 'triggers_are(schema, table, triggers, desc)', 'whatever', '' ); SELECT * FROM check_test( triggers_are( 'public', 'users', ARRAY['set_users_pass', 'upd_users_pass'] ), true, 'triggers_are(schema, table, triggers)', 'Table public.users should have the correct triggers', '' ); SELECT * FROM check_test( triggers_are( 'public', 'users', ARRAY['set_users_pass'] ), false, 'triggers_are(schema, table, triggers) + extra', 'Table public.users should have the correct triggers', ' Extra triggers: upd_users_pass' ); SELECT * FROM check_test( triggers_are( 'public', 'users', ARRAY['set_users_pass', 'upd_users_pass', 'howdy'] ), false, 'triggers_are(schema, table, triggers) + missing', 'Table public.users should have the correct triggers', ' Missing triggers: howdy' ); SELECT * FROM check_test( triggers_are( 'public', 'users', ARRAY['set_users_pass', 'howdy'] ), false, 'triggers_are(schema, table, triggers) + extra & missing', 'Table public.users should have the correct triggers', ' Extra triggers: upd_users_pass Missing triggers: howdy' ); SELECT * FROM check_test( triggers_are( 'users', ARRAY['set_users_pass', 'upd_users_pass'], 'whatever' ), true, 'triggers_are(table, triggers, desc)', 'whatever', '' ); SELECT * FROM check_test( triggers_are( 'users', ARRAY['set_users_pass', 'upd_users_pass'] ), true, 'triggers_are(table, triggers)', 'Table users should have the correct triggers', '' ); SELECT * FROM check_test( triggers_are( 'users', ARRAY['set_users_pass'] ), false, 'triggers_are(table, triggers) + extra', 'Table users should have the correct triggers', ' Extra triggers: upd_users_pass' ); SELECT * FROM check_test( triggers_are( 'users', ARRAY['set_users_pass', 'upd_users_pass', 'howdy'] ), false, 'triggers_are(table, triggers) + missing', 'Table users should have the correct triggers', ' Missing triggers: howdy' ); SELECT * FROM check_test( triggers_are( 'users', ARRAY['set_users_pass', 'howdy'] ), false, 'triggers_are(table, triggers) + extra & missing', 'Table users should have the correct triggers', ' Extra triggers: upd_users_pass Missing triggers: howdy' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/unique.sql000066400000000000000000000120351455775703000164530ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(18*3); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE public.sometab( id INT NOT NULL PRIMARY KEY, name TEXT DEFAULT '' UNIQUE, numb NUMERIC(10, 2), myint NUMERIC(8), UNIQUE (numb, myint) ); -- This table has no unique index CREATE TABLE public.uniqueless( id INT PRIMARY KEY ); RESET client_min_messages; /****************************************************************************/ -- Test has_unique(). SELECT * FROM check_test( has_unique( 'public', 'sometab', 'public.sometab should have a unique constraint' ), true, 'has_unique( schema, table, description )', 'public.sometab should have a unique constraint', '' ); SELECT * FROM check_test( has_unique( 'sometab', 'sometab should have a unique constraint' ), true, 'has_unique( table, description )', 'sometab should have a unique constraint', '' ); SELECT * FROM check_test( has_unique( 'sometab' ), true, 'has_unique( table )', 'Table sometab should have a unique constraint', '' ); SELECT * FROM check_test( has_unique( 'public', 'uniqueless', 'public.uniqueless should have a unique constraint' ), false, 'has_unique( schema, table, description ) fail', 'public.uniqueless should have a unique constraint', '' ); SELECT * FROM check_test( has_unique( 'uniqueless', 'uniqueless should have a unique constraint' ), false, 'has_unique( table, description ) fail', 'uniqueless should have a unique constraint', '' ); /****************************************************************************/ -- Test col_is_unique(). SELECT * FROM check_test( col_is_unique( 'public', 'sometab', 'name', 'public.sometab.name should be unique' ), true, 'col_is_unique( schema, table, column, description )', 'public.sometab.name should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'public', 'sometab', ARRAY['numb', 'myint'], 'public.sometab.numb+myint should be unique' ), true, 'col_is_unique( schema, table, columns, description )', 'public.sometab.numb+myint should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'sometab', 'name', 'sometab.name should be unique' ), true, 'col_is_unique( table, column, description )', 'sometab.name should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'sometab', ARRAY['numb', 'myint'], 'sometab.numb+myint should be unique' ), true, 'col_is_unique( table, columns, description )', 'sometab.numb+myint should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'public', 'sometab', 'name'::name ), true, 'col_is_unique( schema, table, column )', 'Column sometab(name) should have a unique constraint', '' ); SELECT * FROM check_test( col_is_unique( 'public', 'sometab', ARRAY['numb'::name, 'myint'] ), true, 'col_is_unique( schema, table, columns )', 'Columns sometab(numb, myint) should have a unique constraint', '' ); SELECT * FROM check_test( col_is_unique( 'sometab', 'name' ), true, 'col_is_unique( table, column )', 'Column sometab(name) should have a unique constraint', '' ); SELECT * FROM check_test( col_is_unique( 'sometab', ARRAY['numb', 'myint'] ), true, 'col_is_unique( table, columns )', 'Columns sometab(numb, myint) should have a unique constraint', '' ); SELECT * FROM check_test( col_is_unique( 'public', 'sometab', 'id', 'public.sometab.id should be unique' ), false, 'col_is_unique( schema, table, column, description ) fail', 'public.sometab.id should be unique', ' have: {name} {numb,myint} want: {id}' ); SELECT * FROM check_test( col_is_unique( 'sometab', 'id', 'sometab.id should be unique' ), false, 'col_is_unique( table, column, description ) fail', 'sometab.id should be unique', ' have: {name} {numb,myint} want: {id}' ); /****************************************************************************/ -- Test col_is_unique() with an array of columns. SET client_min_messages = warning; CREATE TABLE public.argh ( id INT NOT NULL, name TEXT NOT NULL, UNIQUE (id, name) ); RESET client_min_messages; SELECT * FROM check_test( col_is_unique( 'public', 'argh', ARRAY['id', 'name'], 'id + name should be unique' ), true, 'col_is_unique( schema, table, column[], description )', 'id + name should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'argh', ARRAY['id', 'name'], 'id + name should be unique' ), true, 'col_is_unique( table, column[], description )', 'id + name should be unique', '' ); SELECT * FROM check_test( col_is_unique( 'argh', ARRAY['id', 'name'] ), true, 'col_is_unique( table, column[] )', 'Columns argh(id, name) should have a unique constraint', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/usergroup.sql000066400000000000000000000142141455775703000172010ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(90); --SELECT * FROM no_plan(); /****************************************************************************/ -- Test has_user() and hasnt_user(). SELECT * FROM check_test( has_user(current_user), true, 'has_user(current user)', 'User ' || quote_ident(current_user) || ' should exist', '' ); SELECT * FROM check_test( has_user(current_user, 'whatever'), true, 'has_user(current user, desc)', 'whatever', '' ); SELECT * FROM check_test( has_user('aoijaoisjfaoidfjaisjdfosjf'), false, 'has_user(nonexistent user)', 'User aoijaoisjfaoidfjaisjdfosjf should exist', '' ); SELECT * FROM check_test( has_user('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'has_user(nonexistent user, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_user(current_user), false, 'hasnt_user(current user)', 'User ' || quote_ident(current_user) || ' should not exist', '' ); SELECT * FROM check_test( hasnt_user(current_user, 'whatever'), false, 'hasnt_user(current user, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_user('aoijaoisjfaoidfjaisjdfosjf'), true, 'hasnt_user(nonexistent user)', 'User aoijaoisjfaoidfjaisjdfosjf should not exist', '' ); SELECT * FROM check_test( hasnt_user('aoijaoisjfaoidfjaisjdfosjf', 'desc'), true, 'hasnt_user(nonexistent user, desc)', 'desc', '' ); /****************************************************************************/ -- Test is_superuser() and isnt_superuser(). SELECT * FROM check_test( is_superuser('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'is_superuser(nonexistent user, desc)', 'desc', ' User aoijaoisjfaoidfjaisjdfosjf does not exist' ); SELECT * FROM check_test( is_superuser('aoijaoisjfaoidfjaisjdfosjf'), false, 'is_superuser(nonexistent user)', 'User aoijaoisjfaoidfjaisjdfosjf should be a super user', ' User aoijaoisjfaoidfjaisjdfosjf does not exist' ); SELECT * FROM check_test( isnt_superuser('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'isnt_superuser(nonexistent user, desc)', 'desc', ' User aoijaoisjfaoidfjaisjdfosjf does not exist' ); SELECT * FROM check_test( isnt_superuser('aoijaoisjfaoidfjaisjdfosjf'), false, 'isnt_superuser(nonexistent user)', 'User aoijaoisjfaoidfjaisjdfosjf should not be a super user', ' User aoijaoisjfaoidfjaisjdfosjf does not exist' ); SELECT * FROM check_test( is_superuser(current_user), true, 'is_superuser( current user )', 'User ' || quote_ident(current_user) || ' should be a super user', '' ); SELECT * FROM check_test( is_superuser(current_user, 'whatever'), true, 'is_superuser( current user, desc )', 'whatever', '' ); /****************************************************************************/ -- Test has_group() and hasnt_group(). CREATE GROUP meanies; SELECT * FROM check_test( has_group('meanies'), true, 'has_group(group)', 'Group ' || quote_ident('meanies') || ' should exist', '' ); SELECT * FROM check_test( has_group('meanies', 'whatever'), true, 'has_group(group, desc)', 'whatever', '' ); SELECT * FROM check_test( has_group('aoijaoisjfaoidfjaisjdfosjf'), false, 'has_group(nonexistent group)', 'Group aoijaoisjfaoidfjaisjdfosjf should exist', '' ); SELECT * FROM check_test( has_group('aoijaoisjfaoidfjaisjdfosjf', 'desc'), false, 'has_group(nonexistent group, desc)', 'desc', '' ); SELECT * FROM check_test( hasnt_group('meanies'), false, 'hasnt_group(group)', 'Group ' || quote_ident('meanies') || ' should not exist', '' ); SELECT * FROM check_test( hasnt_group('meanies', 'whatever'), false, 'hasnt_group(group, desc)', 'whatever', '' ); SELECT * FROM check_test( hasnt_group('aoijaoisjfaoidfjaisjdfosjf'), true, 'hasnt_group(nonexistent group)', 'Group aoijaoisjfaoidfjaisjdfosjf should not exist', '' ); SELECT * FROM check_test( hasnt_group('aoijaoisjfaoidfjaisjdfosjf', 'desc'), true, 'hasnt_group(nonexistent group, desc)', 'desc', '' ); /****************************************************************************/ -- Test isnt_member_of(). SELECT * FROM check_test( isnt_member_of('meanies', ARRAY[current_user], 'whatever' ), true, 'isnt_member_of(meanies, [current_user], desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_member_of('meanies', ARRAY[current_user] ), true, 'isnt_member_of(meanies, [current_user])', 'Should not have members of role meanies', '' ); SELECT * FROM check_test( isnt_member_of('meanies', current_user, 'whatever' ), true, 'isnt_member_of(meanies, current_user, desc)', 'whatever', '' ); SELECT * FROM check_test( isnt_member_of('meanies', current_user ), true, 'isnt_member_of(meanies, current_user)', 'Should not have members of role meanies', '' ); /****************************************************************************/ -- Test is_member_of(). CREATE OR REPLACE FUNCTION addmember() RETURNS SETOF TEXT AS $$ BEGIN EXECUTE 'ALTER GROUP meanies ADD USER ' || quote_ident(current_user); RETURN; END; $$ LANGUAGE PLPGSQL; SELECT * FROM addmember(); SELECT * FROM check_test( is_member_of('meanies', ARRAY[current_user], 'whatever' ), true, 'is_member_of(meanies, [current_user], desc)', 'whatever', '' ); SELECT * FROM check_test( is_member_of('meanies', ARRAY[current_user] ), true, 'is_member_of(meanies, [current_user])', 'Should have members of role meanies', '' ); SELECT * FROM check_test( is_member_of('meanies', current_user, 'whatever' ), true, 'is_member_of(meanies, current_user, desc)', 'whatever', '' ); SELECT * FROM check_test( is_member_of('meanies', current_user ), true, 'is_member_of(meanies, current_user)', 'Should have members of role meanies', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/util.sql000066400000000000000000000045641455775703000161320ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(14); --SELECT * FROM no_plan(); SELECT is( pg_typeof(42), 'integer', 'pg_type(int) should work' ); SELECT is( pg_typeof(42.1), 'numeric', 'pg_type(numeric) should work' ); SELECT is( pg_typeof(''::text), 'text', 'pg_type(text) should work' ); SELECT is( pg_typeof( pg_version() ), 'text', 'pg_version() should return text' ); SELECT is( pg_version(), current_setting( 'server_version'), 'pg_version() should return same as "server_version" setting' ); SELECT matches( pg_version(), '(?x)' '(?: ^[89][.][[:digit:]]{1,2}([.][[:digit:]]{1,2}|devel|(alpha|beta|rc)[[:digit:]]+) )' '|' '(?: ^1[[:digit:]] (?: [.] [[:digit:]]{1,2} | devel | (?:alpha|beta|rc)[[:digit:]]+))', 'pg_version() should work' ); SELECT CASE WHEN pg_version_num() < 81000 THEN pass( 'pg_version_num() should return same as "server_version_num" setting' ) ELSE is( pg_version_num(), current_setting('server_version_num')::integer, 'pg_version_num() should return same as "server_version_num" setting' ) END; SELECT is( pg_typeof( pg_version_num() ), 'integer', 'pg_version_num() should return integer' ); SELECT matches( pg_version_num()::text, '^[89][[:digit:]]{4}$|^1[[:digit:]]{5}$', 'pg_version_num() should be correct' ); SELECT matches( os_name(), '^[[:alnum:]]+$', 'os_name() should output something like an OS name' ); SELECT is( findfuncs('pg_catalog'::name, '^abs$'), ARRAY['pg_catalog.abs'], 'findfincs() should return distinct values' ); SELECT cmp_ok( pgtap_version(), '>=', 1.0, 'pgtap_version() should work' ); /****************************************************************************/ -- Test collect_tap(). SELECT is( collect_tap(ARRAY['foo', 'bar', 'baz']), 'foo bar baz', 'collect_tap(text[]) should simply collect tap' ); CREATE FUNCTION test_variadic() RETURNS TEXT AS $$ BEGIN IF pg_version_num() >= 80400 THEN RETURN collect_tap('foo', 'bar', 'baz'); ELSE RETURN collect_tap(ARRAY['foo', 'bar', 'baz']); END IF; END; $$ LANGUAGE plpgsql; SELECT is( test_variadic(), 'foo bar baz', 'variadic collect_tap() should simply collect tap' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/sql/valueset.sql000066400000000000000000001241551455775703000170040ustar00rootroot00000000000000\unset ECHO \i test/setup.sql SELECT plan(349); --SELECT * FROM no_plan(); -- This will be rolled back. :-) SET client_min_messages = warning; CREATE TABLE names ( id SERIAL NOT NULL PRIMARY KEY, name TEXT DEFAULT '' ); RESET client_min_messages; -- Top 100 boy an 100 girl names in 2005. https://www.ssa.gov/OACT/babynames/ INSERT INTO names (name) VALUES ('Jacob'); INSERT INTO names (name) VALUES ('Emily'); INSERT INTO names (name) VALUES ('Michael'); INSERT INTO names (name) VALUES ('Emma'); INSERT INTO names (name) VALUES ('Joshua'); INSERT INTO names (name) VALUES ('Madison'); INSERT INTO names (name) VALUES ('Matthew'); INSERT INTO names (name) VALUES ('Abigail'); INSERT INTO names (name) VALUES ('Ethan'); INSERT INTO names (name) VALUES ('Olivia'); INSERT INTO names (name) VALUES ('Andrew'); INSERT INTO names (name) VALUES ('Isabella'); INSERT INTO names (name) VALUES ('Daniel'); INSERT INTO names (name) VALUES ('Hannah'); INSERT INTO names (name) VALUES ('Anthony'); INSERT INTO names (name) VALUES ('Samantha'); INSERT INTO names (name) VALUES ('Christopher'); INSERT INTO names (name) VALUES ('Ava'); INSERT INTO names (name) VALUES ('Joseph'); INSERT INTO names (name) VALUES ('Ashley'); INSERT INTO names (name) VALUES ('William'); INSERT INTO names (name) VALUES ('Elizabeth'); INSERT INTO names (name) VALUES ('Alexander'); INSERT INTO names (name) VALUES ('Sophia'); INSERT INTO names (name) VALUES ('David'); INSERT INTO names (name) VALUES ('Alexis'); INSERT INTO names (name) VALUES ('Ryan'); INSERT INTO names (name) VALUES ('Grace'); INSERT INTO names (name) VALUES ('Nicholas'); INSERT INTO names (name) VALUES ('Sarah'); INSERT INTO names (name) VALUES ('Tyler'); INSERT INTO names (name) VALUES ('Alyssa'); INSERT INTO names (name) VALUES ('James'); INSERT INTO names (name) VALUES ('Mia'); INSERT INTO names (name) VALUES ('John'); INSERT INTO names (name) VALUES ('Natalie'); INSERT INTO names (name) VALUES ('Jonathan'); INSERT INTO names (name) VALUES ('Chloe'); INSERT INTO names (name) VALUES ('Nathan'); INSERT INTO names (name) VALUES ('Brianna'); INSERT INTO names (name) VALUES ('Samuel'); INSERT INTO names (name) VALUES ('Lauren'); INSERT INTO names (name) VALUES ('Christian'); INSERT INTO names (name) VALUES ('Anna'); INSERT INTO names (name) VALUES ('Noah'); INSERT INTO names (name) VALUES ('Ella'); INSERT INTO names (name) VALUES ('Dylan'); INSERT INTO names (name) VALUES ('Taylor'); INSERT INTO names (name) VALUES ('Benjamin'); INSERT INTO names (name) VALUES ('Kayla'); INSERT INTO names (name) VALUES ('Logan'); INSERT INTO names (name) VALUES ('Hailey'); INSERT INTO names (name) VALUES ('Brandon'); INSERT INTO names (name) VALUES ('Jessica'); INSERT INTO names (name) VALUES ('Gabriel'); INSERT INTO names (name) VALUES ('Victoria'); INSERT INTO names (name) VALUES ('Zachary'); INSERT INTO names (name) VALUES ('Jasmine'); INSERT INTO names (name) VALUES ('Jose'); INSERT INTO names (name) VALUES ('Sydney'); INSERT INTO names (name) VALUES ('Elijah'); INSERT INTO names (name) VALUES ('Julia'); INSERT INTO names (name) VALUES ('Angel'); INSERT INTO names (name) VALUES ('Destiny'); INSERT INTO names (name) VALUES ('Kevin'); INSERT INTO names (name) VALUES ('Morgan'); INSERT INTO names (name) VALUES ('Jack'); INSERT INTO names (name) VALUES ('Kaitlyn'); INSERT INTO names (name) VALUES ('Caleb'); INSERT INTO names (name) VALUES ('Savannah'); INSERT INTO names (name) VALUES ('Justin'); INSERT INTO names (name) VALUES ('Katherine'); INSERT INTO names (name) VALUES ('Robert'); INSERT INTO names (name) VALUES ('Alexandra'); INSERT INTO names (name) VALUES ('Austin'); INSERT INTO names (name) VALUES ('Rachel'); INSERT INTO names (name) VALUES ('Evan'); INSERT INTO names (name) VALUES ('Lily'); INSERT INTO names (name) VALUES ('Thomas'); INSERT INTO names (name) VALUES ('Kaylee'); INSERT INTO names (name) VALUES ('Luke'); INSERT INTO names (name) VALUES ('Megan'); INSERT INTO names (name) VALUES ('Mason'); INSERT INTO names (name) VALUES ('Jennifer'); INSERT INTO names (name) VALUES ('Aidan'); INSERT INTO names (name) VALUES ('Angelina'); INSERT INTO names (name) VALUES ('Jackson'); INSERT INTO names (name) VALUES ('Makayla'); INSERT INTO names (name) VALUES ('Isaiah'); INSERT INTO names (name) VALUES ('Allison'); INSERT INTO names (name) VALUES ('Jordan'); INSERT INTO names (name) VALUES ('Maria'); INSERT INTO names (name) VALUES ('Gavin'); INSERT INTO names (name) VALUES ('Brooke'); INSERT INTO names (name) VALUES ('Connor'); INSERT INTO names (name) VALUES ('Trinity'); INSERT INTO names (name) VALUES ('Isaac'); INSERT INTO names (name) VALUES ('Faith'); INSERT INTO names (name) VALUES ('Aiden'); INSERT INTO names (name) VALUES ('Lillian'); INSERT INTO names (name) VALUES ('Jason'); INSERT INTO names (name) VALUES ('Mackenzie'); INSERT INTO names (name) VALUES ('Cameron'); INSERT INTO names (name) VALUES ('Sofia'); INSERT INTO names (name) VALUES ('Hunter'); INSERT INTO names (name) VALUES ('Riley'); INSERT INTO names (name) VALUES ('Jayden'); INSERT INTO names (name) VALUES ('Haley'); INSERT INTO names (name) VALUES ('Juan'); INSERT INTO names (name) VALUES ('Gabrielle'); INSERT INTO names (name) VALUES ('Charles'); INSERT INTO names (name) VALUES ('Nicole'); INSERT INTO names (name) VALUES ('Aaron'); INSERT INTO names (name) VALUES ('Kylie'); INSERT INTO names (name) VALUES ('Lucas'); INSERT INTO names (name) VALUES ('Zoe'); INSERT INTO names (name) VALUES ('Luis'); INSERT INTO names (name) VALUES ('Katelyn'); INSERT INTO names (name) VALUES ('Owen'); INSERT INTO names (name) VALUES ('Paige'); INSERT INTO names (name) VALUES ('Landon'); INSERT INTO names (name) VALUES ('Gabriella'); INSERT INTO names (name) VALUES ('Diego'); INSERT INTO names (name) VALUES ('Jenna'); INSERT INTO names (name) VALUES ('Brian'); INSERT INTO names (name) VALUES ('Kimberly'); INSERT INTO names (name) VALUES ('Adam'); INSERT INTO names (name) VALUES ('Stephanie'); INSERT INTO names (name) VALUES ('Adrian'); INSERT INTO names (name) VALUES ('Andrea'); INSERT INTO names (name) VALUES ('Eric'); INSERT INTO names (name) VALUES ('Alexa'); INSERT INTO names (name) VALUES ('Kyle'); INSERT INTO names (name) VALUES ('Avery'); INSERT INTO names (name) VALUES ('Ian'); INSERT INTO names (name) VALUES ('Leah'); INSERT INTO names (name) VALUES ('Nathaniel'); INSERT INTO names (name) VALUES ('Nevaeh'); INSERT INTO names (name) VALUES ('Carlos'); INSERT INTO names (name) VALUES ('Madeline'); INSERT INTO names (name) VALUES ('Alex'); INSERT INTO names (name) VALUES ('Evelyn'); INSERT INTO names (name) VALUES ('Bryan'); INSERT INTO names (name) VALUES ('Mary'); INSERT INTO names (name) VALUES ('Jesus'); INSERT INTO names (name) VALUES ('Maya'); INSERT INTO names (name) VALUES ('Julian'); INSERT INTO names (name) VALUES ('Michelle'); INSERT INTO names (name) VALUES ('Sean'); INSERT INTO names (name) VALUES ('Sara'); INSERT INTO names (name) VALUES ('Hayden'); INSERT INTO names (name) VALUES ('Jada'); INSERT INTO names (name) VALUES ('Carter'); INSERT INTO names (name) VALUES ('Audrey'); INSERT INTO names (name) VALUES ('Jeremiah'); INSERT INTO names (name) VALUES ('Brooklyn'); INSERT INTO names (name) VALUES ('Cole'); INSERT INTO names (name) VALUES ('Vanessa'); INSERT INTO names (name) VALUES ('Brayden'); INSERT INTO names (name) VALUES ('Amanda'); INSERT INTO names (name) VALUES ('Wyatt'); INSERT INTO names (name) VALUES ('Rebecca'); INSERT INTO names (name) VALUES ('Chase'); INSERT INTO names (name) VALUES ('Caroline'); INSERT INTO names (name) VALUES ('Steven'); INSERT INTO names (name) VALUES ('Ariana'); INSERT INTO names (name) VALUES ('Timothy'); INSERT INTO names (name) VALUES ('Amelia'); INSERT INTO names (name) VALUES ('Dominic'); INSERT INTO names (name) VALUES ('Mariah'); INSERT INTO names (name) VALUES ('Sebastian'); INSERT INTO names (name) VALUES ('Jordan'); INSERT INTO names (name) VALUES ('Xavier'); INSERT INTO names (name) VALUES ('Jocelyn'); INSERT INTO names (name) VALUES ('Jaden'); INSERT INTO names (name) VALUES ('Arianna'); INSERT INTO names (name) VALUES ('Jesse'); INSERT INTO names (name) VALUES ('Isabel'); INSERT INTO names (name) VALUES ('Seth'); INSERT INTO names (name) VALUES ('Marissa'); INSERT INTO names (name) VALUES ('Devin'); INSERT INTO names (name) VALUES ('Autumn'); INSERT INTO names (name) VALUES ('Antonio'); INSERT INTO names (name) VALUES ('Melanie'); INSERT INTO names (name) VALUES ('Miguel'); INSERT INTO names (name) VALUES ('Aaliyah'); INSERT INTO names (name) VALUES ('Richard'); INSERT INTO names (name) VALUES ('Gracie'); INSERT INTO names (name) VALUES ('Colin'); INSERT INTO names (name) VALUES ('Claire'); INSERT INTO names (name) VALUES ('Cody'); INSERT INTO names (name) VALUES ('Isabelle'); INSERT INTO names (name) VALUES ('Alejandro'); INSERT INTO names (name) VALUES ('Molly'); INSERT INTO names (name) VALUES ('Caden'); INSERT INTO names (name) VALUES ('Mya'); INSERT INTO names (name) VALUES ('Blake'); INSERT INTO names (name) VALUES ('Diana'); INSERT INTO names (name) VALUES ('Kaden'); INSERT INTO names (name) VALUES ('Katie'); CREATE TABLE annames AS SELECT id, name FROM names WHERE name like 'An%'; -- We'll use these prepared statements. PREPARE anames AS SELECT id, name FROM names WHERE name like 'An%'; PREPARE expect AS VALUES (11, 'Andrew'), ( 44, 'Anna'), (15, 'Anthony'), (183, 'Antonio'), (86, 'Angelina'), (130, 'Andrea'), (63, 'Angel'); /****************************************************************************/ -- First, test _temptable. PREPARE "something cool" AS VALUES (1, 2), (3, 4); SELECT is( _temptable( '"something cool"', '__spacenames__' ), '__spacenames__', 'Should create a temp table for a prepared statement with space and values' ); SELECT has_table('__spacenames__' ); SELECT is( _temptable('VALUES (1, 2), (3, 5)', '__somevals__'), '__somevals__', 'Should create a temp table for a values statement' ); SELECT has_table('__somevals__'); /****************************************************************************/ -- Now test set_eq(). SELECT * FROM check_test( set_eq( 'anames', 'expect', 'whatever' ), true, 'set_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( set_eq( 'anames', 'expect' ), true, 'set_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( set_eq( 'EXECUTE anames', 'EXECUTE expect' ), true, 'set_eq(execute, execute, desc)', '', '' ); -- Make sure that dupes are disregarded. SELECT * FROM check_test( set_eq( 'VALUES (1, ''Anna'')', 'VALUES (1, ''Anna''), (1, ''Anna'')' ), true, 'set_eq(values, dupe values)', '', '' ); -- Try some failures. SELECT * FROM check_test( set_eq( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'set_eq(select, prepared) fail missing', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( set_eq( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'set_eq(select, prepared) fail missings', '', E' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_eq( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_eq(values, values) fail mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_eq( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_eq(values, values) fail column count', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test bag_eq(). SELECT * FROM check_test( bag_eq( 'anames', 'expect', 'whatever' ), true, 'bag_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_eq( 'anames', 'expect' ), true, 'bag_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( bag_eq( 'EXECUTE anames', 'EXECUTE expect' ), true, 'bag_eq(execute, execute)', '', '' ); -- Compare with dupes. SELECT * FROM check_test( bag_eq( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (1, ''Anna''), (86, ''Angelina'')' ), true, 'bag_eq(dupe values, dupe values)', '', '' ); -- And now some failures. SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'bag_eq(select, prepared) fail missing', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_eq( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'bag_eq(select, prepared) fail missings', '', E' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_eq( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_eq(values, values) fail mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_eq( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_eq(values, values) fail column count', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Handle failure due to missing dupe. SELECT * FROM check_test( bag_eq( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), false, 'bag_eq(values, values) fail missing dupe', '', ' Extra records: (1,Anna)' ); /****************************************************************************/ -- Now test set_eq(). SELECT * FROM check_test( set_ne( 'anames', 'expect' ), false, 'set_ne(prepared, prepared) fail', '', '' ); -- Handle fail with column mismatch. SELECT * FROM check_test( set_ne( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_ne( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_ne fail with different col counts', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Handle fail with a dupe. SELECT * FROM check_test( set_ne( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), false, 'set_ne fail with dupe', '', '' ); /****************************************************************************/ -- Now test bag_ne(). SELECT * FROM check_test( bag_ne( 'anames', 'expect' ), false, 'bag_ne(prepared, prepared) fail', '', '' ); SELECT * FROM check_test( bag_ne( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle pass with a dupe. SELECT * FROM check_test( bag_ne( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), true, 'set_ne pass with dupe', '', '' ); -- Handle fail with column mismatch. SELECT * FROM check_test( bag_ne( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_ne fail with column mismatch', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_ne( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_ne fail with different col counts', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test results_eq(). PREPARE anames_ord AS SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; PREPARE expect_ord AS VALUES (11, 'Andrew'), (15, 'Anthony'), ( 44, 'Anna'), (63, 'Angel'), (86, 'Angelina'), (130, 'Andrea'), (183, 'Antonio'); SELECT * FROM check_test( results_eq( 'anames_ord', 'expect_ord', 'whatever' ), true, 'results_eq(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( results_eq( 'anames_ord', 'expect_ord' ), true, 'results_eq(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( results_eq( 'EXECUTE anames_ord', 'EXECUTE expect_ord' ), true, 'results_eq(execute, execute)', '', '' ); -- Compare with dupes. SELECT * FROM check_test( results_eq( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')' ), true, 'results_eq(dupe values, dupe values)', '', '' ); -- Compare with nulls. SELECT * FROM check_test( results_eq( 'VALUES (4, NULL), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (4, NULL), (86, ''Angelina''), (1, ''Anna'')' ), true, 'results_eq(values with null, values with null)', '', '' ); -- Compare only NULLs SELECT * FROM check_test( results_eq( 'VALUES (NULL, NULL), (NULL, NULL)', 'VALUES (NULL, NULL), (NULL, NULL)' ), true, 'results_eq(nulls, nulls)', '', '' ); -- Compare only NULLs SELECT * FROM check_test( results_eq( 'VALUES (NULL, NULL), (NULL, NULL)', 'VALUES (NULL, NULL)' ), false, 'results_eq(nulls, nulls) fail', '', ' Results differ beginning at row 2: have: (,) want: NULL' ); -- Now when the last row is missing. SELECT * FROM check_test( results_eq( 'SELECT id, name FROM annames WHERE name <> ''Antonio''', 'anames_ord' ), false, 'results_eq(select, prepared) fail missing last row', '', ' Results differ beginning at row 7: have: NULL want: (183,Antonio)' ); -- Invert that. SELECT * FROM check_test( results_eq( 'anames_ord', 'SELECT id, name FROM annames WHERE name <> ''Antonio''' ), false, 'results_eq(prepared, select) fail missing first row', '', ' Results differ beginning at row 7: have: (183,Antonio) want: NULL' ); -- Compare with missing dupe. SELECT * FROM check_test( results_eq( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), false, 'results_eq(values dupe, values)', '', ' Results differ beginning at row 3: have: (1,Anna) want: NULL' ); -- Handle failure with null. SELECT * FROM check_test( results_eq( 'VALUES (1, NULL), (86, ''Angelina'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), false, 'results_eq(values null, values)', '', ' Results differ beginning at row 1: have: (1,) want: (1,Anna)' ); -- Handle failure due to column mismatch. SELECT * FROM check_test( results_eq( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'results_eq(values, values) mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: cannot compare dissimilar column types integer and text at record column 1' ELSE ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to more subtle column mismatch SELECT * FROM check_test( results_eq( 'VALUES (1, ''foo''::varchar), (2, ''bar''::varchar)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_eq(values, values) subtle mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries ERROR: cannot compare dissimilar column types character varying and text at record column 2' ELSE ' Number of columns or their types differ between the queries ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( results_eq( 'VALUES (1), (2)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_eq(values, values) fail column count', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: cannot compare record types with different numbers of columns' ELSE ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: details not available in pg <= 9.1' END ); -- Compare with cursors. DECLARE cwant CURSOR FOR SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; DECLARE chave CURSOR FOR SELECT id, name from annames ORDER BY id; -- Mix cursors and prepared statements PREPARE annames_ord AS VALUES (11, 'Andrew'), (15, 'Anthony'), ( 44, 'Anna'), (63, 'Angel'), (86, 'Angelina'), (130, 'Andrea'), (183, 'Antonio'); MOVE BACKWARD ALL IN cwant; SELECT * FROM check_test( results_eq( 'cwant'::refcursor, 'annames_ord' ), true, 'results_eq(cursor, prepared)', '', '' ); SELECT * FROM check_test( results_eq( 'annames_ord', 'chave'::refcursor ), true, 'results_eq(prepared, cursor)', '', '' ); /****************************************************************************/ -- Now test set_has(). SELECT * FROM check_test( set_has( 'anames', 'expect', 'whatever' ), true, 'set_has( prepared, prepared, description )', 'whatever', '' ); PREPARE subset AS VALUES (11, 'Andrew'), ( 44, 'Anna'), (63, 'Angel'); SELECT * FROM check_test( set_has( 'anames', 'subset' ), true, 'set_has( prepared, subprepared )', '', '' ); SELECT * FROM check_test( set_has( 'EXECUTE anames', 'EXECUTE subset' ), true, 'set_has( execute, execute )', '', '' ); -- Make sure that dupes are ignored. SELECT * FROM check_test( set_has( 'anames', 'VALUES (44, ''Anna''), (44, ''Anna'')' ), true, 'set_has( prepared, dupes )', '', '' ); SELECT * FROM check_test( set_has( 'VALUES (44, ''Anna''), (44, ''Anna'')', 'VALUES(44, ''Anna'')' ), true, 'set_has( dupes, values )', '', '' ); -- Check failures. SELECT * FROM check_test( set_has( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'set_has( missing1, expect )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( set_has( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'set_has(missing2, expect )', '', E' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_has( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_has((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_has( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_has((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test bag_has(). SELECT * FROM check_test( bag_has( 'anames', 'expect', 'whatever' ), true, 'bag_has( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( bag_has( 'anames', 'subset' ), true, 'bag_has( prepared, subprepared )', '', '' ); SELECT * FROM check_test( bag_has( 'EXECUTE anames', 'EXECUTE subset' ), true, 'bag_has( execute, execute )', '', '' ); -- Make sure that dupes are not ignored. SELECT * FROM check_test( bag_has( 'anames', 'VALUES (44, ''Anna''), (44, ''Anna'')' ), false, 'bag_has( prepared, dupes )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_has( 'VALUES (44, ''Anna''), (44, ''Anna'')', 'VALUES(44, ''Anna'')' ), true, 'bag_has( dupes, values )', '', '' ); SELECT * FROM check_test( bag_has( 'SELECT id, name FROM annames WHERE name <> ''Anna''', 'expect' ), false, 'bag_has( missing1, expect )', '', ' Missing records: (44,Anna)' ); SELECT * FROM check_test( bag_has( 'SELECT id, name FROM annames WHERE name NOT IN (''Anna'', ''Angelina'')', 'expect' ), false, 'bag_has(missing2, expect )', '', E' Missing records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_has( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_has((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_has( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_has((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test set_hasnt(). PREPARE others AS VALUES ( 44, 'Larry' ), (52, 'Tom'), (23, 'Damian' ); SELECT * FROM check_test( set_hasnt( 'anames', 'others', 'whatever' ), true, 'set_hasnt( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( set_hasnt( 'anames', 'others' ), true, 'set_hasnt( prepared, prepared, description )', '', '' ); SELECT * FROM check_test( set_hasnt( 'EXECUTE anames', 'EXECUTE others' ), true, 'set_hasnt( execute, execute )', '', '' ); -- Make sure that dupes are ignored. SELECT * FROM check_test( set_hasnt( 'anames', 'VALUES (44, ''Bob''), (44, ''Bob'')' ), true, 'set_hasnt( prepared, dupes )', '', '' ); SELECT * FROM check_test( set_hasnt( 'anames', 'VALUES (44,''Anna'')' ), false, 'set_hasnt( prepared, value )', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( set_hasnt( 'anames', 'VALUES (44, ''Anna''), (86, ''Angelina'')' ), false, 'set_hasnt( prepared, values )', '', E' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( set_hasnt( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_hasnt((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( set_hasnt( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'set_hasnt((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); /****************************************************************************/ -- Now test bag_hasnt(). SELECT * FROM check_test( bag_hasnt( 'anames', 'others', 'whatever' ), true, 'bag_hasnt( prepared, prepared, description )', 'whatever', '' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'others' ), true, 'bag_hasnt( prepared, prepared, description )', '', '' ); SELECT * FROM check_test( bag_hasnt( 'EXECUTE anames', 'EXECUTE others' ), true, 'bag_hasnt( execute, execute )', '', '' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'VALUES (44,''Anna'')' ), false, 'bag_hasnt( prepared, value )', '', ' Extra records: (44,Anna)' ); SELECT * FROM check_test( bag_hasnt( 'anames', 'VALUES (44, ''Anna''), (86, ''Angelina'')' ), false, 'bag_hasnt( prepared, values )', '', E' Extra records: [(](44,Anna|86,Angelina)[)] [(](44,Anna|86,Angelina)[)]', true ); -- Handle failure due to column mismatch. SELECT * FROM check_test( bag_hasnt( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_hasnt((int,text), (text,int))', '', ' Columns differ between queries: have: (integer,text) want: (text,integer)' ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( bag_hasnt( 'VALUES (1), (2)', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'bag_hasnt((int), (text,int))', '', ' Columns differ between queries: have: (integer) want: (text,integer)' ); -- Make sure that dupes are not ignored. SELECT * FROM check_test( bag_hasnt( 'VALUES (44, ''Anna''), (44, ''Anna'')', 'VALUES (44, ''Anna''), (44, ''Anna'')' ), false, 'bag_hasnt( dupes, dupes )', '', ' Extra records: (44,Anna) (44,Anna)' ); -- But a dupe that appears only once should be in the list only once. SELECT * FROM check_test( bag_hasnt( 'VALUES (44, ''Anna'')', 'VALUES (44, ''Anna''), (44, ''Anna'')' ), false, 'bag_hasnt( value, dupes )', '', ' Extra records: (44,Anna)' ); /****************************************************************************/ -- Test set_eq() with an array argument. PREPARE justnames AS VALUES ('Andrew'), ('Antonio'), ('Angelina'), ('Anna'), ('Anthony'), ('Andrea'), ('Angel'); SELECT * FROM check_test( set_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ], 'whatever' ), true, 'set_eq(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( set_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), true, 'set_eq(prepared, array)', '', '' ); SELECT * FROM check_test( set_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Andrew', 'Anna' ] ), true, 'set_eq(prepared, dupe array)', '', '' ); -- Fail with an extra record. SELECT * FROM check_test( set_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_eq(prepared, array) extra record', '', ' Extra records: (Anthony)' ); -- Fail with a missing record. SELECT * FROM check_test( set_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Alan', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_eq(prepared, array) missing record', '', ' Missing records: (Alan)' ); -- Fail with incompatible columns. SELECT * FROM check_test( set_eq( 'justnames', ARRAY[1, 2, 3] ), false, 'set_eq(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); /****************************************************************************/ -- Test bag_eq() with an array argument. SELECT * FROM check_test( bag_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ], 'whatever' ), true, 'bag_eq(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), true, 'bag_eq(prepared, array)', '', '' ); SELECT * FROM check_test( bag_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), false, 'bag_eq(prepared, dupe array) fail', '', ' Missing records: (Anna)' ); -- Fail with an extra record. SELECT * FROM check_test( bag_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_eq(prepared, array) extra record', '', ' Extra records: (Anthony)' ); -- Fail with a missing record. SELECT * FROM check_test( bag_eq( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Alan', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_eq(prepared, array) missing record', '', ' Missing records: (Alan)' ); -- Fail with incompatible columns. SELECT * FROM check_test( bag_eq( 'justnames', ARRAY[1, 2, 3] ), false, 'bag_eq(prepared, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); /****************************************************************************/ -- Test set_ne() with an array argument. SELECT * FROM check_test( set_ne( 'justnames', ARRAY['Andrew', 'Anna' ], 'whatever' ), true, 'set_ne(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( set_ne( 'justnames', ARRAY['Andrew', 'Anna' ] ), true, 'set_ne(prepared, array)', '', '' ); SELECT * FROM check_test( set_ne( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'set_ne(prepared, array) fail', '', '' ); -- Fail with dupes. SELECT * FROM check_test( set_ne( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), false, 'set_ne(prepared, dupes array) fail', '', '' ); -- Fail with incompatible columns. SELECT * FROM check_test( set_ne( 'justnames', ARRAY[1, 2, 3] ), false, 'set_ne(sql, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); /****************************************************************************/ -- Test bag_ne() with an array argument. SELECT * FROM check_test( bag_ne( 'justnames', ARRAY['Andrew', 'Anna' ], 'whatever' ), true, 'bag_ne(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( bag_ne( 'justnames', ARRAY['Andrew', 'Anna' ] ), true, 'bag_ne(prepared, array)', '', '' ); SELECT * FROM check_test( bag_ne( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel' ] ), false, 'bag_ne(prepared, array) fail', '', '' ); -- Pass with dupes. SELECT * FROM check_test( bag_ne( 'justnames', ARRAY['Andrew', 'Anna', 'Anthony', 'Antonio', 'Angelina', 'Andrea', 'Angel', 'Anna' ] ), true, 'bag_ne(prepared, dupes array)', '', '' ); -- Fail with incompatible columns. SELECT * FROM check_test( bag_ne( 'justnames', ARRAY[1, 2, 3] ), false, 'bag_ne(prepared, array) incompatible types', '', ' Columns differ between queries: have: (text) want: (integer)' ); /****************************************************************************/ -- Now test results_eq() with an array argument. PREPARE ordnames AS VALUES ('Andrea'), ('Andrew'), ('Angel'), ('Angelina'), ('Anna'), ('Anthony'), ('Antonio'); SELECT * FROM check_test( results_eq( 'ordnames', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ], 'whatever' ), true, 'results_eq(prepared, array, desc)', 'whatever', '' ); SELECT * FROM check_test( results_eq( 'ordnames', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony', 'Antonio' ] ), true, 'results_eq(prepared, array)', '', '' ); SELECT * FROM check_test( results_eq( 'ordnames', ARRAY['Andrea', 'Andrew', 'Angel', 'Angelina', 'Anna', 'Anthony' ] ), false, 'results_eq(prepared, array) extra record', '', ' Results differ beginning at row 7: have: (Antonio) want: NULL' ); /****************************************************************************/ -- Now test results_eq(). PREPARE nenames_ord AS SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; PREPARE nexpect_ord AS VALUES (15, 'Anthony'), ( 44, 'Anna'), (11, 'Andrew'), (63, 'Angel'), (86, 'Angelina'), (130, 'Andrea'), (183, 'Antonio'); SELECT * FROM check_test( results_ne( 'nenames_ord', 'nexpect_ord', 'whatever' ), true, 'results_ne(prepared, prepared, desc)', 'whatever', '' ); SELECT * FROM check_test( results_ne( 'nenames_ord', 'nexpect_ord' ), true, 'results_ne(prepared, prepared)', '', '' ); -- Pass a full SQL statement for the prepared statements. SELECT * FROM check_test( results_ne( 'EXECUTE nenames_ord', 'EXECUTE nexpect_ord' ), true, 'results_ne(execute, execute)', '', '' ); -- Compare with dupes. SELECT * FROM check_test( results_ne( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (2, ''Anna''), (86, ''Angelina''), (2, ''Anna'')' ), true, 'results_ne(dupe values, dupe values)', '', '' ); -- Compare with nulls. SELECT * FROM check_test( results_ne( 'VALUES (4, NULL), (86, ''Angelina''), (1, NULL)', 'VALUES (4, NULL), (86, ''Angelina''), (1, ''Anna'')' ), true, 'results_ne(values with null, values with null)', '', '' ); -- Compare only NULLs SELECT * FROM check_test( results_ne( 'VALUES (NULL, NULL), (NULL, NULL), (NULL, NULL)', 'VALUES (NULL, NULL), (NULL, NULL)' ), true, 'results_ne(nulls, nulls)', '', '' ); -- Compare with missing dupe. SELECT * FROM check_test( results_ne( 'VALUES (1, ''Anna''), (86, ''Angelina''), (1, ''Anna'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), true, 'results_ne(values dupe, values)', '', '' ); -- Handle pass with null. SELECT * FROM check_test( results_ne( 'VALUES (1, NULL), (86, ''Angelina'')', 'VALUES (1, ''Anna''), (86, ''Angelina'')' ), true, 'results_ne(values null, values)', '', '' ); -- Handle failure due to column mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1, ''foo''), (2, ''bar'')', 'VALUES (''foo'', 1), (''bar'', 2)' ), false, 'results_ne(values, values) mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: cannot compare dissimilar column types integer and text at record column 1' ELSE ' Number of columns or their types differ between the queries: have: (1,foo) want: (foo,1) ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to subtle column mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1, ''foo''::varchar), (2, ''bar''::varchar)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_ne(values, values) subtle mismatch', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries ERROR: cannot compare dissimilar column types character varying and text at record column 2' ELSE ' Number of columns or their types differ between the queries ERROR: details not available in pg <= 9.1' END ); -- Handle failure due to column count mismatch. SELECT * FROM check_test( results_ne( 'VALUES (1), (2)', 'VALUES (1, ''foo''), (2, ''bar'')' ), false, 'results_ne(values, values) fail column count', '', CASE WHEN pg_version_num() >= 90200 THEN ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: cannot compare record types with different numbers of columns' ELSE ' Number of columns or their types differ between the queries: have: (1) want: (1,foo) ERROR: details not available in pg <= 9.1' END ); -- Compare with cursors. CLOSE cwant; CLOSE chave; DECLARE cwant CURSOR FOR SELECT id, name FROM names WHERE name like 'An%' ORDER BY id; DECLARE chave CURSOR FOR SELECT id, name from annames ORDER BY id; -- Mix cursors and prepared statements MOVE BACKWARD ALL IN cwant; SELECT * FROM check_test( results_ne( 'cwant'::refcursor, 'annames_ord' ), false, 'results_ne(cursor, prepared)', '', '' ); MOVE BACKWARD ALL IN chave; SELECT * FROM check_test( results_ne( 'annames_ord', 'chave'::refcursor ), false, 'results_ne(prepared, cursor)', '', '' ); /****************************************************************************/ -- Finish the tests and clean up. SELECT * FROM finish(); ROLLBACK; pgtap-1.3.2/test/test_MVU.sh000077500000000000000000000254211455775703000156750ustar00rootroot00000000000000#!/usr/bin/env bash # Test performing a Major Version Upgrade via pg_upgrade. # # MVU can be problematic due to catalog changes. For example, if the extension # contains a view that references a catalog column that no longer exists, # pg_upgrade itself will break. set -E -e -u -o pipefail BASEDIR=`dirname $0` if ! . $BASEDIR/../tools/util.sh; then echo "FATAL: error sourcing $BASEDIR/../tools/util.sh" 1>&2 exit 99 fi trap err_report ERR debug 19 "Arguments: $@" rc=0 byte_len() ( [ $# -eq 1 ] || die 99 "Expected 1 argument, not $# ($@)" LANG=C LC_ALL=C debug 99 "byte_len($@) = ${#1}" echo ${#1} ) check_bin() { for f in pg_ctl psql initdb; do [ -x "$1/$f" ] || die 1 "$1/$f does not exist or is not executable" done } # mktemp on OS X results is a super-long path name that can cause problems, ie: # connection to database failed: Unix-domain socket path "/private/var/folders/rp/mv0457r17cg0xqyw5j7701892tlc0h/T/test_pgtap_upgrade.upgrade.7W4BLF/.s.PGSQL.50432" is too long (maximum 103 bytes) # # This function looks for that condition and replaces the output with something more legible short_tmpdir() ( [ $# -eq 1 ] || die 99 "Expected 1 argument, not $# ($@)" [ "$TMPDIR" != "" ] || die 99 '$TMPDIR not set' out=$(mktemp -p '' -d $1.XXXXXX) if echo "$out" | egrep -q '^(/private)?/var/folders'; then newout=$(echo "$out" | sed -e "s#.*/$TMPDIR#$TMPDIR#") debug 19 "replacing '$out' with '$newout'" fi debug 9 "$0($@) = $out" # Postgres blows up if this is too long. Technically the limit is 103 bytes, # but need to account for the socket name, plus the fact that OS X might # prepend '/private' to what we return. :( [ $(byte_len "$out") -lt 75 ] || die 9 "short_tmpdir($@) returning a value >= 75 bytes ('$out')" echo "$out" ) banner() { echo echo '###################################' echo "$@" echo '###################################' echo } modify_config() ( # See below for definition of ctl_separator if [ -z "$ctl_separator" ]; then confDir=$PGDATA conf=$confDir/postgresql.conf debug 6 "$0: conf = $conf" debug 0 "Modifying NATIVE $conf" echo "port = $PGPORT" >> $conf else confDir="/etc/postgresql/$1/$cluster_name" conf="$confDir/postgresql.conf" debug 6 "$0: confDir = $confDir conf=$conf" debug_ls 9 -la $confDir debug 0 "Modifying DEBIAN $confDir and $PGDATA" debug 2 ln -s $conf $PGDATA/ ln -s $conf $PGDATA/ # Some versions also have a conf.d ... if [ -e "$confDir/conf.d" ]; then debug 2 ln -s $confDir/conf.d $PGDATA/ ln -s $confDir/conf.d $PGDATA/ fi debug_ls 8 -la $PGDATA # Shouldn't need to muck with PGPORT... # GUC changed somewhere between 9.1 and 9.5, so read config to figure out correct value guc=$(grep unix_socket_director $conf | sed -e 's/^# *//' | cut -d ' ' -f 1) debug 4 "$0: guc = $guc" echo "$guc = '/tmp'" >> $conf fi echo "synchronous_commit = off" >> $conf ) ############################# # Argument processing keep='' if [ "$1" == "-k" ]; then debug 1 keeping results after exit keep=1 shift fi sudo='' if [ "$1" == '-s' ]; then # Useful error if we can't find sudo command -v sudo > /dev/null || echo "sudo not found" sudo=$(command -v sudo) debug 2 "sudo located at $sudo" shift fi OLD_PORT=$1 NEW_PORT=$2 OLD_VERSION=$3 NEW_VERSION=$4 OLD_PATH="${5:-/usr/lib/postgresql/$OLD_VERSION/bin}" NEW_PATH="${5:-/usr/lib/postgresql/$NEW_VERSION/bin}" export PGDATABASE=test_pgtap_upgrade check_bin "$OLD_PATH" check_bin "$NEW_PATH" export TMPDIR=${TMPDIR:-${TEMP:-${TMP:-/tmp}}} debug 9 "\$TMPDIR=$TMPDIR" [ $(byte_len "$TMPDIR") -lt 50 ] || die 9 "\$TMPDIR ('$TMPDIR') is too long; please set it" '(or $TEMP, or $TMP) to a value less than 50 bytes' upgrade_dir=$(short_tmpdir test_pgtap_upgrade.upgrade) old_dir=$(short_tmpdir test_pgtap_upgrade.old) new_dir=$(short_tmpdir test_pgtap_upgrade.new) # Note: if this trap fires and removes the old directories with databases still # running we'll get a bunch of spew on STDERR. It'd be nice to have a trap that # knew what databases might actually be running. exit_trap() { # No point in stopping on error in here... set +e # Force sudo on a debian system (see below) [ -z "$ctl_separator" ] || sudo=$(command -v sudo) # Attempt to shut down any running clusters, otherwise we'll get log spew # when the temporary directories vanish. $old_pg_ctl stop > /dev/null 2>&1 $new_pg_ctl stop > /dev/null 2>&1 # Do not simply stick this command in the trap command; the quoting gets # tricky, but the quoting is also damn critical to make sure rm -rf doesn't # hose you if the temporary directory names have spaces in them! $sudo rm -rf "$upgrade_dir" "$old_dir" "$new_dir" } [ -n "$keep" ] || trap exit_trap EXIT debug 5 "traps: $(trap -p)" cluster_name=test_pg_upgrade if command -v pg_ctlcluster > /dev/null; then # Looks like we're running in a apt / Debian / Ubuntu environment, so use their tooling ctl_separator='--' # Force socket path to normal for pg_upgrade export PGHOST=/tmp # And force current user export PGUSER=${USER:-$(whoami)} old_initdb="$sudo pg_createcluster $OLD_VERSION $cluster_name -u $PGUSER -p $OLD_PORT -d $old_dir -- -A trust" old_pg_ctl="$sudo pg_ctlcluster $OLD_VERSION test_pg_upgrade" new_initdb="$sudo pg_createcluster $NEW_VERSION $cluster_name -u $PGUSER -p $NEW_PORT -d $new_dir -- -A trust" new_pg_ctl="$sudo pg_ctlcluster $NEW_VERSION test_pg_upgrade" # See also ../.github/workflows/test.yml new_pg_upgrade="/usr/lib/postgresql/$NEW_VERSION/bin/pg_upgrade" else ctl_separator='' old_initdb="$(find_at_path "$OLD_PATH" initdb) -D $old_dir -N" old_pg_ctl=$(find_at_path "$OLD_PATH" pg_ctl) new_initdb="$(find_at_path "$NEW_PATH" initdb) -D $new_dir -N" new_pg_ctl=$(find_at_path "$NEW_PATH" pg_ctl) new_pg_upgrade=$(find_at_path "$NEW_PATH" pg_upgrade) fi ################################################################################################## banner "Creating old version temporary installation at $old_dir on port $OLD_PORT (in the background)" echo "Creating new version temporary installation at $new_dir on port $NEW_PORT (in the background)" $old_initdb & $new_initdb & echo Waiting... wait ################################################################################################## banner "Starting OLD $OLD_VERSION postgres via $old_pg_ctl" export PGDATA=$old_dir export PGPORT=$OLD_PORT modify_config $OLD_VERSION $old_pg_ctl start $ctl_separator -w # older versions don't support --wait echo "Creating database" createdb # Note this uses PGPORT, so no need to wrap. echo "Installing pgtap" # If user requested sudo then we need to use it for the install step. TODO: # it'd be nice to move this into the Makefile, if the PGXS make stuff allows # it... $sudo make clean install banner "Loading extension" psql -c 'CREATE EXTENSION pgtap' # Also uses PGPORT echo "Stopping OLD postgres via $old_pg_ctl" $old_pg_ctl stop $ctl_separator -w # older versions don't support --wait ################################################################################################## banner "Running pg_upgrade" export PGDATA=$new_dir export PGPORT=$NEW_PORT modify_config $NEW_VERSION ( cd $upgrade_dir if [ $DEBUG -ge 9 ]; then echo $old_dir; ls -la $old_dir; egrep 'director|unix|conf' $old_dir/postgresql.conf echo $new_dir; ls -la $new_dir; egrep 'director|unix|conf' $new_dir/postgresql.conf fi echo $new_pg_upgrade -d "$old_dir" -D "$new_dir" -b "$OLD_PATH" -B "$NEW_PATH" $new_pg_upgrade -d "$old_dir" -D "$new_dir" -b "$OLD_PATH" -B "$NEW_PATH" || rc=$? if [ $rc -ne 0 ]; then # Dump log, but only if we're not keeping the directory if [ -z "$keep" ]; then for f in `ls *.log`; do echo; echo; echo; echo; echo; echo echo "`pwd`/$f:" cat "$f" done ls -la else error "pg_upgrade logs are at $upgrade_dir" fi die $rc "pg_upgrade returned $rc" fi ) ################################################################################################## banner "Testing UPGRADED cluster" # Run our tests against the upgraded cluster, but first make sure the old # cluster is still down, to ensure there's no chance of testing it instead. # Note that some versions of pg_ctl return different exit codes when the server # isn't running. echo ensuring OLD cluster is stopped rc=0 status=$($old_pg_ctl status) || rc=$? [ "$status" == 'pg_ctl: no server running' ] || die 3 "$old_pg_ctl status returned '$status' and exited with $?" debug 4 "$old_pg_ctl status exited with $rc" # TODO: send log output to a file so it doesn't mix in with STDOUT echo starting NEW cluster $new_pg_ctl start $ctl_separator -w || die $? "$new_pg_ctl start $ctl_separator -w returned $?" $new_pg_ctl status # Should error if not running on most versions psql -E -c '\dx' psql -E -c 'SELECT pgtap_version(), pg_version_num(), version();' # We want to make sure to use the NEW pg_config export PG_CONFIG=$(find_at_path "$NEW_PATH" pg_config) [ -x "$PG_CONFIG" ] || ( debug_ls 1 "$NEW_PATH"; die 4 "unable to find executable pg_config at $NEW_PATH" ) # When crossing certain upgrade boundaries we need to exclude some tests # because the test functions are not available in the previous version. int_ver() { local ver ver=$(echo $1 | tr -d .) # "multiply" versions less than 7.0 by 10 so that version 10.x becomes 100, # 11 becomes 110, etc. [ $ver -ge 70 ] || ver="${ver}0" echo $ver } EXCLUDE_TEST_FILES='' add_exclude() { local old new old=$(int_ver $1) new=$(int_ver $2) shift 2 if [ $(int_ver $OLD_VERSION) -le $old -a $(int_ver $NEW_VERSION) -ge $new ]; then EXCLUDE_TEST_FILES="$EXCLUDE_TEST_FILES $@" fi } add_exclude 9.1 9.2 test/sql/resultset.sql add_exclude 9.1 9.2 test/sql/valueset.sql add_exclude 9.1 9.2 test/sql/throwtap.sql add_exclude 9.4 9.5 test/sql/policy.sql test/sql/throwtap.sql add_exclude 9.6 10 test/sql/partitions.sql # Use this if there's a single test failing .github/workflows/test.yml that you can't figure out... #(cd $(dirname $0)/..; pg_prove -v --pset tuples_only=1 test/sql/throwtap.sql) export EXCLUDE_TEST_FILES $sudo make clean make test if [ -n "$EXCLUDE_TEST_FILES" ]; then banner "Rerunning test after a reinstall due to version differences" echo "Excluded tests: $EXCLUDE_TEST_FILES" export EXCLUDED_TEST_FILES='' # Need to build with the new version, then install $sudo make install psql -E -c 'DROP EXTENSION pgtap; CREATE EXTENSION pgtap;' make test fi pgtap-1.3.2/tools/000077500000000000000000000000001455775703000140055ustar00rootroot00000000000000pgtap-1.3.2/tools/getos.sh000077500000000000000000000205071455775703000154710ustar00rootroot00000000000000#!/bin/sh uname=`command -v uname` sed=`command -v sed` tr=`command -v tr` myuname='' newmyuname='' trnl='' case "$test" in test) echo "Hopefully test is built into your sh." ;; *) if `sh -c "PATH= test true" >/dev/null 2>&1`; then # echo "Using the test built into your sh." test=test _test=test fi ;; esac : Find the appropriate value for a newline for tr if test -n "$DJGPP"; then trnl='\012' fi if test X"$trnl" = X; then case "`echo foo|tr '\n' x 2>/dev/null`" in foox) trnl='\n' ;; esac fi if test X"$trnl" = X; then case "`echo foo|tr '\012' x 2>/dev/null`" in foox) trnl='\012' ;; esac fi if test X"$trnl" = X; then case "`echo foo|tr '\r\n' xy 2>/dev/null`" in fooxy) trnl='\n\r' ;; esac fi if test X"$trnl" = X; then cat <&2 $me: Fatal Error: cannot figure out how to translate newlines with 'tr'. EOM exit 1 fi myuname=`$uname -a 2>/dev/null` $test -z "$myuname" && myuname=`hostname 2>/dev/null` # tr '[A-Z]' '[a-z]' would not work in EBCDIC # because the A-Z/a-z are not consecutive. myuname=`echo $myuname | $sed -e 's/^[^=]*=//' -e "s,['/],,g" | \ $tr '[A-Z]' '[a-z]' | $tr $trnl ' '` newmyuname="$myuname" : Half the following guesses are probably wrong... If you have better : tests or hints, please send them to perlbug@perl.org : The metaconfig authors would also appreciate a copy... $test -f /irix && osname=irix $test -f /xenix && osname=sco_xenix $test -f /dynix && osname=dynix $test -f /dnix && osname=dnix $test -f /lynx.os && osname=lynxos $test -f /unicos && osname=unicos && osvers=`$uname -r` $test -f /unicosmk && osname=unicosmk && osvers=`$uname -r` $test -f /unicosmk.ar && osname=unicosmk && osvers=`$uname -r` $test -f /bin/mips && /bin/mips && osname=mips $test -d /NextApps && set X `hostinfo | grep 'NeXT Mach.*:' | \ $sed -e 's/://' -e 's/\./_/'` && osname=next && osvers=$4 $test -d /usr/apollo/bin && osname=apollo $test -f /etc/saf/_sactab && osname=svr4 $test -d /usr/include/minix && osname=minix $test -f /system/gnu_library/bin/ar.pm && osname=vos if $test -d /MachTen -o -d /MachTen_Folder; then osname=machten if $test -x /sbin/version; then osvers=`/sbin/version | $awk '{print $2}' | $sed -e 's/[A-Za-z]$//'` elif $test -x /usr/etc/version; then osvers=`/usr/etc/version | $awk '{print $2}' | $sed -e 's/[A-Za-z]$//'` else osvers="$2.$3" fi fi $test -f /sys/posix.dll && $test -f /usr/bin/what && set X `/usr/bin/what /sys/posix.dll` && $test "$3" = UWIN && osname=uwin && osvers="$5" if $test -f $uname; then set X $myuname shift case "$5" in fps*) osname=fps ;; mips*) case "$4" in umips) osname=umips ;; *) osname=mips ;; esac;; [23]100) osname=mips ;; next*) osname=next ;; i386*) tmp=`/bin/uname -X 2>/dev/null|awk '/3\.2v[45]/{ print $(NF) }'` if $test "$tmp" != "" -a "$3" = "3.2" -a -f '/etc/systemid'; then osname='sco' osvers=$tmp elif $test -f /etc/kconfig; then osname=isc if test "$lns" = "$ln -s"; then osvers=4 elif $contains _SYSV3 /usr/include/stdio.h > /dev/null 2>&1 ; then osvers=3 elif $contains _POSIX_SOURCE /usr/include/stdio.h > /dev/null 2>&1 ; then osvers=2 fi fi tmp='' ;; pc*) if test -n "$DJGPP"; then osname=dos osvers=djgpp fi ;; esac case "$1" in aix) osname=aix tmp=`( (oslevel) 2>/dev/null || echo "not found") 2>&1` case "$tmp" in # oslevel can fail with: # oslevel: Unable to acquire lock. *not\ found) osvers="$4"."$3" ;; '<3240'|'<>3240') osvers=3.2.0 ;; '=3240'|'>3240'|'<3250'|'<>3250') osvers=3.2.4 ;; '=3250'|'>3250') osvers=3.2.5 ;; *) osvers=$tmp;; esac ;; bsd386) osname=bsd386 osvers=`$uname -r` ;; cygwin*) osname=cygwin osvers="$3" ;; *dc.osx) osname=dcosx osvers="$3" ;; dnix) osname=dnix osvers="$3" ;; domainos) osname=apollo osvers="$3" ;; dgux) osname=dgux osvers="$3" ;; dragonfly) osname=dragonfly osvers="$3" ;; dynixptx*) osname=dynixptx osvers=`echo "$4"|sed 's/^v//'` ;; freebsd) osname=freebsd osvers="$3" ;; genix) osname=genix ;; gnu) osname=gnu osvers="$3" ;; hp*) osname=hpux osvers=`echo "$3" | $sed 's,.*\.\([0-9]*\.[0-9]*\),\1,'` ;; irix*) osname=irix case "$3" in 4*) osvers=4 ;; 5*) osvers=5 ;; *) osvers="$3" ;; esac ;; linux) osname=linux case "$3" in *) osvers="$3" ;; esac ;; MiNT) osname=mint ;; netbsd*) osname=netbsd osvers="$3" ;; news-os) osvers="$3" case "$3" in 4*) osname=newsos4 ;; *) osname=newsos ;; esac ;; next*) osname=next ;; nonstop-ux) osname=nonstopux ;; openbsd) osname=openbsd osvers="$3" ;; os2) osname=os2 osvers="$4" ;; POSIX-BC | posix-bc ) osname=posix-bc osvers="$3" ;; powerux | power_ux | powermax_os | powermaxos | \ powerunix | power_unix) osname=powerux osvers="$3" ;; qnx) osname=qnx osvers="$4" ;; solaris) osname=solaris case "$3" in 5*) osvers=`echo $3 | $sed 's/^5/2/g'` ;; *) osvers="$3" ;; esac ;; sunos) osname=sunos case "$3" in 5*) osname=solaris osvers=`echo $3 | $sed 's/^5/2/g'` ;; *) osvers="$3" ;; esac ;; titanos) osname=titanos case "$3" in 1*) osvers=1 ;; 2*) osvers=2 ;; 3*) osvers=3 ;; 4*) osvers=4 ;; *) osvers="$3" ;; esac ;; ultrix) osname=ultrix osvers="$3" ;; osf1|mls+) case "$5" in alpha) osname=dec_osf osvers=`sizer -v | awk -FUNIX '{print $2}' | awk '{print $1}' | tr '[A-Z]' '[a-z]' | sed 's/^[xvt]//'` case "$osvers" in [1-9].[0-9]*) ;; *) osvers=`echo "$3" | sed 's/^[xvt]//'` ;; esac ;; hp*) osname=hp_osf1 ;; mips) osname=mips_osf1 ;; esac ;; # UnixWare 7.1.2 is known as Open UNIX 8 openunix|unixware) osname=svr5 osvers="$4" ;; uts) osname=uts osvers="$3" ;; vos) osvers="$3" ;; $2) case "$osname" in *isc*) ;; *freebsd*) ;; svr*) : svr4.x or possibly later case "svr$3" in ${osname}*) osname=svr$3 osvers=$4 ;; esac case "$osname" in svr4.0) : Check for ESIX if test -f /stand/boot ; then eval `grep '^INITPROG=[a-z/0-9]*$' /stand/boot` if test -n "$INITPROG" -a -f "$INITPROG"; then isesix=`strings -a $INITPROG|grep 'ESIX SYSTEM V/386 Release 4.0'` if test -n "$isesix"; then osname=esix4 fi fi fi ;; esac ;; *) if test -f /etc/systemid; then osname=sco set `echo $3 | $sed 's/\./ /g'` $4 if $test -f $src/hints/sco_$1_$2_$3.sh; then osvers=$1.$2.$3 elif $test -f $src/hints/sco_$1_$2.sh; then osvers=$1.$2 elif $test -f $src/hints/sco_$1.sh; then osvers=$1 fi else case "$osname" in '') : Still unknown. Probably a generic Sys V. osname="sysv" osvers="$3" ;; esac fi ;; esac ;; *) case "$osname" in '') : Still unknown. Probably a generic BSD. osname="$1" osvers="$3" ;; esac ;; esac else if test -f /vmunix -a -f $src/hints/news_os.sh; then (what /vmunix | UU/tr '[A-Z]' '[a-z]') > UU/kernel.what 2>&1 if $contains news-os UU/kernel.what >/dev/null 2>&1; then osname=news_os fi $rm -f UU/kernel.what elif test -d c:/. -o -n "$is_os2" ; then set X $myuname osname=os2 osvers="$5" fi fi case "$targetarch" in '') ;; *) hostarch=$osname osname=`echo $targetarch|sed 's,^[^-]*-,,'` osvers='' ;; esac : Now look for a hint file osname_osvers, unless one has been : specified already. case "$hintfile" in ''|' ') file=`echo "${osname}_${osvers}" | $sed -e 's%\.%_%g' -e 's%_$%%'` : Also try without trailing minor version numbers. xfile=`echo $file | $sed -e 's%_[^_]*$%%'` xxfile=`echo $xfile | $sed -e 's%_[^_]*$%%'` xxxfile=`echo $xxfile | $sed -e 's%_[^_]*$%%'` xxxxfile=`echo $xxxfile | $sed -e 's%_[^_]*$%%'` case "$file" in '') dflt=none ;; *) case "$osvers" in '') dflt=$file ;; *) if $test -f $src/hints/$file.sh ; then dflt=$file elif $test -f $src/hints/$xfile.sh ; then dflt=$xfile elif $test -f $src/hints/$xxfile.sh ; then dflt=$xxfile elif $test -f $src/hints/$xxxfile.sh ; then dflt=$xxxfile elif $test -f $src/hints/$xxxxfile.sh ; then dflt=$xxxxfile elif $test -f "$src/hints/${osname}.sh" ; then dflt="${osname}" else dflt=none fi ;; esac ;; esac if $test -f Policy.sh ; then case "$dflt" in *Policy*) ;; none) dflt="Policy" ;; *) dflt="Policy $dflt" ;; esac fi ;; *) dflt=`echo $hintfile | $sed 's/\.sh$//'` ;; esac echo $osname pgtap-1.3.2/tools/missing_extensions.sh000077500000000000000000000015641455775703000203020ustar00rootroot00000000000000#!/bin/sh MISSING_EXTENSIONS=$1 EXTENSION_TEST_FILES=$2 # Doesn't seem worth pulling all of util.sh in for just this, but if you need # anything else please just pull it in! stderr() { echo "$@" >&2 } if [ -n "$MISSING_EXTENSIONS" ]; then if [ -n "$ALLOW_MISSING_EXTENSIONS" ]; then stderr stderr '***************************' stderr "WARNING: Some mandatory extensions ($MISSING_EXTENSIONS) are not installed, ignoring tests: $EXTENSION_TEST_FILES" stderr '***************************' stderr else stderr stderr '***************************' stderr "ERROR: Missing extensions required for testing: $MISSING_EXTENSIONS" stderr stderr "You may over-ride by setting \$ALLOW_MISSING_EXTENSIONS to a value." stderr '***************************' stderr exit 1 fi fi pgtap-1.3.2/tools/parallel_conn.sh000077500000000000000000000020111455775703000171470ustar00rootroot00000000000000#!/bin/sh # Find the maximum safe connections for parallel execution error () { echo $@ 1>&2 } die () { error $@ exit 1 } [ $# -le 1 ] || die "$0: Invalid number of arguments" PARALLEL_CONN=$1 if [ -n "$PARALLEL_CONN" ]; then [ $PARALLEL_CONN -ge 1 ] 2>/dev/null || die "Invalid value for PARALLEL_CONN ($PARALLEL_CONN)" echo $PARALLEL_CONN exit fi COMMAND="SELECT greatest(1, current_setting('max_connections')::int - current_setting('superuser_reserved_connections')::int - (SELECT count(*) FROM pg_stat_activity) - 2)" if PARALLEL_CONN=`psql -d ${PGDATABASE:-postgres} -P pager=off -P tuples_only=true -qAXtc "$COMMAND" 2> /dev/null`; then if [ $PARALLEL_CONN -ge 1 ] 2>/dev/null; then # We know it's a number at this point [ $PARALLEL_CONN -eq 1 ] && error "NOTICE: unable to run tests in parallel; not enough connections" echo $PARALLEL_CONN exit fi fi error "Problems encountered determining maximum parallel test connections; forcing serial mode" echo 1 pgtap-1.3.2/tools/psql_args.sh000077500000000000000000000006441455775703000163430ustar00rootroot00000000000000#!/bin/sh # This script allows for passing args to psql using pg_regress's --launcher option while [ $# -gt 0 ]; do case $1 in */psql) found=1 break ;; *) args="$args $1" shift ;; esac done if [ -z "$found" ]; then echo "Error: psql not found in arguments" exit 1 fi #$* $args <&0 || exit $? $* $args || exit $? pgtap-1.3.2/tools/util.sh000066400000000000000000000060641455775703000153240ustar00rootroot00000000000000# Adapted from https://github.com/decibel/db_tools/blob/0.1.10/lib/util.sh ME=`basename $0` DEBUG=${DEBUG:-0} stderr() { echo "$@" 1>&2 } debug() { local level=$1 shift if [ $level -le $DEBUG ] ; then local oldIFS oldIFS=$IFS unset IFS # Output debug level if it's over threashold if [ $DEBUG -ge ${DEBUGEXTRA:-10} ]; then stderr "${level}: $@" else stderr "$@" fi IFS=$oldIFS fi } debug_vars () { level=$1 shift local out='' local value='' for variable in $*; do eval value=\$$variable out="$out $variable='$value'" done debug $level $out } debug_do() { local level level=$1 shift [ $level -gt $DEBUG ] || ( "$@" ) } debug_ls() { # Reverse test since we *exit* if we shouldn't debug! Also, note that unlike # `exit`, `return` does not default to 0. [ $1 -le $DEBUG ] || return 0 ( level=$1 shift # Look through each argument and see if more than one exist. If so, we don't # need to print what it is we're listing. location='' for a in "$@"; do if [ -e "$a" ]; then if [ -n "$location" ]; then location='' break else location=$a fi fi done stderr # blank line [ -z "$location" ] || stderr "$location" ls "$@" >&2 ) } error() { local stack lineno stack='' lineno='' while [ "$1" = "-s" -o "$1" = "-n" ]; do if [ "$1" = "-n" ]; then lineno=$2 shift 2 fi if [ "$1" = "-s" ]; then stack=1 shift fi done stderr "$@" if [ -n "$stack" ]; then stacktrace 1 # Skip our own frame else [ -z "$lineno" ] || echo "File \"$0\", line $lineno" 1>&2 fi } die() { local return=$1 debug_vars 99 return shift error "$@" [ $DEBUG -le 0 ] || stacktrace 1 if [ -n "${DIE_EXTRA:-}" ]; then local lineno='' error error $DIE_EXTRA fi exit $return } db_exists() { local exists exists=`psql -qtc "SELECT EXISTS( SELECT 1 FROM pg_database WHERE datname = '$dbname' )" postgres $@ | tr -d ' '` if [ "$exists" == "t" ]; then return 0 else return 1 fi } stacktrace () { debug 200 "stacktrace( $@ )" local frame=${1:-0} local line='' local file='' debug_vars 200 frame line file # NOTE the stderr redirect below! ( echo echo Stacktrace: while caller $frame; do frame=$(( $frame + 1 )) done | while read line function file; do if [ -z "$function" -o "$function" = main ]; then echo "$file: line $line" else echo "$file: line $line: function $function" fi done ) 1>&2 } # This is intended to be used by a trap, ie: # trap err_report ERR err_report() { stderr "errexit on line $(caller)" >&2 } find_at_path() ( export PATH="$1:$PATH" # Unfortunately need to maintain old PATH to be able to find `which` :( out=$(command -v $2) [ -n "$out" ] || die 2 "unable to find $2" echo $out ) # vi: noexpandtab ts=2 sw=2