I am writing a query that will return
if a table or stored proc exists within a database
if a particular role has been assignned execute permissions to execute that particular stored proc.
I guess I need to query the master database and wiggle thru that to get to the database and the table or stored proc that I am looking for. How can I get a 'true / false' if execute permissions have been assigned to a particular role on that object?
USE YourDatabase
/*To find out if it exists*/
SELECT OBJECT_ID('dbo.spFoo') /*Will be NULL if it doesn't exist or you don't have
permission to see the object*/
/*To find out the permissions on it take a look at the following system views*/
select * from sys.database_permissions p
inner JOIN sys.database_principals dp
on p.grantee_principal_id = dp.principal_id
where major_id=object_id('dbo.spFoo')
Related
There is a table in redshift, which is causing a problem to complete a run as it has huge data set. So I need to replace the table with another table. This table is present in few stored procedure code. But here is a challenge. There are around 300+ stored procedure in the database. So, anyone please help me to write with a query, like what are list of procedures that using the particular table.
You could query the catalog pg_proc like this to find out if <particular table> is used in a stored procedure:
SELECT n.nspname as schema_name,
u.usename as sp_owner,
p.proname as stored_procedure_name,
p.prosrc as procedure_source
FROM pg_catalog.pg_namespace n
JOIN pg_catalog.pg_proc p ON pronamespace = n.oid
JOIN pg_catalog.pg_user u on u.usesysid = p.proowner
where prosrc like '%<particular table>%';
Or you could use PG_PROC_INFO, a Redshift system view built on the PostgreSQL catalog table PG_PROC and the internal catalog table PG_PROC_EXTENDED.
Is it possible to grant select permission on sql table with some conditions.
For example grant select where table.id = < 50
supplemented: i am talking about ms sql
It's not possible directly.
Though to achieve this task, you can create a View initially with required conditions and then Grant select permission to that particular view.
For more details:
mysql GRANT + WHERE
Aer, you haven't said anything about DB engine (which one you are using: Oracle / MS SQL Server / MySQL etc.).
In Oracle for instance you are Granting / Revoking privileges to specific object, and there is no way to limit the output result (with out of the box GRANT statement).
In SQL Server you are able to grant row-level permissions for individual users with some additional effort: https://msdn.microsoft.com/en-us/library/bb669076(v=vs.110).aspx
Example:
CREATE SCHEMA Security
GO
CREATE FUNCTION Security.userAccessPredicate(#UserName sysname)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS accessResult
WHERE #UserName = SUSER_SNAME()
GO
CREATE SECURITY POLICY Security.userAccessPolicy
ADD FILTER PREDICATE Security.userAccessPredicate(UserName) ON dbo.MyTable,
ADD BLOCK PREDICATE Security.userAccessPredicate(UserName) ON dbo.MyTable
GO
enter code here
CREATE VIEW vw_MyTable
AS
RETURN SELECT * FROM MyTable
WHERE UserName = SUSER_SNAME()
GO
In general from the concept perspective if you want to limit users to only certain amount of rows you should do the following:
The basic way would be :
Prevent users (or group) from accessing the base table.
Define a view on top of that table that shows only the rows these users are supposed to see.
Give users SELECT permission on the view.
I am connected to a oracle database with a read only user and i used service name while Setting up connection in sql developer hence i dont know SID ( schema ).
How can i find out schema name which i am connected to ?
I am looking for this because i want to generate ER diagram and in that process at one step it asks to select schema. When i tried to select my user name , i dint get any tables as i guess all tables are mapped with schema user.
Edit: I got my answer partially by the below sql Frank provided in comment , it gave me owner name which is schema in my case. But I am not sure if it is generic solution applicable for all cases.
select owner, table_name from all_tables.
Edit: I think above sql is correct solution in all cases because schema is owner of all db objects. So either i get schema or owner both are same. Earlier my understanding about schema was not correct and i gone through another question and found schema is also a user.
Frank/a_horse_with_no_name Put this in answer so that i can accept it.
Call SYS_CONTEXT to get the current schema. From Ask Tom "How to get current schema:
select sys_context( 'userenv', 'current_schema' ) from dual;
To create a read-only user, you have to setup a different user than the one owning the tables you want to access.
If you just create the user and grant SELECT permission to the read-only user, you'll need to prepend the schema name to each table name. To avoid this, you have basically two options:
Set the current schema in your session:
ALTER SESSION SET CURRENT_SCHEMA=XYZ
Create synonyms for all tables:
CREATE SYNONYM READER_USER.TABLE1 FOR XYZ.TABLE1
So if you haven't been told the name of the owner schema, you basically have three options. The last one should always work:
Query the current schema setting:
SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL
List your synonyms:
SELECT * FROM ALL_SYNONYMS WHERE OWNER = USER
Investigate all tables (with the exception of the some well-known standard schemas):
SELECT * FROM ALL_TABLES WHERE OWNER NOT IN ('SYS', 'SYSTEM', 'CTXSYS', 'MDSYS');
How about the following 3 statements?
-- change to your schema
ALTER SESSION SET CURRENT_SCHEMA=yourSchemaName;
-- check current schema
SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL;
-- generate drop table statements
SELECT 'drop table ', table_name, 'cascade constraints;' FROM ALL_TABLES WHERE OWNER = 'yourSchemaName';
COPY the RESULT and PASTE and RUN.
I have table 'stf_table' under the schema 'staff' with username 'staff'.
I have table 'emp_table' under the schema 'employee' with username 'employee'.
Both of these are under the same database SID/host/port but user 'staff' doesn't have privelege to query tables under schema 'employee' and vice versa (ie. user 'employee' doesn't have privelege to query tables under schema 'staff'). But each user can query the table under their own schema. Note: I cannot grant extra privileges and I don't want to have to dump both tables into a local schema.
Is it possible to write a PL/SQL proc or package that would do the following?
select count(*) from stf_table;
select count(*) from emp_table;
then output both counts to a file (ie a .txt or .dat not concerned) like so:
stf_table count: 47830
emp_table count: 36462
difference: 11368
counts match: FALSE
If you don't want to grant additional privileges to either user, you don't have many options.
You can create a procedure owned by a super user, say an account which has SELECT ANY TABLE, (but not SYS or SYSTEM) which does both counts and calculates the difference.
create function get_diff
return pls_integer
authid definer
as
c1 pls_integer;
c2 pls_integer;
begin
select count(*)
into c1
from staff.stf_table;
select count(*)
into c2
from employee.emp_table;
return abs(c1-c2);
end get_diff;
/
So the crucial thing here is the AUTHID DEFINER. That means the function runs with the permissions of the user who owns the function; because they have the neecssary permissions to query both tables that user can run the function, and so can any other user to whom they grant EXECUTE ON GET_DIFF.
That really is the minimum about of granting you can get away with.
NB: I haven't addressed the question of writing to a file, because I don't really think that's the thrust of your question. The main thing is permissions.
"Is there no way that the proc could connect as user 'staff' save the
count to a file. then connect as user 'employee' save the count to the
same file and compare?"
No. That's not the way the security model works.
STAFF's data is owned by STAFF and EMPLOYEE's data is owned by EMPLOYEE. By default, STAFF cannot see EMPLOYEE's data and vice versa. To change this situation you have two options:
Have STAFF grant SELECT on their table to EMPLOYEE and have EMPLOYEE grant SELECT on their table to STAFF.
Use an account which has privileges on both schemas' tables to do the work.
Obviously, there may well be data protection issues with the first approach. If that is your concern there are some refinements open to you:
Have each schema own a view which just selects a count of their records, and grant privileges on the views.
If you have Enterprise Edition 10gR2 or higher, you can use column-level VPD: grant select on the table put put a policy in place to hide all the sensitive data. Find out more.
Granting permissions is the correct thing to do however as you state this is not possible:
one solution could be to do it at the command line using scripts.
(the biggest drawback is the username & password would be embedded in the script for all to see, so make sure the scripts are appropriately secured)
first create 2 scripts:
a.sql:
set timing off
set feedback off
set pages 0
select count(*) from stf_table;
exit
b.sql:
set timing off
set feedback off
set pages 0
select count(*) from emp_table;
exit
now create a script file extract.bat to get the output:
#echo off
FOR /F "usebackq delims=!" %%i IN (`sqlplus -s username/password#db_a #a.sql`) DO set resulta=%%i
FOR /F "usebackq delims=!" %%i IN (`sqlplus -s username/password#db_b #b.sql`) DO set resultb=%%i
set /a diff=%resulta%-%resultb%
echo stf_table count %resulta%
echo emp_table count %resultb%
echo difference %diff%
IF %diff%=0 (
echo Counts match TRUE
) ELSE (
echo Counts match FALSE)
now simply execute extract.bat at the command prompt
APC is right in that you can't solve this problem easily without granting additional permissions. There might be a simpler way than what he is suggesting.
I would suggest creating a view and granting access to that view to the other schema.
In the STAFF schema you can create a view stf_table_count:
create or replace view stf_table_count
as
select count(*) as num_rows
from stf_count;
Then grant select on that view to the employee schema:
grant select on stf_table_count to employee;
Then from the employee schema you can find the result without getting the data
select num_rows from staff.stf_table_count
union all
select count(*) from emp_table;
You can also repeat this process to get the employee counts in the staff schema.
I'm not really an Oracle database security expert so your mileage may vary on this answer but I think it should work.
What is the SQL to delete a SQL User from a database?
DROP USER [UserName]
You can prefix this with an existence check if required.
IF EXISTS (SELECT * FROM sys.database_principals WHERE name = N'UserName')
There are some requirements to be met before dropping Users (e.g. they can't own any objects). Full Details here.