postgresql/src/test/isolation
Heikki Linnakangas 6214e2b228 Fix permission checks on constraint violation errors on partitions.
If a cross-partition UPDATE violates a constraint on the target partition,
and the columns in the new partition are in different physical order than
in the parent, the error message can reveal columns that the user does not
have SELECT permission on. A similar bug was fixed earlier in commit
804b6b6db4.

The cause of the bug is that the callers of the
ExecBuildSlotValueDescription() function got confused when constructing
the list of modified columns. If the tuple was routed from a parent, we
converted the tuple to the parent's format, but the list of modified
columns was grabbed directly from the child's RTE entry.

ExecUpdateLockMode() had a similar issue. That lead to confusion on which
columns are key columns, leading to wrong tuple lock being taken on tables
referenced by foreign keys, when a row is updated with INSERT ON CONFLICT
UPDATE. A new isolation test is added for that corner case.

With this patch, the ri_RangeTableIndex field is no longer set for
partitions that don't have an entry in the range table. Previously, it was
set to the RTE entry of the parent relation, but that was confusing.

NOTE: This modifies the ResultRelInfo struct, replacing the
ri_PartitionRoot field with ri_RootResultRelInfo. That's a bit risky to
backpatch, because it breaks any extensions accessing the field. The
change that ri_RangeTableIndex is not set for partitions could potentially
break extensions, too. The ResultRelInfos are visible to FDWs at least,
and this patch required small changes to postgres_fdw. Nevertheless, this
seem like the least bad option. I don't think these fields widely used in
extensions; I don't think there are FDWs out there that uses the FDW
"direct update" API, other than postgres_fdw. If there is, you will get a
compilation error, so hopefully it is caught quickly.

Backpatch to 11, where support for both cross-partition UPDATEs, and unique
indexes on partitioned tables, were added.

Reviewed-by: Amit Langote
Security: CVE-2021-3393
2021-02-08 11:01:51 +02:00
..
expected Fix permission checks on constraint violation errors on partitions. 2021-02-08 11:01:51 +02:00
specs Fix permission checks on constraint violation errors on partitions. 2021-02-08 11:01:51 +02:00
.gitignore Move isolationtester's is-blocked query into C code for speed. 2017-04-10 10:26:54 -04:00
isolation_main.c Allow pg_regress.c wrappers to postprocess test result files. 2021-01-11 13:43:19 -05:00
isolation_schedule Fix permission checks on constraint violation errors on partitions. 2021-02-08 11:01:51 +02:00
isolationtester.c Avoid redundantly prefixing PQerrorMessage for a connection failure. 2021-01-22 16:52:31 -05:00
isolationtester.h Update copyright for 2021 2021-01-02 13:06:25 -05:00
Makefile Fix CREATE INDEX CONCURRENTLY for simultaneous prepared transactions. 2021-01-30 00:00:27 -08:00
README Fix CREATE INDEX CONCURRENTLY for simultaneous prepared transactions. 2021-01-30 00:00:27 -08:00
specparse.y Update copyright for 2021 2021-01-02 13:06:25 -05:00
specscanner.l Update copyright for 2021 2021-01-02 13:06:25 -05:00

src/test/isolation/README

Isolation tests
===============

This directory contains a set of tests for concurrent behaviors in
PostgreSQL.  These tests require running multiple interacting transactions,
which requires management of multiple concurrent connections, and therefore
can't be tested using the normal pg_regress program.  The name "isolation"
comes from the fact that the original motivation was to test the
serializable isolation level; but tests for other sorts of concurrent
behaviors have been added as well.

You can run the tests against the current build tree by typing
    make check
Alternatively, you can run against an existing installation by typing
    make installcheck
(This will contact a server at the default port expected by libpq.
You can set PGPORT and so forth in your environment to control this.)

To run just specific test(s) against an installed server,
you can do something like
    ./pg_isolation_regress fk-contention fk-deadlock
(look into the specs/ subdirectory to see the available tests).

Certain tests require the server's max_prepared_transactions parameter to be
set to at least 3; therefore they are not run by default.  To include them in
the test run, use
    make check-prepared-txns
or
    make installcheck-prepared-txns
after making sure the server configuration is correct (see TEMP_CONFIG
to adjust this in the "check" case).

To define tests with overlapping transactions, we use test specification
files with a custom syntax, which is described in the next section.  To add
a new test, place a spec file in the specs/ subdirectory, add the expected
output in the expected/ subdirectory, and add the test's name to the
isolation_schedule file.

isolationtester is a program that uses libpq to open multiple connections,
and executes a test specified by a spec file. A libpq connection string
specifies the server and database to connect to; defaults derived from
environment variables are used otherwise.

pg_isolation_regress is a tool similar to pg_regress, but instead of using
psql to execute a test, it uses isolationtester.  It accepts all the same
command-line arguments as pg_regress.

By default, isolationtester will wait at most 300 seconds (5 minutes)
for any one test step to complete.  If you need to adjust this, set
the environment variable PGISOLATIONTIMEOUT to the desired timeout
in seconds.


Test specification
==================

Each isolation test is defined by a specification file, stored in the specs
subdirectory. A test specification consists of four parts, in this order:

setup { <SQL> }

  The given SQL block is executed once, in one session only, before running
  the test.  Create any test tables or other required objects here.  This
  part is optional.  Multiple setup blocks are allowed if needed; each is
  run separately, in the given order.  (The reason for allowing multiple
  setup blocks is that each block is run as a single PQexec submission,
  and some statements such as VACUUM cannot be combined with others in such
  a block.)

teardown { <SQL> }

  The teardown SQL block is executed once after the test is finished. Use
  this to clean up in preparation for the next permutation, e.g dropping
  any test tables created by setup. This part is optional.

session "<name>"

  There are normally several "session" parts in a spec file. Each
  session is executed in its own connection. A session part consists
  of three parts: setup, teardown and one or more "steps". The per-session
  setup and teardown parts have the same syntax as the per-test setup and
  teardown described above, but they are executed in each session. The
  setup part typically contains a "BEGIN" command to begin a transaction.

  Each step has the syntax

  step "<name>" { <SQL> }

  where <name> is a name identifying this step, and SQL is a SQL statement
  (or statements, separated by semicolons) that is executed in the step.
  Step names must be unique across the whole spec file.

permutation "<step name>" ...

  A permutation line specifies a list of steps that are run in that order.
  Any number of permutation lines can appear.  If no permutation lines are
  given, the test program automatically generates all possible orderings
  of the steps from each session (running the steps of any one session in
  order).  Note that the list of steps in a manually specified
  "permutation" line doesn't actually have to be a permutation of the
  available steps; it could for instance repeat some steps more than once,
  or leave others out.

Lines beginning with a # are considered comments.

For each permutation of the session steps (whether these are manually
specified in the spec file, or automatically generated), the isolation
tester runs the main setup part, then per-session setup parts, then
the selected session steps, then per-session teardown, then the main
teardown script.  Each selected step is sent to the connection associated
with its session.


Support for blocking commands
=============================

Each step may contain commands that block until further action has been taken
(most likely, some other session runs a step that unblocks it or causes a
deadlock).  A test that uses this ability must manually specify valid
permutations, i.e. those that would not expect a blocked session to execute a
command.  If a test fails to follow that rule, isolationtester will cancel it
after PGISOLATIONTIMEOUT seconds.  If the cancel doesn't work, isolationtester
will exit uncleanly after a total of twice PGISOLATIONTIMEOUT.  Testing
invalid permutations should be avoided because they can make the isolation
tests take a very long time to run, and they serve no useful testing purpose.

Note that isolationtester recognizes that a command has blocked by looking
to see if it is shown as waiting in the pg_locks view; therefore, only
blocks on heavyweight locks will be detected.