title: PostgreSQL Error 42501: Permission Denied for Schema
body: <p>I am building a user registration system in ASP.NET with a PostgreSQL database to maintain the user information.  As a part of the registration process, the user is sent a confirmation message in which they must click the link to validate their e-mail address.  This then takes them to a page where they can create their password.</p>
  
  <p>Once the user provides a password that meets some basic criteria for security, the Web application runs a couple of PostgreSQL stored procedures (functions) to first create the user role in the database and put them into a user group, then create a record in a database with the user's "profile" details (first and last name, e-mail address, etc.).</p>
  
  <p>The first of these stored procedures - the one that creates the user role - runs just fine.  Then, the application disconnects from the database and reconnects as the newly created user to run the second stored procedure to create the profile record.  However, this is where the application fails, returning the above mentioned error <code>42501: Permission denied for schema...</code></p>
  
  <p>I have verified that the user group in which the new user is being created has been given <code>USAGE</code> permission on the schema, and gone over all of the permissions for each of the affected objects in the database (the profile table and the stored procedure), and everything appears to look correct, but I can't get my Web application to create the new "profile" record.</p>
  
  <p>For reference, here are the two stored procedures (redacted):</p>
  
  <p><strong>1) CREATE THE DATABASE USER ROLE</strong> (This works correctly and the user is created)</p>
  
  <pre><code>CREATE OR REPLACE FUNCTION "SP_CreateUser"("User" character varying, "Pass" character varying)
    RETURNS boolean AS
  $BODY$DECLARE success boolean;
  BEGIN
  EXECUTE 'CREATE USER ' || quote_ident($1) || ' PASSWORD ' || quote_literal($2);
  EXECUTE 'GRANT systemusers TO ' || quote_ident($1);
  SELECT pg_roles.rolname = $1 INTO success FROM pg_roles WHERE pg_roles.rolname = $1;
  RETURN success;
  END$BODY$
    LANGUAGE plpgsql VOLATILE SECURITY DEFINER
    COST 100;
  ALTER FUNCTION "SP_CreateUser"(character varying, character varying)
    OWNER TO administrators;
  GRANT EXECUTE ON FUNCTION "SP_CreateUser"(character varying, character varying) TO administrators;
  GRANT EXECUTE ON FUNCTION "SP_CreateUser"(character varying, character varying) TO systemusers;
  REVOKE ALL ON FUNCTION "SP_CreateUser"(character varying, character varying) FROM public;
  </code></pre>
  
  <p><strong>2) CREATE THE "PROFILE" RECORD</strong> (This fails with <code>Error 42501</code> when the Web application connects to the database as the newly created user)</p>
  
  <pre><code>CREATE OR REPLACE FUNCTION website."SP_CreateProfile"("EmailAddress" character varying, "FirstName" character varying, "LastName" character varying, "PhoneNumber" character varying)
    RETURNS boolean AS
  $BODY$DECLARE success boolean;
  BEGIN
  INSERT INTO website.profiles ("UserEmail", "FirstName", "LastName", "AdministrativeUser", "Active", "PhoneNumber")
  VALUES ($1, $2, $3, FALSE, TRUE, $4);
  SELECT p."UserEmail" = $1 INTO success FROM website.profiles p WHERE p."UserEmail" = $1;
  RETURN success;
  END$BODY$
    LANGUAGE plpgsql VOLATILE
    COST 100;
  ALTER FUNCTION website."SP_CreateProfile"(character varying, character, character varying, character varying, character varying, character varying)
    OWNER TO administrators;
  GRANT EXECUTE ON FUNCTION website."SP_CreateProfile"(character varying, character, character varying, character varying, character varying, character varying) TO administrators;
  GRANT EXECUTE ON FUNCTION website."SP_CreateProfile"(character varying, character, character varying, character varying, character varying, character varying) TO systemusers;
  REVOKE ALL ON FUNCTION website."SP_CreateProfile"(character varying, character, character varying, character varying, character varying, character varying) FROM public;
  </code></pre>
  
  <p>You may note that I didn't set the second stored procedure with <code>SECURITY DEFINER</code>.  That was intentional, as I'd prefer the function run with the individual's security credentials.  However, in my testing, even if I've turned on <code>SECURITY DEFINER</code>, I still get the same "permission denied" error.</p>
  
  <p>So, the question now is this: What am I overlooking?  I feel like I've tested about every permutation of permission settings, but I've obviously missed something in the process.  Thanks for your help.</p>