From 3908473c809d5c24940faebfabdad673f4302178 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 8 Nov 2000 22:10:03 +0000 Subject: Make DROP TABLE rollback-able: postpone physical file delete until commit. (WAL logging for this is not done yet, however.) Clean up a number of really crufty things that are no longer needed now that DROP behaves nicely. Make temp table mapper do the right things when drop or rename affecting a temp table is rolled back. Also, remove "relation modified while in use" error check, in favor of locking tables at first reference and holding that lock throughout the statement. --- src/backend/parser/parse_relation.c | 61 ++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) (limited to 'src/backend/parser/parse_relation.c') diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 3fccd95cb1..984485f9b4 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: @@ -643,6 +655,41 @@ addRangeTableEntryForSubquery(ParseState *pstate, return rte; } +/* + * 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. -- cgit v1.2.1