SQL-Macros and Invoker Rights

This note is meant more as an illustrative example for a question, because the behavior seems strange to me. If I want to do something in my SQL macro that needs additional privileges, how it will run then, when other users will call my SQL macro?

That is what you can read in Oracle documentation about SQL_Macro Clause

How I read this: I cannot specify AUTHID CURRENT_USER, but it will anyway run with invoker rights. It is just supposed to always do so.

Let’s test it. I’ll create two users: definer_user and invoker_user

SQL> drop user if exists invoker_user cascade;
SQL>
SQL> create user if not exists invoker_user identified by oracle;
SQL>
SQL> grant create session to invoker_user;
SQL>
SQL>
SQL> drop user if exists definer_user cascade;
SQL>
SQL> create user if not exists definer_user identified by oracle quota unlimited on users;
SQL>
SQL> grant create session, create table, create procedure to definer_user;
SQL>

As you can see, the invoker_user has no privileges except create session. Now let’s create a table as definer_user and use it inside a SQL macro. I will also do the same with a normal function (no SQL macro) but defined as invoker rights function (AUTHID CURRENT_USER). I expect the behavior to be more or less the same.

connect definer_user/...@localhost:1522/freepdb1

create table col_config (column_name varchar2(128 byte));

insert into col_config (column_name) values ('ENAME');

-- a sql macro function
create or replace function get_column_macro return varchar2 
sql_macro(scalar) as
    v_column_name dbms_id;
begin
    select column_name into v_column_name from col_config;
    return  ''''||v_column_name||'''';
end;
/

-- a normal but invoker-rights function
create or replace function get_column_no_macro return varchar2 
authid current_user as
    v_column_name dbms_id;
begin
    select column_name into v_column_name from col_config;
    return  ''''||v_column_name||'''';
end;
/

grant execute on get_column_macro to invoker_user;

grant execute on get_column_no_macro to invoker_user;

Now, the invoker_user only has the right to execute both functions, but no privileges on the table col_config which belongs definer_user. That’s why I expect a “table or view doesn’t exist” error while executing both functions as invoker_user. But see what happens: only “no-macro” function behaves so! Our SQL macro was executed without an error:

SQL> connect invoker_user/...@localhost:1522/freepdb1
SQL>
SQL> select definer_user.get_column_no_macro;

Error starting at line : 1 in command -
select definer_user.get_column_no_macro
Error at Command Line : 1 Column : 8
Error report -
SQL Error: ORA-00942: table or view does not exist
ORA-06512: at "DEFINER_USER.GET_COLUMN_NO_MACRO", line 5
00942. 00000 -  "table or view%s does not exist"
*Cause:    The specified table or view did not exist, or a synonym
           pointed to a table or view that did not exist.
           To find existing user tables and views, query the
           ALL_TABLES and ALL_VIEWS data dictionary views. Certain
           privileges may be required to access the table. If an
           application returned this message, then the table that the
           application tried to access did not exist in the database, or
           the application did not have access to it.
*Action:   Check each of the following
           - The spelling of the table or view name is correct.
           - The referenced table or view name does exist.
           - The synonym points to an existing table or view.

More Details :
https://docs.oracle.com/error-help/db/ora-00942/
https://docs.oracle.com/error-help/db/ora-06512/
SQL>
SQL> select definer_user.get_column_macro;

GET_COLUMN_MACRO
___________________
ENAME
SQL>

This tells me, my SQL macro was indeed executed with definer rights!

Another thing I don’t really understood is the second sentence from the above documentation quote: “The SQL macro owner must grant inherit privileges to the invoking function.” As far as I know INHERIT PRIVILEGES is about granting it from high-privileged user to a user who creates an invoker-right program units. But in this case it makes no sense to me… And what is invoking function? Even if knew that and wanted to grant INHERIT PRIVILEGES to this function, how can i do this? I thought, it is only possible to grant roles to program units, not system privileges?

Maybe I am missing something or it is just a bug or a documentation bug or both . All comments are welcome!

UPDATE:

Thanks, Chris Saxon for the answer. The behavior we could see above is indeed intended. The body of a SQL Macro runs with definer privileges:

Leave a Reply

Your email address will not be published. Required fields are marked *