The object identifier (object ID) of a row. This is a serial number that is automatically added by PostgreSQL to all table rows (unless the table was created WITHOUT OIDS, in which case this column is not present).
The OID of the table containing this row. This attribute
is particularly handy for queries that select from
inheritance hierarchies, since without it, it's difficult
to tell which individual table a row came from. The
tableoid can be joined against
the oid column of
pg_class to obtain the table name.
The identity (transaction ID) of the inserting transaction for this tuple. (Note: A tuple is an individual state of a row; each update of a row creates a new tuple for the same logical row.)
The command identifier (starting at zero) within the inserting transaction.
The identity (transaction ID) of the deleting transaction, or zero for an undeleted tuple. It is possible for this field to be nonzero in a visible tuple: that usually indicates that the deleting transaction hasn't committed yet, or that an attempted deletion was rolled back.
The command identifier within the deleting transaction, or zero.
The tuple ID of the tuple within its table. This is a pair (block number, tuple index within block) that identifies the physical location of the tuple. Note that although the ctid can be used to locate the tuple very quickly, a row's ctid will change each time it is updated or moved by VACUUM FULL. Therefore ctid is useless as a long-term row identifier. The OID, or even better a user-defined serial number, should be used to identify logical rows.
OIDs are 32-bit quantities and are assigned from a single cluster-wide counter. In a large or long-lived database, it is possible for the counter to wrap around. Hence, it is bad practice to assume that OIDs are unique, unless you take steps to ensure that they are unique. Recommended practice when using OIDs for row identification is to create a unique constraint on the OID column of each table for which the OID will be used. Never assume that OIDs are unique across tables; use the combination of tableoid and row OID if you need a database-wide identifier. (Future releases of PostgreSQL are likely to use a separate OID counter for each table, so that tableoid must be included to arrive at a globally unique identifier.)
Transaction identifiers are 32-bit quantities. In a long-lived database it is possible for transaction IDs to wrap around. This is not a fatal problem given appropriate maintenance procedures; see the Administrator's Guide for details. However, it is unwise to depend on uniqueness of transaction IDs over the long term (more than one billion transactions).
Command identifiers are also 32-bit quantities. This creates a hard limit of 232 (4 billion) SQL commands within a single transaction. In practice this limit is not a problem --- note that the limit is on number of SQL queries, not number of tuples processed.
In case you, too, wonder what's up with the OIDs and the WITHOUT OID clause - Tom Lane has answered my question on this (there is also an answer from Bruce Momjian in the same thread, partly explaining the lack of documentation here.)