diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-09-13 20:10:13 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-09-13 20:10:13 +0000 |
commit | b2c4071299e02ed96d48d3c8e776de2fab36f88c (patch) | |
tree | ff0db14826870f1c3fe46d94ea3a1e1697c658a7 /src/backend/tcop/utility.c | |
parent | d69528881ab72eac5a9f154f23dbf549789c264d (diff) | |
download | postgresql-b2c4071299e02ed96d48d3c8e776de2fab36f88c.tar.gz postgresql-b2c4071299e02ed96d48d3c8e776de2fab36f88c.zip |
Redesign query-snapshot timing so that volatile functions in READ COMMITTED
mode see a fresh snapshot for each command in the function, rather than
using the latest interactive command's snapshot. Also, suppress fresh
snapshots as well as CommandCounterIncrement inside STABLE and IMMUTABLE
functions, instead using the snapshot taken for the most closely nested
regular query. (This behavior is only sane for read-only functions, so
the patch also enforces that such functions contain only SELECT commands.)
As per my proposal of 6-Sep-2004; I note that I floated essentially the
same proposal on 19-Jun-2002, but that discussion tailed off without any
action. Since 8.0 seems like the right place to be taking possibly
nontrivial backwards compatibility hits, let's get it done now.
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r-- | src/backend/tcop/utility.c | 93 |
1 files changed, 90 insertions, 3 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6aec17bf9a5..d44e986e3c1 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.229 2004/09/10 18:40:00 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.230 2004/09/13 20:07:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -222,6 +222,46 @@ CheckRelationOwnership(RangeVar *rel, bool noCatalogs) } +/* + * QueryIsReadOnly: is an analyzed/rewritten query read-only? + * + * This is a much stricter test than we apply for XactReadOnly mode; + * the query must be *in truth* read-only, because the caller wishes + * not to do CommandCounterIncrement for it. + */ +bool +QueryIsReadOnly(Query *parsetree) +{ + switch (parsetree->commandType) + { + case CMD_SELECT: + if (parsetree->into != NULL) + return false; /* SELECT INTO */ + else if (parsetree->rowMarks != NIL) + return false; /* SELECT FOR UPDATE */ + else + return true; + case CMD_UPDATE: + case CMD_INSERT: + case CMD_DELETE: + return false; + case CMD_UTILITY: + /* For now, treat all utility commands as read/write */ + return false; + default: + elog(WARNING, "unrecognized commandType: %d", + (int) parsetree->commandType); + break; + } + return false; +} + +/* + * check_xact_readonly: is a utility command read-only? + * + * Here we use the loose rules of XactReadOnly mode: no permanent effects + * on the database are allowed. + */ static void check_xact_readonly(Node *parsetree) { @@ -299,8 +339,7 @@ check_xact_readonly(Node *parsetree) * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * in which to store a command completion status string. * - * completionTag is only set nonempty if we want to return a nondefault - * status (currently, only used for MOVE/FETCH). + * completionTag is only set nonempty if we want to return a nondefault status. * * completionTag may be NULL if caller doesn't want a status string. */ @@ -1586,3 +1625,51 @@ CreateCommandTag(Node *parsetree) return tag; } + +/* + * CreateQueryTag + * utility to get a string representation of a Query operation. + * + * This is exactly like CreateCommandTag, except it works on a Query + * that has already been through parse analysis (and possibly further). + */ +const char * +CreateQueryTag(Query *parsetree) +{ + const char *tag; + + switch (parsetree->commandType) + { + case CMD_SELECT: + /* + * We take a little extra care here so that the result will + * be useful for complaints about read-only statements + */ + if (parsetree->into != NULL) + tag = "SELECT INTO"; + else if (parsetree->rowMarks != NIL) + tag = "SELECT FOR UPDATE"; + else + tag = "SELECT"; + break; + case CMD_UPDATE: + tag = "UPDATE"; + break; + case CMD_INSERT: + tag = "INSERT"; + break; + case CMD_DELETE: + tag = "DELETE"; + break; + case CMD_UTILITY: + tag = CreateCommandTag(parsetree->utilityStmt); + break; + default: + elog(WARNING, "unrecognized commandType: %d", + (int) parsetree->commandType); + tag = "???"; + break; + } + + return tag; +} |