when the other transaction terminates and releases its locks.
</para>
<para>
Although tuples are a lockable type of object,
information about row-level locks is stored on disk, not in memory,
and therefore row-level locks normally do not appear in this view.
If a process is waiting for a
row-level lock, it will usually appear in the view as waiting for the
permanent transaction ID of the current holder of that row lock.
</para>
<para>
A speculative insertion lock consists of a transaction ID and a speculative
insertion token. The speculative insertion token is displayed in the
<structfield>objid</structfield> column.
</para>
<para>
Advisory locks can be acquired on keys consisting of either a single
<type>bigint</type> value or two integer values.
A <type>bigint</type> key is displayed with its
high-order half in the <structfield>classid</structfield> column, its low-order half
in the <structfield>objid</structfield> column, and <structfield>objsubid</structfield> equal
to 1. The original <type>bigint</type> value can be reassembled with the
expression <literal>(classid::bigint << 32) |
objid::bigint</literal>. Integer keys are displayed with the
first key in the
<structfield>classid</structfield> column, the second key in the <structfield>objid</structfield>
column, and <structfield>objsubid</structfield> equal to 2. The actual meaning of
the keys is up to the user. Advisory locks are local to each database,
so the <structfield>database</structfield> column is meaningful for an advisory lock.
</para>
<para>
Apply transaction locks are used in parallel mode to apply the transaction
in logical replication. The remote transaction ID is displayed in the
<structfield>transactionid</structfield> column. The <structfield>objsubid</structfield>
displays the lock subtype which is 0 for the lock used to synchronize the
set of changes, and 1 for the lock used to wait for the transaction to
finish to ensure commit order.
</para>
<para>
<structname>pg_locks</structname> provides a global view of all locks
in the database cluster, not only those relevant to the current database.
Although its <structfield>relation</structfield> column can be joined
against <link linkend="catalog-pg-class"><structname>pg_class</structname></link>.<structfield>oid</structfield> to identify locked
relations, this will only work correctly for relations in the current
database (those for which the <structfield>database</structfield> column
is either the current database's OID or zero).
</para>
<para>
The <structfield>pid</structfield> column can be joined to the
<structfield>pid</structfield> column of the
<link linkend="monitoring-pg-stat-activity-view">
<structname>pg_stat_activity</structname></link>
view to get more
information on the session holding or awaiting each lock,
for example
<programlisting>
SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa
ON pl.pid = psa.pid;
</programlisting>
Also, if you are using prepared transactions, the
<structfield>virtualtransaction</structfield> column can be joined to the
<structfield>transaction</structfield> column of the <link
linkend="view-pg-prepared-xacts"><structname>pg_prepared_xacts</structname></link>
view to get more information on prepared transactions that hold locks.
(A prepared transaction can never be waiting for a lock,
but it continues to hold the locks it acquired while running.)
For example:
<programlisting>
SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
ON pl.virtualtransaction = '-1/' || ppx.transaction;
</programlisting>
</para>
<para>
While it is possible to obtain information about which processes block
which other processes by joining <structname>pg_locks</structname> against
itself, this is very difficult to get right in detail. Such a query would
have to encode knowledge