]> 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 8ee1890044df7f9d7008533d3e8aead7cb0d105e..fdaa99e1f81a8e4ba04ce2b8f32c844a619949bf 100644 (file)
@@ -2,34 +2,45 @@
  *
  * 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-2003, PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.28 2003/11/29 19:52:04 pgsql 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/pg_shadow.h"
-#include "commands/dbcommands.h"
+#include "catalog/pg_authid.h"
+#include "utils/inval.h"
 #include "utils/syscache.h"
 #include "miscadmin.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);
+
+
 /*
  * The Postgres user running this command has Postgres superuser privileges
- *
- * All code should use either of these two functions to find out
- * whether a given user is a superuser, rather than evaluating
- * pg_shadow.usesuper directly, so that the escape hatch built in for
- * the single-user case works.
  */
 bool
 superuser(void)
@@ -38,23 +49,61 @@ superuser(void)
 }
 
 
+/*
+ * The specified role has Postgres superuser privileges
+ */
 bool
-superuser_arg(AclId 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,
-                                                 Int32GetDatum(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;
 }
+
+/*
+ * UseridCallback
+ *             Syscache inval callback function
+ */
+static void
+RoleidCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
+{
+       /* Invalidate our local cache in case role's superuserness changed */
+       last_roleid = InvalidOid;
+}