data extraction from oracle source - oracle

I am trying to extract data from oracle source using pyspark.
I am using this code.
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('Spark_Job').getOrCreate()
driver = 'oracle.jdbc.driver.OracleDriver'
url = 'jdbc:oracle:thin:#XXXXXXXXXXXXXXXXXX/XXX'
user = 'XXXXX'
password = 'XXXXXXXX'
query = 'SELECT col_1 from schema_1.view_1'
df = spark.read.format('jdbc').option('driver', driver).option('url', url).option('dbtable', query)\
.option('user', user).option('password', password).load()
df.show(10)
I am getting this error :
java.sql.SQLSyntaxErrorException: ORA-00903: invalid table name

ORA-00903 means that you tried to use table name, but - that table doesn't exist.
There's only one select statement here:
SELECT col_1 from schema_1.view_1
-------- ------
owner table (or view) name
("user")
Info you posted suggests that you're connected as
user = 'XXXXX'
If view_1 belongs to currently connected user, you don't have to specify owner name so query would then be just select col_1 from view_1.
If view_1 belongs to currently connected user, then view_1 must be correctly spelled. Oracle doesn't care about letter case unless you decided to enclose its (table's, view's) name into double quotes and used lower or mixed case - then you have to do it every time you reference that table, so query might be e.g. select col_1 from "View_1".
If view_1 belongs to user who is different from currently logged user (that's what information you posted suggests), then yes - preceding table's name with its owner's name is the way to do it. However, schema_1 (the owner) has to grant at least select privilege on view_1 to XXXXX - otherwise, it won't work. (Double quotes/letter case issue still stands.)
I can't tell which situation of these you have, but now you have something to check and act appropriately.

Related

Informix - select from a table of another user

I have to do CRUD operations on a table that is not owned by the user I am using to connect to my Informix database. I have been granted the necessary privileges to do the operations, but I do not know how to do the actual query.
I have little experience with Informix, but I remember in OracleDB I had to do reference the shema like so:
SELECT * FROM SCHEMA.TABLE;
In Informix should I reference the user that owns the table ? Like :
SELECT * FROM OWNER:TABLE
Or can I just do :
SELECT * FROM TABLE
Thanks for any help !
In Informix you can generally use the table name without or without the owner prefix unless the database was created with mode ANSI in which case the owner prefix is required. Note that the correct syntax when using the owner is to use a period "." as in:
SELECT * FROM owner.table;
The colon is used to separate the database name as shown in the Informix Guide to SQL: Syntax https://www.ibm.com/docs/en/informix-servers/14.10?topic=segments-database-object-name#ids_sqs_1649
FYI you can determine if the database is mode ANSI with this query:
SELECT is_ansi FROM sysmaster:sysdatabases WHERE name = "<database name>";

Extract table names from oracle database server

I have access to an oracle11g server that blongs to a store and have a software to get reports inside softare but the software is closed source.
bacause i have a username inside database i can access from the software to all reports but i want to automate some works and want to write a python3 script to do that.all i need is that know the table names in DB. i want a code in oracle that returns me the table name.
I have access to database from "PLSQL Developer" and from my notcompleted code in python.
import cx_Oracle
con = cx_Oracle.connect('username/password#serveraddress/dbname')
print (con.version)
cur =con.cursor()
cur.execute(" SOME ORACLE CODE")
#cur.execute('select * from tablesname orderby id' )
for i in cur:
print (i)
con.close()
so what is a code that can execute and return table names to me?
p.s : i even used wireshark to find out what was the code that program sent to server but table names was not there in packet. :(
p.s 2 : any creative and unusual answer is welcome.
You can use
select table_name
from user_tables
order by table_name
or
select table_name
from cat
where table_type = 'TABLE'
order by table_name
to derive the names of all tables in your current user. Where cat is synonym of user_catalog data dictionary view and user_tables is another data dictionary view automatically created by database during installation.

Oracle : check for read/write privileges, automated testing

I have a question about Oracle and checking privileges.
Some background Info
I wrote some php scripts that will 'test' various things in our environment. One of those tasks is checking that a user has execute privileges on a procedure and that the procedure is valid/compiled.
Here is the query
select ao.object_name, utp.grantee, ao.status, utp.privilege
from all_objects ao, user_tab_privs utp
where utp.owner = ao.owner and
ao.object_name = utp.table_name and
upper( ao.object_name ) = :object_name and
ao.object_type = 'PACKAGE' and
utp.privilege = 'EXECUTE' and
ao.status = 'VALID'
This has worked well and has saved us time on procedure privileges; I do realize now that I can also double check the all_tab_privs to check execute access as well.
The problem
Now my question is, how do I do something similar with tables? We ran into an issue where a certain user had SELECT privs on a table but not UPDATE/INSERT privs. How can I check for each of these privileges individually. I've looked into all_tab_privs but haven't found it shows me what I want. It has procedures I can execute but when I check to see if a known table is there it isn't. For example, I'll run the following
select * from all_tab_privs
where table_name = 'KNOWN_TABLE' and
grantee = 'CURRENT_USER'
and privilege in ( 'SELECT', 'UPDATE', 'INSERT' );
but instead of getting back 3 rows for a table I know 100% that I can already select/insert/update it returns nothing.
Any ideas? Thank you.
Disclaimer
I am aware that I could just try inserting/updating data and then deleting it but I'd rather not do this. I'd rather not leave any trace since these scripts will run periodically, should be repeatable, and shouldn't alter the state of any piece of data, even if it's just a sequence on the table.
Also, if you could provide a 'list' of possible queries that I can use to determine privileges that would be fine. For example, to determine if i have select access run query 1, 2 and 3. If either returns data then you have select privs and so on for insert/update.
This looks rather optimistic to me, as the role issue could get really complex, particularly if roles ever get password protected, and I'd never really trust the method 100% without actually trying the DML.
It might be more simple to try queries such as:
select count(*)
from schema_name.table_name
where 1=0;
insert into schema_name.table_name
select *
from schema_name.table_name
where 1=0;
delete from schema_name.table_name
where 1=0;
update schema_name.table_name
set column_name = column_name
where 1=0;
I believe that such queries would fail if no privileges were granted (no database handy to check it), and they would never modify any data.
By the way, the ANY privileges are generally regarded as a security problem, so you might like to fail the system if any user is granted them.
If you have privileges granted via roles, you need a more complicated check. The link in comments gives some queries to use to look at the wider picture, but if you want to check what the current user can see - as one of your queries suggests - then you can query the session_roles view to see what object privileges are currently available to your session via roles, in addition to directly-granted object privileges:
select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
'Direct' as grant_type
from all_tab_privs atp
where atp.grantee = user
union all
select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
'Via role' as grant_type
from session_roles sr
join all_tab_privs atp on atp.grantee = sr.role;
You can obviously add filters if you want to look at a specific object or privilege, and the grant_type pseudo-column is just for info - not really that useful since you can compare grantee with user to get the same info I suppose.
You might want to look at session_privs as well, to check your user has any system privileges you expect.
But if you want a single query to check the privileges for another user or several users at once, you'll need something more like the linked queries, and the privileges necessary to run them.
I ended up solving this problem using a multi-step approach based around different queries and the results they brought back. I'm executing all the queries with some PHP code so it wasn't 100% necessary that I only have big query to solve it all.
Additionally, our databases are split up physically and they are linked together through database links so I had to do some additional work to make sure that this privilege checking worked across database links.
Currently I'm only checking for SELECT, DELETE, UPDATE, and INSERT privileges; that is all I need really for now.
The procedure
Here is the general procedure in a nut-list.
Get a list of all the database links available to the user.
For the following steps, start with the current database we are logged into and then check each database link retrieved from step 1.
2a. Check to see if the table is visible using a database query.
2b. If the table is visible, check to see if any of the permission queries return that this user has access to the table.
The queries
Here are the queries for each of the steps above.
1 Database links
select db_link from all_db_links
2a Table Visibility
select * from all_tables%DB_LINK% where table_name = :table_name and owner = :owner
The %DB_LINK% above is replaced by #db_link where applicable. If we are checking the current connection then I remove it entirely. Remember, the queries are being executed by a PHP script so I can do some string manipulation on the string to either remove the %DB_LINK% for the current database or replace it with one of the database links we got from step 1.
2b. Users, Roles, Tables
There are 4 queries all together here.
/*****/
/* 1 */
/*****/
select *
from user_tab_privs%DB_LINK%
where
owner = :owner
and
table_name = :table_name
and
privilege = :privilege
/*****/
/* 2 */
/*****/
select * from user_sys_privs%DB_LINK% where privilege = :privilege
/*****/
/* 3 */
/*****/
select * from
(
select distinct granted_role from
(
select null linker, granted_role
from user_role_privs%DB_LINK%
union all
select role linker, granted_role
from role_role_privs%DB_LINK%
)
start with linker is null
connect by prior granted_role = linker
) user_roles join role_tab_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
where
owner = :owner
and
table_name = :table_name
and
rtab.privilege = :privilege
/*****/
/* 4 */
/*****/
select * from
(
select distinct granted_role from
(
select null linker, granted_role
from user_role_privs%DB_LINK%
union all
select role linker, granted_role
from role_role_privs%DB_LINK%
)
start with linker is null
connect by prior granted_role = linker
) user_roles join role_sys_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
where rtab.privilege = :privilege
Explanations
Database links
In the phpunit tests I pass in two things : table name and schema name ( owner ). However, because of the database links we have to explicitly check the other databases by using the #db_link in the queries. Otherwise I might report a table as being inaccessible when in reality it is accessible via the database link.
Table visibility
If the user can't see the table then there is no point in checking for privileges. Checking for privileges also prevents the case where a user has been given 'SELECT ANY TABLE' privileges but the table itself doesn't actually exist from causing an unwanted failure.
The band of 4 queries
As shown by other posters, a user can be given access to a table in many ways. Specifically, they can be given roles, and those roles can be given roles, and then those roles can be assigned access. Or the user can be given explicit access or generic access through system privileges.
Query 1
The first of the four queries checks to see if the user has been given explicit SELECT, DELETE, etc, privileges on the table. It's easy to understand and would ideally be all that's necessary
Query 2
The second checks to see if the user has been granted any system privileges like DELETE ANY TABLE, SELECT ANY TABLE, INSERT ANY TABLE, etc. These are not granted explicitly on a table but the user can perform any of the referenced actions on any table they have visibility.
Query 3
The third query will see if any of the roles that user has, either directly or indirectly, has been given explicit SELECT, DELETE, etc, privileges on the table. This is similar to query 1 except it's based on the roles given to the user, not the user.
Query 4
The fourth checks to see if any of the roles that user has, either directly or indirectly, has been given any system privileges like DELETE ANY TABLE, SELECT ANY TABLE, INSERT ANY TABLE, etc. This one is similar to query 2.
That's it! I chain these together and use the results returned from each to determine whether a user has the desired privileges or not.
Details worth mentioning
If a user has any privileges across db_link_1 it does NOT mean that they have the same privileges on tables they access across db_link_2. Most should know this but I wanted to make sure I stated it explicitly. For example, select privs on table 1 across db_link_1 does not imply select privs on table 2 across db_link_2.
I check each db_link one at a time. So first I start of with the database I'm connected to directly, no database link required for this. Then, if I can't find the table or don't have the privs on the table I move on to the next database link.
In queries 2 and 4, I use 'SELECT ANY TABLE', 'DELETE ANY TABLE', etc in place of the :privilege variable.
In queries 1 and 3, I use 'SELECT', 'DELETE', 'UPDATE', 'INSERT' in place of the :privilege variable.

ORA-00942: Can select from "schema.table" but not "table"?

I experienced an ORA-00942 ("table or view does not exist") when executing
select * from brunch
However, no such problem when executing
select * from joe.brunch
May i know what is the issue here?
Unqualified, BRUNCH refers to a different object than JOE.BRUNCH in your current session. You've got a couple of options to fix that.
Create a public synonym. This will allow any user that has privileges on the JOE.BRUNCH table to access it by querying BRUNCH
CREATE PUBLIC SYNONYM brunch
FOR joe.brunch
Create a private synonym. This will allow just the current user to access the JOE.BRUNCH table by querying BRUNCH
CREATE SYNONYM brunch
FOR joe.brunch
Change the current schema for the current session to JOE. This will cause all unqualified references in the current session to resolve to the JOE schema rather than to the current user's schema
ALTER SESSION SET current_schema = JOE
There are several possible causes
1) there is more than one object (table,view, procedure, etc) called brunch. Oracle does not know which one you are referring to.
2) most likely cause: the table exists in the joe schema but you are connecting as another user who has not been granted select on the joe.brunch object
Try
Grant select on joe.brunch to your_user
and try this and see how many objects match the name brunch
select *
from all_objects
where object_type in (‘TABLE’,'VIEW’)
and object_name = ‘brunch‘;
I found that the table I was referencing (Flyway's schema_version table), was created with double quotes... and thus needed double quotes wherever it was referenced.
Here's what Oracle says:
A quoted identifier begins and ends with double quotation marks (").
If you name a schema object using a quoted identifier, then you must
use the double quotation marks whenever you refer to that object.
In practice, these worked:
SELECT * FROM MYSCHEMA."schema_version";
SELECT * FROM "MYSCHEMA"."schema_version";
When this didn't (-> ORA-00942: table or view does not exist):
SELECT * FROM MYSCHEMA.schema_version;

How do I get all indices on a Table in Oracle via JDBC, even if they are owned by different users?

Yes, I know about DatabaseMetadata.getIndexInfo, but it doesn't seem to do what I want.
I've got two users/schemas, let's call them A and B.
There's a table in A called TAB. The user B created an index on A.TAB, let's call that index IND.
The information that I want is: what indices are there on the table TAB in the schema A (a.k.a with the owner A). I don't care about the owner of the indices, just that they are on that specific table.
Experimenting with getIndexInfo I found out the following things:
the first argument catalog seems to be entirely ignored by the Oracle JDBC driver.
the second argument schema restricts which table statistics is returned and the owner of the index
unique and approximate do (roughly) what they should (except that giving approximate=false will actually execute an update statistics statement).
Having traced the SQL the JDBC driver executes on getIndexInfo(null, "A", "TAB", false, true), I got this:
select null as table_cat,
owner as table_schem,
table_name,
0 as NON_UNIQUE,
null as index_qualifier,
null as index_name, 0 as type,
0 as ordinal_position, null as column_name,
null as asc_or_desc,
num_rows as cardinality,
blocks as pages,
null as filter_condition
from all_tables
where table_name = 'TAB'
and owner = 'A'
union
select null as table_cat,
i.owner as table_schem,
i.table_name,
decode (i.uniqueness, 'UNIQUE', 0, 1),
null as index_qualifier,
i.index_name,
1 as type,
c.column_position as ordinal_position,
c.column_name,
null as asc_or_desc,
i.distinct_keys as cardinality,
i.leaf_blocks as pages,
null as filter_condition
from all_indexes i, all_ind_columns c
where i.table_name = 'TAB'
and i.owner = 'A'
and i.index_name = c.index_name
and i.table_owner = c.table_owner
and i.table_name = c.table_name
and i.owner = c.index_owner
order by non_unique, type, index_name, ordinal_position
As you can see both table_name and i.owner are restricted to being TAB. This means that this query will only return index information that is owned by the same user as the table.
I can think of three possible workarounds:
always create the index and the table in the same schema (i.e. let them have the same owner). Unfortunately that's not always an option.
Query with schema set to null. This would get ugly as soon as two schemata contained the same table name (because there's no way to find out on which table (i.e. which table owner) a given schema is).
execute that SQL directly (using executeQuery()). I'd rather not fall down to this level, unless it's absolutely unavoidable.
None of those workarounds look particularly pleasing to me, but if nothing else works, I might have to fall back to direct SQL execution.
Both the Database and the JDBC Driver are at 11.2.0.2.0.
So basically my questions are:
Is this a bug in the JDBC driver, or is there some logic behind it that I'm unaware of?
Is there a simple and reasonably portable way to get Oracle to give me the information that I need?
I suggest you query directly the Oracle dictionary tables, BUT start with:
select * from dba_indexes
Using that view it should be almost trivial to get the info you need.
However, accesing the dba_ tables and views requires the user to have special privileges, but since you don't want to give DBA privilege to everyone, you can just:
grant select any dictionary to username
connected as system or sys so the selected user can query the dictionary.
Just in case you want to explore Oracle's dictionary, try:
select * from dict
Best regards.
always create the index and the table in the same schema (i.e. let them have the same owner). Unfortunately that's not always an option.
That would be my preferred way of doing it.
Query with schema set to null. This would get ugly as soon as two schemata contained the same table name (because there's no way to find out on which table (i.e. which table owner) a given schema is)
Of course you can find that out, because the result set returned by getIndexInfo() does contain the correct schema for each table. But you can't find out in which schema the index is.
execute that SQL directly
I would actually use a modified version of that query that also returns the schema for each index to alleviate the identification of the index.
But again: I would also create the index and the table in the same schema.

Resources