aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/README
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/misc/README')
-rw-r--r--src/backend/utils/misc/README159
1 files changed, 109 insertions, 50 deletions
diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README
index bf1e3b65455..263f97790f7 100644
--- a/src/backend/utils/misc/README
+++ b/src/backend/utils/misc/README
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.6 2007/09/10 00:57:21 tgl Exp $
+$PostgreSQL: pgsql/src/backend/utils/misc/README,v 1.7 2007/09/11 00:06:42 tgl Exp $
GUC IMPLEMENTATION NOTES
@@ -69,74 +69,133 @@ by SHOW.
SAVING/RESTORING GUC VARIABLE VALUES
-Prior values of configuration variables must be remembered in order to
-deal with three special cases: RESET (a/k/a SET TO DEFAULT), rollback of
-SET on transaction abort, and rollback of SET LOCAL at transaction end
-(either commit or abort). RESET is defined as selecting the value that
-would be effective had there never been any SET commands in the current
-session.
+Prior values of configuration variables must be remembered in order to deal
+with several special cases: RESET (a/k/a SET TO DEFAULT), rollback of SET
+on transaction abort, rollback of SET LOCAL at transaction end (either
+commit or abort), and save/restore around a function that has a SET option.
+RESET is defined as selecting the value that would be effective had there
+never been any SET commands in the current session.
To handle these cases we must keep track of many distinct values for each
variable. The primary values are:
* actual variable contents always the current effective value
-* reset_value the value to use for RESET
+* reset_val the value to use for RESET
+
+(Each GUC entry also has a boot_val which is the wired-in default value.
+This is assigned to the reset_val and the actual variable during
+InitializeGUCOptions(). The boot_val is also consulted to restore the
+correct reset_val if SIGHUP processing discovers that a variable formerly
+specified in postgresql.conf is no longer set there.)
+
+In addition to the primary values, there is a stack of former effective
+values that might need to be restored in future. Stacking and unstacking
+is controlled by the GUC "nest level", which is zero when outside any
+transaction, one at top transaction level, and incremented for each
+open subtransaction or function call with a SET option. A stack entry
+is made whenever a GUC variable is first modified at a given nesting level.
+(Note: the reset_val need not be stacked because it is only changed by
+non-transactional operations.)
+
+A stack entry has a state, a prior value of the GUC variable, a remembered
+source of that prior value, and depending on the state may also have a
+"masked" value. The masked value is needed when SET followed by SET LOCAL
+occur at the same nest level: the SET's value is masked but must be
+remembered to restore after transaction commit.
+
+During initialization we set the actual value and reset_val based on
+whichever non-interactive source has the highest priority. They will
+have the same value.
-* tentative_value the uncommitted result of SET
+The possible transactional operations on a GUC value are:
-The reason we need a tentative_value separate from the actual value is
-that when a transaction does SET followed by SET LOCAL, the actual value
-will now be the LOCAL value, but we want to remember the prior SET so that
-that value is restored at transaction commit.
+Entry to a function with a SET option:
-In addition, for each level of transaction (possibly nested) we have to
-remember the transaction-entry-time actual and tentative values, in case
-we need to restore them at transaction end. (The RESET value is essentially
-non-transactional, so it doesn't have to be stacked.) For efficiency these
-stack entries are not constructed until/unless the variable is actually SET
-within a particular transaction.
+ Push a stack entry with the prior variable value and state SAVE,
+ then set the variable.
-During initialization we set the actual value and reset_value based on
-whichever non-interactive source has the highest priority. They will
-have the same value. The tentative_value is not meaningful at this point.
+Plain SET command:
+
+ If no stack entry of current level:
+ Push new stack entry w/prior value and state SET
+ else if stack entry's state is SAVE, SET, or LOCAL:
+ change stack state to SET, don't change saved value
+ (here we are forgetting effects of prior set action)
+ else (entry must have state SET+LOCAL):
+ discard its masked value, change state to SET
+ (here we are forgetting effects of prior SET and SET LOCAL)
+ Now set new value.
+
+SET LOCAL command:
+
+ If no stack entry of current level:
+ Push new stack entry w/prior value and state LOCAL
+ else if stack entry's state is SAVE or LOCAL or SET+LOCAL:
+ no change to stack entry
+ (in SAVE case, SET LOCAL will be forgotten at func exit)
+ else (entry must have state SET):
+ put current active into its masked slot, set state SET+LOCAL
+ Now set new value.
+
+Transaction or subtransaction abort:
+
+ Pop stack entries, restoring prior value, until top < subxact depth
-A SET command starts by stacking the existing actual and tentative values
-if this hasn't already been done within the current transaction. Then:
+Transaction or subtransaction commit (incl. successful function exit):
-A SET LOCAL command sets the actual variable (and nothing else). At
-transaction end, the stacked values are used to restore the GUC entry
-to its pre-transaction state.
+ While stack entry level >= subxact depth
-A SET (or SET SESSION) command sets the actual variable, and if no error,
-then sets the tentative_value. If the transaction commits, the
-tentative_value is assigned again to the actual variable (which could by
-now be different, if the SET was followed by SET LOCAL). If the
-transaction aborts, the stacked values are used to restore the GUC entry
-to its pre-transaction state.
+ if entry's state is SAVE:
+ pop, restoring prior value
+ else if level is 1 and entry's state is SET+LOCAL:
+ pop, restoring *masked* value
+ else if level is 1 and entry's state is SET:
+ pop, discarding old value
+ else if level is 1 and entry's state is LOCAL:
+ pop, restoring prior value
+ else if there is no entry of exactly level N-1:
+ decrement entry's level, no other state change
+ else
+ merge entries of level N-1 and N as specified below
-In the case of SET within nested subtransactions, at each commit the
-tentative_value propagates out to the next transaction level. It will
-be thrown away at abort of any level, or after exiting the top transaction.
+The merged entry will have level N-1 and prior = older prior, so easiest
+to keep older entry and free newer. There are 12 possibilities since
+we already handled level N state = SAVE:
-RESET is executed like a SET, but using the reset_value as the desired new
+N-1 N
+
+SAVE SET discard top prior, set state SET
+SAVE LOCAL discard top prior, no change to stack entry
+SAVE SET+LOCAL discard top prior, copy masked, state S+L
+
+SET SET discard top prior, no change to stack entry
+SET LOCAL copy top prior to masked, state S+L
+SET SET+LOCAL discard top prior, copy masked, state S+L
+
+LOCAL SET discard top prior, set state SET
+LOCAL LOCAL discard top prior, no change to stack entry
+LOCAL SET+LOCAL discard top prior, copy masked, state S+L
+
+SET+LOCAL SET discard top prior and second masked, state SET
+SET+LOCAL LOCAL discard top prior, no change to stack entry
+SET+LOCAL SET+LOCAL discard top prior, copy masked, state S+L
+
+
+RESET is executed like a SET, but using the reset_val as the desired new
value. (We do not provide a RESET LOCAL command, but SET LOCAL TO DEFAULT
has the same behavior that RESET LOCAL would.) The source associated with
-the reset_value also becomes associated with the actual and tentative values.
+the reset_val also becomes associated with the actual value.
If SIGHUP is received, the GUC code rereads the postgresql.conf
configuration file (this does not happen in the signal handler, but at
next return to main loop; note that it can be executed while within a
transaction). New values from postgresql.conf are assigned to actual
-variable, reset_value, and stacked actual values, but only if each of
+variable, reset_val, and stacked actual values, but only if each of
these has a current source priority <= PGC_S_FILE. (It is thus possible
-for reset_value to track the config-file setting even if there is
+for reset_val to track the config-file setting even if there is
currently a different interactive value of the actual variable.)
-Note that tentative_value is unused and undefined except between a SET
-command and the end of the transaction. Also notice that we must track
-the source associated with each one of the values.
-
The assign_hook and show_hook routines work only with the actual variable,
and are not directly aware of the additional values maintained by GUC.
This is not a problem for normal usage, since we can assign first to the
@@ -154,9 +213,9 @@ pstrdup/palloc mechanisms. We would need to keep them in a permanent
context anyway, and strdup gives us more control over handling
out-of-memory failures.
-We allow a string variable's actual value, reset_val, tentative_val, and
-stacked copies of same to point at the same storage. This makes it
-slightly harder to free space (must test whether a value to be freed isn't
-equal to any of the other pointers in the GUC entry or associated stack
-items). The main advantage is that we never need to strdup during
-transaction commit/abort, so cannot cause an out-of-memory failure there.
+We allow a string variable's actual value, reset_val, boot_val, and stacked
+values to point at the same storage. This makes it slightly harder to free
+space (we must test whether a value to be freed isn't equal to any of the
+other pointers in the GUC entry or associated stack items). The main
+advantage is that we never need to strdup during transaction commit/abort,
+so cannot cause an out-of-memory failure there.