]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/misc/superuser.c
Improve the plan cache invalidation mechanism to make it invalidate plans
[postgresql] / src / backend / utils / misc / superuser.c
index f677d64fd3e3615d85b3745d6282625a62702120..fdaa99e1f81a8e4ba04ce2b8f32c844a619949bf 100644 (file)
@@ -2,27 +2,41 @@
  *
  * superuser.c
  *       The superuser() function.  Determines if user has superuser privilege.
- *       Also, a function to check for the owner (datdba) of a database.
  *
+ * All code should use either of these two functions to find out
+ * whether a given user is a superuser, rather than examining
+ * pg_authid.rolsuper directly, so that the escape hatch built in for
+ * the single-user case works.
  *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.20 2002/02/18 23:11:26 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.38 2008/09/09 18:58:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/pg_database.h"
-#include "catalog/pg_shadow.h"
+#include "catalog/pg_authid.h"
+#include "utils/inval.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"
-#include "utils/fmgroids.h"
+
+
+/*
+ * In common cases the same roleid (ie, the session or current ID) will
+ * be queried repeatedly.  So we maintain a simple one-entry cache for
+ * the status of the last requested roleid.  The cache can be flushed
+ * at need by watching for cache update events on pg_authid.
+ */
+static Oid     last_roleid = InvalidOid;       /* InvalidOid == cache not valid */
+static bool last_roleid_is_super = false;
+static bool roleid_callback_registered = false;
+
+static void RoleidCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
 
 
 /*
@@ -35,54 +49,61 @@ superuser(void)
 }
 
 
+/*
+ * The specified role has Postgres superuser privileges
+ */
 bool
-superuser_arg(Oid userid)
+superuser_arg(Oid roleid)
 {
-       bool            result = false;
-       HeapTuple       utup;
+       bool            result;
+       HeapTuple       rtup;
+
+       /* Quick out for cache hit */
+       if (OidIsValid(last_roleid) && last_roleid == roleid)
+               return last_roleid_is_super;
 
        /* Special escape path in case you deleted all your users. */
-       if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID)
+       if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID)
                return true;
 
-       utup = SearchSysCache(SHADOWSYSID,
-                                                 ObjectIdGetDatum(userid),
+       /* OK, look up the information in pg_authid */
+       rtup = SearchSysCache(AUTHOID,
+                                                 ObjectIdGetDatum(roleid),
                                                  0, 0, 0);
-       if (HeapTupleIsValid(utup))
+       if (HeapTupleIsValid(rtup))
+       {
+               result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper;
+               ReleaseSysCache(rtup);
+       }
+       else
        {
-               result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
-               ReleaseSysCache(utup);
+               /* Report "not superuser" for invalid roleids */
+               result = false;
        }
+
+       /* If first time through, set up callback for cache flushes */
+       if (!roleid_callback_registered)
+       {
+               CacheRegisterSyscacheCallback(AUTHOID,
+                                                                         RoleidCallback,
+                                                                         (Datum) 0);
+               roleid_callback_registered = true;
+       }
+
+       /* Cache the result for next time */
+       last_roleid = roleid;
+       last_roleid_is_super = result;
+
        return result;
 }
 
-
 /*
- * The Postgres user running this command is the owner of the specified
- * database.
+ * UseridCallback
+ *             Syscache inval callback function
  */
-bool
-is_dbadmin(Oid dbid)
+static void
+RoleidCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
 {
-       Relation        pg_database;
-       ScanKeyData entry[1];
-       HeapScanDesc scan;
-       HeapTuple       dbtuple;
-       int32           dba;
-
-       /* There's no syscache for pg_database, so must look the hard way */
-       pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
-       ScanKeyEntryInitialize(&entry[0], 0x0,
-                                                  ObjectIdAttributeNumber, F_OIDEQ,
-                                                  ObjectIdGetDatum(dbid));
-       scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, entry);
-       dbtuple = heap_getnext(scan, 0);
-       if (!HeapTupleIsValid(dbtuple))
-               elog(ERROR, "database %u does not exist", dbid);
-       dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
-       heap_endscan(scan);
-       heap_close(pg_database, AccessShareLock);
-
-       /* XXX some confusion about whether userids are OID or int4 ... */
-       return (GetUserId() == (Oid) dba);
+       /* Invalidate our local cache in case role's superuserness changed */
+       last_roleid = InvalidOid;
 }