Can I set a user which can read one database and read/write another database in clickhouse - readonly

Clickhouse offical document implies one user can only have one profile, and database is configured in user section, readonly is configured in profile section, so, readonly will effect on all user's database.
So, how can I set a user x which only can read database dbA, but can read and write database dbB?

Consider using the SQL-driven access control management:
Prepare test environment:
CREATE DATABASE db_01;
CREATE DATABASE db_02;
CREATE TABLE db_01.table_01 (id Int32) Engine = Memory();
CREATE TABLE db_02.table_02 (id Int32) Engine = Memory();
INSERT INTO db_01.table_01 VALUES (1), (2);
INSERT INTO db_02.table_02 VALUES (10), (20);
Create user and assign the required privileges:
CREATE USER user_01 HOST ANY PROFILE 'default';
/* Set readonly access to DB 'db_01'. */
GRANT SELECT ON db_01.* TO user_01;
/* Set read-write access to DB 'db_02'. */
GRANT SELECT ON db_02.* TO user_01;
GRANT INSERT ON db_02.* TO user_01;
Test (need to login as user_01):
SELECT currentUser(); /* Make sure that user is right. */
/*
┌─currentUser()─┐
│ user_01 │
└───────────────┘
*/
SHOW GRANTS; /* Double check the assigned privileges. */
/*
┌─GRANTS─────────────────────────────────────┐
│ GRANT SELECT ON db_01.* TO user_01 │
│ GRANT INSERT, SELECT ON db_02.* TO user_01 │
└────────────────────────────────────────────┘
*/
SELECT * FROM db_01.table_01; /* OK */
INSERT INTO db_01.table_01 VALUES (3); /* DB::Exception: user_01: Not enough privileges. */
SELECT * FROM db_02.table_02; /* OK */
INSERT INTO db_02.table_02 VALUES (30); /* OK */
The code above is just for the demo, you need to consider introduce roles/quotas/.., inherit another user-profile (more restrictive, not 'default') etc.

Related

How to select all DML statement done to a table

With this query, I can see which table where modified last hour.
select * from ALL_TAB_MODIFICATIONS where timestamp> sysdate-1/24
Now I want to know what has been insert, updates, deletes in a table. And if possible with the user id.
How do I do that?
I've tried to use audit.
https://www.ibm.com/docs/en/svgaa?topic=c-enabling-auditing-oracle-resource
in sqlplus
SHOW PARAMETER AUDIT_TRAIL
DB --OK
AUDIT ALL BY SEV BY ACCESS
audit succeeded
I've tried to see the content of all the audit table (SELECT view_name FROM dba_views WHERE view_name LIKE 'DBA%AUDIT%';)
for instance :
select * from dba_audit_exists;
but they are empty

How to check if table has specific grants before inserting a record in a table?

Scenario: I have a config table which includes meta-data about log tables (e.g. Table_name, table_owner). I want to add a trigger to this config table which essentially checks if the table record that is to be inserted, has the specific grant (delete) if not, then don't allow that to happen. How can I go about this?
Another way to do it is to forget about triggers but use a VIEW...WITH CHECK OPTION to control that no one inserts data they shouldn't.
Suppose your config table looks like this:
CREATE TABLE my_config
( owner VARCHAR2(30) NOT NULL,
table_name VARCHAR2(30) NOT NULL,
other_stuff VARCHAR2(500),
CONSTRAINT my_config_pk PRIMARY KEY ( owner, table_name ) );
Create a view to handle inserts
The conditions of the view limit it to only include tables on which the current user has DELETE privileges.
The WITH CHECK OPTION will ensure than no one may use the view to insert or update data that does not satisfy the view.
CREATE VIEW my_config_ins_v
AS
SELECT * FROM my_config c
WHERE EXISTS ( SELECT 'user has delete privs'
FROM user_tab_privs p
WHERE p.owner = c.owner
AND p.grantee = user
AND p.table_name = c.table_name
AND p.privilege = 'DELETE' )
WITH CHECK OPTION;
Try it out
INSERT INTO my_config_ins_v VALUES ('USER_1','TABLE_I_HAVE_ACCESS_TO', 'STUFF');
-- 1 row inserted.
INSERT INTO my_config_ins_v VALUES ('SYS','OBJ$', 'STUFF');
-- ORA-01402: view WITH CHECK OPTION where-clause violation
Naturally, for this to be effective, you cannot
GRANT INSERT ON my_config TO anyone; -- don't do this
Instead:
GRANT INSERT ON my_config_ins_v TO anyone;

Creation of Oracle temporary table with same table structure to that of a existing table

How to create a global temporary table with same table structure to that of a existing table?
I know this concept is available in SQL server like "select * into #temp123 from abc". But I want to perform the same in Oracle.
Create global temporary table mytemp
as
select * from myTable
where 1=2
Global temporary tables in Oracle are very different from temporary tables in SQL Server. They are permanent data structures, it is merely the data in them which is temporary (limited to the session or transaction, depending on how a table is defined).
Therefore, the correct way to use global temporary tables is very different to how we use temporary tables in SQL Server. The CREATE GLOBAL TEMPORARY TABLE statement is a one-off exercise (like any other table). Dropping and recreating tables on the fly is bad practice in Oracle, which doesn't stop people wanting to do it.
Given the creation of a global temporary table should a one-off exercise, there is no real benefit to using the CREATE TABLE ... AS SELECT syntax. The statement should be explicitly defined and the script stored in source control like any other DDL.
You have tagged your question [oracle18c]. If you are really using Oracle 18c you have a new feature open to you, private temporary tables, which are closer to SQL Server temporary tables. These are tables which are genuinely in-memory and are dropped automatically at the end of the transaction or session (again according to definition). These are covered in the Oracle documentation but here are the headlines.
Creating a private temporary table data with a subset of data from permanent table T23:
create table t23 (
id number primary key
, txt varchar2(24)
);
insert into t23
select 10, 'BLAH' from dual union all
select 20, 'MEH' from dual union all
select 140, 'HO HUM' from dual
/
create private temporary table ORA$PTT_t23
on commit preserve definition
as
select * from t23
where id > 100;
The ORA$PTT prefix is mandatory (although it can be changed by setting the init.ora parameter PRIVATE_TEMP_TABLE_PREFIX, but why bother?
There after we can execute any regular DML on the table:
select * from ORA$PTT_t23;
The big limitation is that we cannot use the table in static PL/SQL. The table doesn't exist in the data dictionary as such, and so the PL/SQL compiler hurls - even for anonymous blocks:
declare
rec t23%rowtype;
begin
select *
into rec
from ORA$PTT_t23';
dbms_output.put_line('id = ' || rec.id);
end;
/
ORA-06550: line 6, column 10: PL/SQL: ORA-00942: table or view does not exist
Any reference to a private temporary table in PL/SQL must be done with dynamic SQL:
declare
n pls_integer;
begin
execute immediate 'select id from ORA$PTT_t23' into n;
dbms_output.put_line('id = ' || n);
end;
/
Basically this restricts their usage to SQL*Plus (or sqlcl scripts which run a series of pure SQL statements. So, if you have a use case which fits that, then you should check out private temporary tables. However, please consider that Oracle is different from SQL Server in many aspects, not least its multi-version consistency model: readers do not block writers. Consequently, there is much less need for temporary tables in Oracle.
In the SQL Server's syntax the prefix "#" (hash) in the table name #temp123 means - create temporary table that is only accessible via the current session ("##" means "Global").
To achive exactly the same thing in Oracle you can use private temporary tables:
SQL> show parameter private_temp_table
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
private_temp_table_prefix string ORA$PTT_
create table mytab as
select 1 id, cast ('aaa' as varchar2 (32)) name from dual
;
create private temporary table ora$ptt_mytab on commit preserve definition as
select * from mytab where 1=0
;
Private TEMPORARY created.
Afterwards you can use these tables in SQL and PL/SQL blocks:
declare
r mytab%rowtype;
begin
insert into ora$ptt_mytab values (2, 'bbb');
select id + 1, name||'x' into r from ora$ptt_mytab where rownum = 1;
insert into ora$ptt_mytab values r;
end;
/
select * from mytab
union all
select * from ora$ptt_mytab;
ID NAME
---------- --------------------------------
1 aaa
2 bbb
3 bbbx
Some important restrictions on private temporary tables:
The name must always be prefixed with whatever is defined with the parameter PRIVATE_TEMP_TABLE_PREFIX. The default is ORA$PTT_.
You cannot reference PTT in the static statements of the named PL/SQL blocks, e.g. packages, functions, or triggers.
The %ROWTYPE attribute is not applicable to that table type.
You cannot define column with default values.

No audit results

I have been testing audit area in Oracle 11g. Unfortunately, after I go through below-described steps, I get no results in audit tables. I am connected to the database as store. Why is that?
GRANT AUDIT SYSTEM TO store;
GRANT AUDIT ANY TO store;
AUDIT CREATE ANY TABLE BY store;
CREATE TABLE test_mj_aud(
id INTEGER);
INSERT INTO test_mj_aud
VALUES (1);
COMMIT;
SELECT * FROM test_mj_aud;
SELECT * FROM user_audit_trail; --no results
SELECT * FROM db_audit_trail; --no results

Run Oracle function without access to underlying table

I have a simple function created in Oracle database
taken from https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5009.htm
CREATE FUNCTION get_bal(acc_no IN NUMBER)
RETURN NUMBER
IS acc_bal NUMBER(11,2);
BEGIN
SELECT order_total
INTO acc_bal
FROM orders
WHERE customer_id = acc_no;
RETURN(acc_bal);
END;
/
This is created by user A
I want to
GRANT EXECUTE ON FUNCTION GET_BAL TO USER B
But user B does not have access to underlying table ORDERS
Will user B still be execute the function or will he need access to the underlying table as well?
Thanks
P

Resources