Dynamically logging PLSql statements in a table - oracle

I have bunch of plsql which has dynamic queries ( ie queries are framed as string and executed with immediate execute function). I want to find the dependent tables and columns for a plsql. I am planning to achieve by GSQL parser. I tried the plsql file as it is, because of dynamic queries, I am not able to get the dependency information. The alternate way is collecting the list of SQL statements executed during the plsql run. How to get sql statement for a plsql and store it a table with unit name mapping ?

Hi you need execute the sql you have saved with execute immediate;
you will get all sql in below oracle view
select * from v$sql;
select * from dba_hist_sqltext;

Related

CREATE TABLE statement in Oracle with the existence check

This question is inspired by this.
As stated, I don't want a solution from PL/SQL. I want a 1 or 2 SQL statements that will check for table existence and if its not exist - create it.
Such statement(s) will be plugged into C++ application (not a script) and so I want a plain SQL solution. If such solution is not exist (please say so), I'd like to have a simple string I can plug into C++ code and use either SQLExecute() or a native Oracle client API to execute such a string.
Trying to google for a solution I am getting a results that can be used either in the shell script or a stored procedure. As I explain here and in the previous question - my situation is completely different - I work in C++ and want an appropriate solution.
There is no single SQL statement that will create a table only if it does not exist in Oracle 11g.
It is not obvious to me why you're objecting to a PL/SQL based solution. If you're using raw ODBC calls in C++, you can pass a PL/SQL block to SQLPrepare just as you would pass a plain SQL statement. Given that PL/SQL blocks work almost exactly like a pure SQL statement, it would be unusual to categorically reject a PL/SQL based solution.
If you are going to categorically reject PL/SQL, you can certainly take the logic from any of the PL/SQL based solutions and implement that in a couple of SQL statement executed from your application. For example, you can query dba_| all_| user_tables (depending on your privileges, whether you are creating tables in other schemas, etc.) to determine whether the table exists and then conditionally execute your DDL
select owner, table_name
from dba_tables
where owner = <<schema that will own the table>
and table_name = <<name of the table>>
If that returns no rows you can then execute your DDL.
Of course, you can also just execute your DDL statement and catch the ORA-00955 name is already used by an existing object error in C++.

Dynamic Query Re-write or Evaluating the Query Before Executing Table Function

First, I want to make it clear that the question is not about the materialized views feature.
Suppose, I have a table function that returns a pre-defined set of columns.
When a function call is submitted as
SELECT col1, col2, col3
FROM TABLE(my_tfn(:p1))
WHERE col4 = 'X';
I can evaluate the parameter and choose what queries to execute.
I can either open one of the pre-defined cursors, or I can assemble my query dynamically.
What if instead of evaluating the parameter I want to evaluate the text of the requesting query?
For example, if my function returns 20 columns but the query is only requesting 4,
I can assign NULLs to remaining 16 clumns of the return type, and execute fewer joins.
Or I can push the filter down to my dynamic query.
Is there a way to make this happen?
More generally, is there a way to look at the requesting query before exuting the function?
There is no robust way to identify the SQL that called a PL/SQL object.
Below is a not-so-robust way to identify the calling SQL. I've used code like this before, but only in special circumstances where I knew that the PL/SQL would never run concurrently.
This seems like it should be so simple. The data dictionary tracks all sessions and running SQL. You can find the current session with sys_context('userenv', 'sid'), match that to GV$SESSION, and then get either SQL_ID and PREV_SQL_ID. But neither of those contain the calling SQL. There's even a CURRENT_SQL in SYS_CONTEXT, but it's only for fine-grained auditing.
Instead, the calling SQL must be found by a string search. Using a unique name for the PL/SQL object will help filter out unrelated statements. To prevent re-running for old statements, the SQL must be individually purged from the shared pool as soon as it is found. This could lead to race conditions so this approach will only work if it's never called concurrently.
--Create simple test type for function.
create or replace type clob_table is table of clob;
--Table function that returns the SQL that called it.
--This requires elevated privileges to run.
--To simplify the code, run this as SYS:
-- "grant execute on sys.dbms_shared_pool to your_user;"
--(If you don't want to do that, convert this to invoker's rights and use dynamic SQL.)
create or replace function my_tfn return clob_table is
v_my_type clob_table;
type string_table is table of varchar2(4000);
v_addresses string_table;
v_hash_values string_table;
begin
--Get calling SQL based on the SQL text.
select sql_fulltext, address, hash_value
bulk collect into v_my_type, v_addresses, v_hash_values
from gv$sql
--Make sure there is something unique in the query.
where sql_fulltext like '%my_tfn%'
--But don't include this query!
--(Normally creating a quine is a challenge, but in V$SQL it's more of
-- a challenge to avoid quines.)
and sql_fulltext not like '%quine%';
--Flush the SQL statements immediately, so they won't show up in next run.
for i in 1 .. v_addresses.count loop
sys.dbms_shared_pool.purge(v_addresses(i)||', '||v_hash_values(i), 'C');
end loop;
--Return the SQL statement(s).
return v_my_type;
end;
/
Now queries like these will return themselves, demonstrating that the PL/SQL code was reading the SQL that called it:
SELECT * FROM TABLE(my_tfn) where 1=1;
SELECT * FROM TABLE(my_tfn) where 2=2;
But even if you go through all this trouble - what are you going to do with the results? Parsing SQL is insanely difficult unless you can ensure that everyone always follows strict syntax rules.

Execution of Oracle Procedure prior to Source Qualifier that must use the same Oracle session

I have a security procedure that has to be called just before a select from source table. Without this procedure no rows are returned.
The problem is that I have checked several ways to call this procedure just before Source Qualifier:
Pre-sql into the Source Qualifier As a Stored procedure
Pre-load source
Put several sql sentences in the sql query propertie in Source Qualifier (added 2014-11-08)
Always seems that Powercenter opens a new oracle connection, where security procedure takes no effect.
What could be the correct way to put both process together and use the same Oracle session?
Note added 2014-11-08:
I have tried also to put 2 sentences in the SQL Query of the Source Qualifier:
call procedure('param');
SELECT field1, field2, field.... from VI_ETL...;
and I get error ORA-24333 Zero Interaction Count, perharps because first item is not a SELECT statement that returns rows?
Try using SQL Query on Source Qualifier to invoke a series of statements - the security Stored Procedure being the first one.

How do I capture the query sent to Oracle in an SSIS Package?

I have deployed an SSIS package which has a query that pulls data from oracle. The query has some variables in it and I wanted to see what variable were being inputted at run time. Is there a way maybe via sql profiler that I can capture the query that sql server is sending out to Oracle when the sql job runs?
How are these variables being 'evaluated' when the SSIS package executed? I imagine you get this from a table or generating on the 'fly'.
You have the following option :
Capture them and assign them in SSIS variable(s)
In case you are doing something complex - create a variable something like - User::SQLCommand. In this case Use expression to generate the SQL String that needs to be executed in Oracle. Use this in your OLEDB Source Editor as "Sql command from variable" to execute the statement in Oracle
Use a SQL statement to insert the variable details captured in previous step in your intended audit table
--
Please mark if this answers your question!

Explain Plan for Query in a Stored Procedure

I have a stored procedure that consists of a single select query used to insert into another table based on some minor math that is done to the arguments in the procedure. Can I generate the plan used for this query by referencing the procedure somehow, or do I have to copy and paste the query and create bind variables for the input parameters?
Use SQL Trace and TKPROF. For example, open SQL*Plus, and then issue the following code:-
alter session set tracefile_identifier = 'something-unique'
alter session set sql_trace = true;
alter session set events '10046 trace name context forever, level 8';
select 'right-before-my-sp' from dual;
exec your_stored_procedure
alter session set sql_trace = false;
Once this has been done, go look in your database's UDUMP directory for a TRC file with "something-unique" in the filename. Format this TRC file with TKPROF, and then open the formatted file and search for the string "right-before-my-sp". The SQL command issued by your stored procedure should be shortly after this section, and immediately under that SQL statement will be the plan for the SQL statement.
Edit: For the purposes of full disclosure, I should thank all those who gave me answers on this thread last week that helped me learn how to do this.
From what I understand, this was done on purpose. The idea is that individual queries within the procedure are considered separately by the optimizer, so EXPLAIN PLAN doesn't make sense against a stored proc, which could contain multiple queries/statements.
The current answer is NO, you can't run it against a proc, and you must run it against the individual statements themselves. Tricky when you have variables and calculations, but that's the way it is.
Many tools, such as Toad or SQL Developer, will prompt you for the bind variable values when you execute an explain plan. You would have to do so manually in SQL*Plus or other tools.
You could also turn on SQL tracing and execute the stored procedure, then retrieve the explain plan from the trace file.
Be careful that you do not just retrieve the explain plan for the SELECT statement. The presence of the INSERT clause can change the optimizer goal from first rows to all rows.

Resources