diff --git a/contrib/userlock/user_locks.c b/contrib/userlock/user_locks.c index 207610084b..418daf212e 100644 --- a/contrib/userlock/user_locks.c +++ b/contrib/userlock/user_locks.c @@ -19,9 +19,9 @@ #define SET_LOCKTAG_USERLOCK(locktag,id1,id2) \ - ((locktag).locktag_field1 = (id1), \ - (locktag).locktag_field2 = (id2), \ - (locktag).locktag_field3 = MyDatabaseId, \ + ((locktag).locktag_field1 = MyDatabaseId, \ + (locktag).locktag_field2 = (id1), \ + (locktag).locktag_field3 = (id2), \ (locktag).locktag_field4 = 0, \ (locktag).locktag_type = LOCKTAG_USERLOCK) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 0aa12d4eae..544f9b758d 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -4040,15 +4040,18 @@ lockable object may appear many times, if multiple transactions are holding or waiting for locks on it. However, an object that currently has no locks on it - will not appear at all. A lockable object is either a relation (e.g., a - table) or a transaction ID. + will not appear at all. - Note that this view includes only table-level - locks, not row-level ones. If a transaction is waiting for a - row-level lock, it will appear in the view as waiting for the - transaction ID of the current holder of that row lock. + There are several distinct types of lockable objects: + whole relations (e.g., tables), individual pages of relations, + individual tuples of relations, + transaction IDs, + and general database objects (identified by class OID and object OID, + in the same way as in pg_description or + pg_depend). Also, the right to extend a + relation is represented as a separate lockable object. @@ -4065,12 +4068,18 @@ - relation - oid - pg_class.oid + locktype + text + - OID of the locked relation, or NULL if the lockable object - is a transaction ID + type of the lockable object: + relation, + extend, + page, + tuple, + transaction, + object, or + userlock @@ -4078,9 +4087,35 @@ oid pg_database.oid - OID of the database in which the locked relation exists, or - zero if the locked relation is a globally-shared table, or - NULL if the lockable object is a transaction ID + OID of the database in which the object exists, or + zero if the object is a globally-shared object, or + NULL if the object is a transaction ID + + + + relation + oid + pg_class.oid + + OID of the relation, or NULL if the object is not + a relation or part of a relation + + + + page + integer + + + page number within the relation, or NULL if the object + is not a tuple or relation page + + + + tuple + smallint + + + tuple number within the page, or NULL if the object is not a tuple @@ -4088,14 +4123,43 @@ xid - ID of a transaction, or NULL if the lockable object is a relation + ID of a transaction, or NULL if the object is not a transaction ID + + + + classid + oid + pg_class.oid + + OID of the system catalog containing the object, or NULL if the + object is not a general database object + + + + objid + oid + any OID column + + OID of the object within its system catalog, or NULL if the + object is not a general database object + + + + objsubid + smallint + + + For a table column, this is the column number (the + classid and objid refer to the + table itself). For all other object types, this column is + zero. NULL if the object is not a general database object pid integer - process ID of a server process holding or awaiting this + process ID of the server process holding or awaiting this lock @@ -4133,6 +4197,21 @@ terminates and releases its locks. + + 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 transaction is waiting for a + row-level lock, it will usually appear in the view as waiting for the + transaction ID of the current holder of that row lock. + + + + If user-defined locks are in use, they are displayed using the columns + for general database objects. However, the actual meaning of the lock + fields in such cases is up to the user. + + When the pg_locks view is accessed, the internal lock manager data structures are momentarily locked, and diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 1bf0f1657d..d66bb780b4 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -3,7 +3,7 @@ * * Copyright (c) 1996-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.12 2005/05/09 11:31:32 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.13 2005/05/17 21:46:09 tgl Exp $ */ CREATE VIEW pg_user AS @@ -261,8 +261,10 @@ CREATE VIEW pg_stat_database AS CREATE VIEW pg_locks AS SELECT * - FROM pg_lock_status() AS L(relation oid, database oid, - transaction xid, pid int4, mode text, granted boolean); + FROM pg_lock_status() AS L + (locktype text, database oid, relation oid, page int4, tuple int2, + transaction xid, classid oid, objid oid, objsubid int2, + pid int4, mode text, granted boolean); CREATE VIEW pg_settings AS SELECT * diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 6878662b79..e941ec2d3d 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -6,7 +6,7 @@ * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.17 2005/04/29 22:28:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.18 2005/05/17 21:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,17 @@ #include "utils/builtins.h" +/* This must match enum LockTagType! */ +static const char * const LockTagTypeNames[] = { + "relation", + "extend", + "page", + "tuple", + "transaction", + "object", + "userlock" +}; + /* Working status for pg_lock_status */ typedef struct { @@ -53,18 +64,30 @@ pg_lock_status(PG_FUNCTION_ARGS) /* build tupdesc for result tuples */ /* this had better match pg_locks view in system_views.sql */ - tupdesc = CreateTemplateTupleDesc(6, false); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation", - OIDOID, -1, 0); + tupdesc = CreateTemplateTupleDesc(12, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype", + TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction", - XIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid", + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page", INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode", + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple", + INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "transaction", + XIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "classid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "objid", + OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objsubid", + INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 10, "pid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 11, "mode", TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted", + TupleDescInitEntry(tupdesc, (AttrNumber) 12, "granted", BOOLOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); @@ -93,8 +116,10 @@ pg_lock_status(PG_FUNCTION_ARGS) PGPROC *proc; bool granted; LOCKMODE mode = 0; - Datum values[6]; - char nulls[6]; + const char *locktypename; + char tnbuf[32]; + Datum values[12]; + char nulls[12]; HeapTuple tuple; Datum result; @@ -155,30 +180,79 @@ pg_lock_status(PG_FUNCTION_ARGS) MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); + if (lock->tag.locktag_type <= LOCKTAG_USERLOCK) + locktypename = LockTagTypeNames[lock->tag.locktag_type]; + else + { + snprintf(tnbuf, sizeof(tnbuf), "unknown %d", + (int) lock->tag.locktag_type); + locktypename = tnbuf; + } + values[0] = DirectFunctionCall1(textin, + CStringGetDatum(locktypename)); + + switch (lock->tag.locktag_type) { case LOCKTAG_RELATION: case LOCKTAG_RELATION_EXTEND: - case LOCKTAG_PAGE: - case LOCKTAG_TUPLE: - values[0] = ObjectIdGetDatum(lock->tag.locktag_field2); values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); - nulls[2] = 'n'; + values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); + nulls[3] = 'n'; + nulls[4] = 'n'; + nulls[5] = 'n'; + nulls[6] = 'n'; + nulls[7] = 'n'; + nulls[8] = 'n'; + break; + case LOCKTAG_PAGE: + values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); + values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); + values[3] = UInt32GetDatum(lock->tag.locktag_field3); + nulls[4] = 'n'; + nulls[5] = 'n'; + nulls[6] = 'n'; + nulls[7] = 'n'; + nulls[8] = 'n'; + break; + case LOCKTAG_TUPLE: + values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); + values[2] = ObjectIdGetDatum(lock->tag.locktag_field2); + values[3] = UInt32GetDatum(lock->tag.locktag_field3); + values[4] = UInt16GetDatum(lock->tag.locktag_field4); + nulls[5] = 'n'; + nulls[6] = 'n'; + nulls[7] = 'n'; + nulls[8] = 'n'; break; case LOCKTAG_TRANSACTION: - nulls[0] = 'n'; + values[5] = TransactionIdGetDatum(lock->tag.locktag_field1); nulls[1] = 'n'; - values[2] = TransactionIdGetDatum(lock->tag.locktag_field1); + nulls[2] = 'n'; + nulls[3] = 'n'; + nulls[4] = 'n'; + nulls[6] = 'n'; + nulls[7] = 'n'; + nulls[8] = 'n'; + break; + case LOCKTAG_OBJECT: + case LOCKTAG_USERLOCK: + default: /* treat unknown locktags like OBJECT */ + values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); + values[6] = ObjectIdGetDatum(lock->tag.locktag_field2); + values[7] = ObjectIdGetDatum(lock->tag.locktag_field3); + values[8] = Int16GetDatum(lock->tag.locktag_field4); + nulls[2] = 'n'; + nulls[3] = 'n'; + nulls[4] = 'n'; + nulls[5] = 'n'; break; - default: - /* XXX Ignore all other lock types for now */ - continue; } - values[3] = Int32GetDatum(proc->pid); - values[4] = DirectFunctionCall1(textin, - CStringGetDatum(GetLockmodeName(mode))); - values[5] = BoolGetDatum(granted); + values[9] = Int32GetDatum(proc->pid); + values[10] = DirectFunctionCall1(textin, + CStringGetDatum(GetLockmodeName(mode))); + values[11] = BoolGetDatum(granted); tuple = heap_formtuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 2579b032a5..dd1c29ab02 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.267 2005/05/09 11:31:34 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.268 2005/05/17 21:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200505091 +#define CATALOG_VERSION_NO 200505171 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 13468fc5be..a3f50ea890 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.361 2005/05/09 11:31:34 neilc Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.362 2005/05/17 21:46:10 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2999,7 +2999,7 @@ DATA(insert OID = 2078 ( set_config PGNSP PGUID 12 f f f f v 3 25 "25 25 16" _ DESCR("SET X as a function"); DATA(insert OID = 2084 ( pg_show_all_settings PGNSP PGUID 12 f f t t s 0 2249 "" _null_ _null_ _null_ show_all_settings - _null_ )); DESCR("SHOW ALL as a function"); -DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 f f f t v 0 2249 "" _null_ _null_ _null_ pg_lock_status - _null_ )); +DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 f f t t v 0 2249 "" _null_ _null_ _null_ pg_lock_status - _null_ )); DESCR("view system lock information"); DATA(insert OID = 2079 ( pg_table_is_visible PGNSP PGUID 12 f f t f s 1 16 "26" _null_ _null_ _null_ pg_table_is_visible - _null_ )); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 5e3ca10fae..5eccf2d44a 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1278,7 +1278,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem --------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char")); - pg_locks | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean); + pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l."transaction", l.classid, l.objid, l.objsubid, l.pid, l."mode", l.granted FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, "transaction" xid, classid oid, objid oid, objsubid smallint, pid integer, "mode" text, granted boolean); pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); pg_settings | SELECT a.name, a.setting, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text); pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));