5.6. Visibility Check Rules

Visibility check rules determine whether a tuple is visible or invisible. These rules utilize the tuple’s t_xmin and t_xmax fields, the clog, and the transaction snapshot.

Due to the complexity of the full ruleset, this documentation presents only the minimal rules required for subsequent sections. The following descriptions omit sub-transaction logic and do not consider tuples updated more than twice within a single transaction (i.e., t_ctid is ignored).

The ten selected rules are classified into the following three cases based on the status of t_xmin.

5.6.1. Status of t_xmin is ABORTED

A tuple whose t_xmin status is ABORTED is always invisible (Rule 1) because the transaction that inserted the tuple failed.

/* t_xmin status == ABORTED */
Rule 1:	  IF t_xmin status is 'ABORTED' THEN
                 RETURN 'Invisible'
          END IF
  • Rule 1: If Status(t_xmin) = ABORTED $\Rightarrow$ Invisible

5.6.2. Status of t_xmin is IN_PROGRESS

A tuple whose t_xmin status is IN_PROGRESS is generally invisible (Rules 3 and 4), with one exception for the inserting transaction (Rule 2).

 /* t_xmin status == IN_PROGRESS */
       IF t_xmin status is 'IN_PROGRESS' THEN
              IF t_xmin = current_txid THEN
Rule 2:              IF t_xmax = INVALID THEN
                           RETURN 'Visible'
Rule 3:              ELSE  /* this tuple has been deleted or updated  */
                           /* by the current transaction itself.      */
                            RETURN 'Invisible'
                     END IF
Rule 4:       ELSE   /* t_xmin != current_txid */
                     RETURN 'Invisible'
              END IF
       END IF

If another transaction inserted the tuple and its t_xmin status is IN_PROGRESS, the tuple is invisible (Rule 4). In other words, uncommitted changes from one transaction are invisible to other transactions.

The exception occurs when the current transaction inserted the tuple and t_xmax is INVALID. In this case, the tuple is visible to the current transaction (Rule 2) because it was inserted by the current transaction itself.

However, even if t_xmin equals the current txid (i.e., the current transaction inserted the tuple) and t_xmax is not INVALID, the tuple is invisible because the current transaction has already updated or deleted it (Rule 3).

  • Rule 2: If Status(t_xmin) = IN_PROGRESS $\wedge$ t_xmin = current_txid $\wedge$ t_xmax = INVALID $\Rightarrow$ Visible
  • Rule 3: If Status(t_xmin) = IN_PROGRESS $\wedge$ t_xmin = current_txid $\wedge$ t_xmax $\ne$ INVALID $\Rightarrow$ Invisible
  • Rule 4: If Status(t_xmin) = IN_PROGRESS $\wedge$ t_xmin $\ne$ current_txid $\Rightarrow$ Invisible

5.6.3. Status of t_xmin is COMMITTED

A tuple whose t_xmin status is COMMITTED is visible (Rules 6, 8, and 9), with three exceptions.

 /* t_xmin status == COMMITTED */
        IF t_xmin status is 'COMMITTED' THEN
Rule 5:        IF t_xmin is 'active' in the obtained transaction snapshot THEN
                      RETURN 'Invisible'
Rule 6:        ELSE IF t_xmax = INVALID OR status of t_xmax is 'ABORTED' THEN
                      RETURN 'Visible'
               ELSE IF t_xmax status is 'IN_PROGRESS' THEN
Rule 7:               IF t_xmax =  current_txid THEN
                             RETURN 'Invisible'
Rule 8:               ELSE  /* t_xmax != current_txid */
                             RETURN 'Visible'
                      END IF
               ELSE IF t_xmax status is 'COMMITTED' THEN
Rule 9:               IF t_xmax is 'active' in the obtained transaction snapshot THEN
                             RETURN 'Visible'
Rule 10:              ELSE
                             RETURN 'Invisible'
                      END IF
               END IF
        END IF

Rule 6 is straightforward because t_xmax is either INVALID or ABORTED. The three exceptions, along with Rules 8 and 9, are described below.

The first exception occurs when t_xmin is active in the obtained transaction snapshot (Rule 5). Under this condition, the tuple is invisible because t_xmin is treated as being in progress.

The second exception occurs when t_xmax equals the current txid (Rule 7). In this case, similar to Rule 3, the tuple is invisible because the current transaction has deleted or updated it.

In contrast, if the status of t_xmax is IN_PROGRESS and t_xmax is not the current txid (Rule 8), the tuple is visible. This is because the deleting transaction is still in progress and has not yet committed.

The third exception occurs when the status of t_xmax is COMMITTED and t_xmax is not active in the obtained transaction snapshot (Rule 10). Under this condition, the tuple is invisible because another transaction has committed its deletion or update.

In contrast, if the status of t_xmax is COMMITTED but t_xmax is active in the obtained snapshot (Rule 9), the tuple is visible. This is because the deleting transaction is treated as being in progress.

  • Rule 5: If Status(t_xmin) = COMMITTED $\wedge$ Snapshot(t_xmin) = active $\Rightarrow$ Invisible
  • Rule 6: If Status(t_xmin) = COMMITTED $\wedge$ ((t_xmax = INVALID $\vee$ Status(t_xmax) = ABORTED)) $\Rightarrow$ Visible
  • Rule 7: If Status(t_xmin) = COMMITTED $\wedge$ Status(t_xmax) = IN_PROGRESS $\wedge$ t_xmax = current_txid $\Rightarrow$ Invisible
  • Rule 8: If Status(t_xmin) = COMMITTED $\wedge$ Status(t_xmax) = IN_PROGRESS $\wedge$ t_xmax $\ne$ current_txid $\Rightarrow$ Visible
  • Rule 9: If Status(t_xmin) = COMMITTED $\wedge$ Status(t_xmax) = COMMITTED $\wedge$ Snapshot(t_xmax) = active $\Rightarrow$ Visible
  • Rule 10: If Status(t_xmin) = COMMITTED $\wedge$ Status(t_xmax) = COMMITTED $\wedge$ Snapshot(t_xmax) $\ne$ active $\Rightarrow$ Invisible

In summary, a tuple with a COMMITTED t_xmin is generally visible. However, it is invisible only if the inserting transaction is still in progress (Rule 5), or if the tuple has been logically deleted or updated (Rules 7 and 10).