aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c61
1 files changed, 54 insertions, 7 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 3fccd95cb18..984485f9b45 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.49 2000/09/29 18:21:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.50 2000/11/08 22:09:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,6 +34,7 @@ static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
char *colname);
static Node *scanJoinForColumn(JoinExpr *join, char *colname,
int sublevels_up);
+static bool isForUpdate(ParseState *pstate, char *relname);
static List *expandNamesVars(ParseState *pstate, List *names, List *vars);
static void warnAutoRange(ParseState *pstate, char *refname);
@@ -477,6 +478,7 @@ addRangeTableEntry(ParseState *pstate,
bool inFromCl)
{
char *refname = alias ? alias->relname : relname;
+ LOCKMODE lockmode;
Relation rel;
RangeTblEntry *rte;
Attr *eref;
@@ -502,17 +504,22 @@ addRangeTableEntry(ParseState *pstate,
/*
* Get the rel's OID. This access also ensures that we have an
- * up-to-date relcache entry for the rel. We don't need to keep it
- * open, however. Since this is open anyway, let's check that the
- * number of column aliases is reasonable. - Thomas 2000-02-04
+ * up-to-date relcache entry for the rel. Since this is typically
+ * the first access to a rel in a statement, be careful to get the
+ * right access level depending on whether we're doing SELECT FOR UPDATE.
*/
- rel = heap_openr(relname, AccessShareLock);
+ lockmode = isForUpdate(pstate, relname) ? RowShareLock : AccessShareLock;
+ rel = heap_openr(relname, lockmode);
rte->relid = RelationGetRelid(rel);
- maxattrs = RelationGetNumberOfAttributes(rel);
eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
numaliases = length(eref->attrs);
+ /*
+ * Since the rel is open anyway, let's check that the
+ * number of column aliases is reasonable. - Thomas 2000-02-04
+ */
+ maxattrs = RelationGetNumberOfAttributes(rel);
if (maxattrs < numaliases)
elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
refname, maxattrs, numaliases);
@@ -527,7 +534,12 @@ addRangeTableEntry(ParseState *pstate,
}
rte->eref = eref;
- heap_close(rel, AccessShareLock);
+ /*
+ * Drop the rel refcount, but keep the access lock till end of transaction
+ * so that the table can't be deleted or have its schema modified
+ * underneath us.
+ */
+ heap_close(rel, NoLock);
/*----------
* Flags:
@@ -644,6 +656,41 @@ addRangeTableEntryForSubquery(ParseState *pstate,
}
/*
+ * Has the specified relname been selected FOR UPDATE?
+ */
+static bool
+isForUpdate(ParseState *pstate, char *relname)
+{
+ /* Outer loop to check parent query levels as well as this one */
+ while (pstate != NULL)
+ {
+ if (pstate->p_forUpdate != NIL)
+ {
+ if (lfirst(pstate->p_forUpdate) == NULL)
+ {
+ /* all tables used in query */
+ return true;
+ }
+ else
+ {
+ /* just the named tables */
+ List *l;
+
+ foreach(l, pstate->p_forUpdate)
+ {
+ char *rname = lfirst(l);
+
+ if (strcmp(relname, rname) == 0)
+ return true;
+ }
+ }
+ }
+ pstate = pstate->parentParseState;
+ }
+ return false;
+}
+
+/*
* Add the given RTE as a top-level entry in the pstate's join list,
* unless there already is an entry for it.
*/