Postgres: how to declare user type variable? - postgresql

I want to write a small script to grant permissions. The script works if I type in the user directly into each query but it's more efficient to use a variable but I cannot find what type to declare it as.
DO $$
DECLARE
usr ??? := myuser;
BEGIN
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA public
TO usr;
GRANT ALL PRIVILEGES ON SCHEMA public to usr;
END $$

You need dynamic SQL for that:
DO
$$DECLARE
usr text := 'myuser' ;
BEGIN
EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE '
'ON ALL TABLES IN SCHEMA public '
'TO %I',
usr);
END;$$;
The second statement works similarly.

Related

GRANT statements with bound parameters

I'm using a client library that only accepts SQL strings that are compile-time constant, in order to prevent SQL injection attacks. And I wanted to execute some GRANT statements for a set of tables and a user.
I tried
GRANT SELECT ON $1 TO $2
and passing the table and user names as bound parameters. But that fails with
syntax error at or near "$1"
Not being able to pass in a tablename as a bound parameter is understandable (you can't use SELECT columns FROM $1 for instance), and with a bit of work, I can make the tablenames compile-time constants. But changing the command to
GRANT SELECT ON MyTable to $1
and passing just the username as a bound parameter also fails. Which is more of an issue: whereas the tablenames can be hard-coded with a bit of work, the username is only known at runtime.
Is there a way to pass the username as a bound parameter, or do I need to bypass my client library in order to GRANT permissions to a run-time-defined username?
CREATE OR REPLACE FUNCTION test_grant (_role text)
RETURNS void
AS $$
DECLARE
_sql text := '';
BEGIN
_sql := 'GRANT SELECT ON a to ' || quote_ident(_role) || ' GRANTED BY current_user ';
RAISE NOTICE '%', _sql;
EXECUTE _sql;
RAISE NOTICE '% granted table a to %', CURRENT_USER, _role;
END
$$
LANGUAGE plpgsql
STRICT.
You can also make the table as function input argument. quote_ident is used for identifiers quoting. In GRANT SELECT ON MyTable to $1 you hope to make sure $1 is a identifiers rather than some string. Because if $1 string then the whole command can be:
GRANT SELECT ON MyTable to public;
GRANT SELECT ON MyTable to role_a WITH GRANT OPTION;
So the above function can solve these problem.
The only statements that can use parameters are INSERT, UPDATE, DELETE and SELECT. GRANT cannot use parameters; you will have to build a statement dynamically.

Specify schema user when creating an Oracle SQL DBMS job

I want to create a dbms_job as a sys user and the schema user of this job should be schemaA.
I have tried alter session set current_schema=schemaA, but that did not work. I still get sys as the schema user.
DECLARE jobno numeric;
Next_Date Date;
next_interval varchar2(20);
BEGIN
select SYSDATE+1 into Next_Date from dual;
dbms_job.submit(jobno,'<pl/sql code>',next_date,'FREQ=minutely;BYMINUTE=0,10,20,30,40,50;BYSECOND=0'); COMMIT; END;
/

How to change password of a newly created user using variable in postgresql 9.5 SP

I have created a stored procedure (function) for my postgresql 9.5 database to create users. code below:
CREATE FUNCTION add_user (name text, cred text) RETURNS void AS $$
DECLARE
name text := 'abc123';
BEGIN
CREATE USER name WITH LOGIN NOSUPERUSER INHERIT NOCREATEDB
NOCREATEROLE NOREPLICATION;
GRANT CONNECT ON DATABASE test TO name;
GRANT USAGE ON SCHEMA test_schema TO name;
GRANT SELECT ON test_schema.test_table TO name;
ALTER USER name WITH PASSWORD cred;
END;
$$ LANGUAGE plpgsql;
This fails for altering password for the user. The moment I replace "cred" with hardcoded password, it works.
So, ALTER USER name WITH PASSWORD 'userpassword' works,
but NOT with any variable (cred).
Is there anyway we can use variable instead of hard coding the password?
Tried running another function, just for password
it does not work because the user is called "name", it does not take parameter value
As I mentioned before, you must do it dynamically all the code to create and grant
the function should look like this:
CREATE or REPLACE FUNCTION add_user (name text, cred text) RETURNS void AS $$
DECLARE
name_temp text := 'abc123';
BEGIN
EXECUTE ' CREATE USER '|| $1 ||' WITH LOGIN NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE NOREPLICATION';
EXECUTE ' GRANT CONNECT ON DATABASE test TO ' || $1;
EXECUTE ' GRANT USAGE ON SCHEMA test_schema TO '|| $1;
EXECUTE 'GRANT SELECT ON test_schema.test_table TO '|| $1;
EXECUTE 'ALTER USER ' || $1 || ' WITH PASSWORD '''|| $2||'''';
END;
$$ LANGUAGE plpgsql;
I recommend using the format function to form the texts of CREATE, GRANT and ALTER, for safety issues, example:
EXECUTE format(' GRANT CONNECT ON DATABASE test TO %I ', $1);
other point, consider variable name diferent of parameter name
thist function work for me
You must execute the ALTER USER with dynamic SQL, for example:
EXECUTE 'ALTER USER || name || ' WITH PASSWORD '|| cred;
I believe that you must execute dynamic SQL in whole code of CREATE and GRANT commands, because I think always will create the user called "name"

Postgres function using DDL statement

I am trying to create function in Postgres which can automate user creation process but it doesn;t accept parameter in DDL statement.
CREATE OR REPLACE FUNCTION AUTOUSER (uname varchar(20))
RETURNS TEXT AS $$
DECLARE
nm varchar(20);
BEGIN
nm=$1;
CREATE USER nm WITH PASSWORD 'Iash12';
GRANT ALL ON DATABASE iashdb TO nm;
GRANT ALL ON ALL TABLES IN SCHEMA public TO nm;
RETURN CONCAT(nm,' Created');
END;
$$
LANGUAGE plpgsql;
Above function create user as 'nm' instead of passed parameter name however RETURN statement showing correct result. Thanks in advance,
You need to use dynamic SQL and you need to quote the parameters properly. The easiest way is to use the format() function with the appropriate placeholders:
CREATE OR REPLACE FUNCTION AUTOUSER (uname varchar(20))
RETURNS TEXT AS $$
BEGIN
execute format('CREATE USER %I WITH PASSWORD %L', uname, 'Iash12');
execute format('GRANT ALL ON DATABASE iashdb TO %I', uname);
execute format('GRANT ALL ON ALL TABLES IN SCHEMA public TO %I', uname);
RETURN CONCAT(uname,' Created');
END;
$$
LANGUAGE plpgsql;
The placeholder %I properly quotes SQL identifiers. The placeholder %L properly deals with string literals.

PL/pgSQL anonymous code block

In PostgreSQL 9.0 I have this PLPGSQL anonymous code block:
DO $$
DECLARE
bigobject integer;
BEGIN
SELECT lo_creat(-1) INTO bigobject;
ALTER LARGE OBJECT bigobject OWNER TO postgres;
INSERT INTO files (id, "mountPoint", data, comment) VALUES (15, '/images/image.png', bigobject, 'image data');
SET search_path = pg_catalog;
SELECT pg_catalog.lo_open(bigobject, 131072);
SELECT pg_catalog.lowrite(0, '\\x000001000100101010000000000028010000160000002800000010000000200000000100040');
SELECT pg_catalog.lo_close(0);
REVOKE ALL ON LARGE OBJECT bigobject FROM PUBLIC;
REVOKE ALL ON LARGE OBJECT bigobject FROM postgres;
GRANT ALL ON LARGE OBJECT bigobject TO postgres;
GRANT ALL ON LARGE OBJECT bigobject TO "com.ektyn.eshops.myuser";
END
$$;
but it fails:
ERROR: syntax error at or near "bigobject"
LINE 6: ALTER LARGE OBJECT bigobject OWNER TO postgres;
^
********** Error **********
ERROR: syntax error at or near "bigobject"
SQL state: 42601
Character: 103
and I can't find mistake in code.
There must be an oid constant in ALTER LARGE OBJECT oid .... Try this workaround:
DO $$
DECLARE
bigobject integer;
BEGIN
SELECT lo_creat(-1) INTO bigobject;
EXECUTE 'ALTER LARGE OBJECT ' || bigobject::text || ' OWNER TO postgres';
...
The same also applies to GRANT and REVOKE, of course.
In addition to what #klin already cleared up, you cannot use SELECT without a target in PL/pgSQL code. Replace it with PERFORM in those calls.
Aside: Using "com.ektyn.eshops.myuser" as name for a role is a terrible idea. Use legal, lower case identifiers that don't have to be double-quoted.
This is an artifact of the fact that PostgreSQL has two completely different kinds of SQL statements internally - plannable (SELECT, INSERT, UPDATE, and DELETE) and unplannable (everything else) statements.
Only plannable statements support query parameters.
PL/pgSQL implements variable substitutions into statements, like your bigobject, using query parameters.
Because they aren't supported for non-plannable statements, no substitution is performed. So PL/pgSQL tries to execute the statement literally, as if you'd typed:
ALTER LARGE OBJECT bigobject OWNER TO postgres;
directly at the psql prompt. It does not detect this as an error.
To work around this, use EXECUTE ... FORMAT, e.g.
EXECUTE format('ALTER LARGE OBJECT %s OWNER TO postgres', bigobject);
See this related answer about COPY.