Oracle Stored Procedure List Parameters - oracle

I'm developing a .NET front end that interacts with an Oracle database. I have figured out how to get a list of stored procedures to execute, but I don't know how to get a list of parameters that belong to the stored procedure. I want to be able to show a list of all the parameters that are both input and output parameters for the stored procedure.
I have tried using the DBA_SOURCE, DBA_PROCEDURES, ALL_DEPENDENCIES, but I haven't seen anything that shows the parameters that belongs to the specified stored procedure.
Any ideas?

I believe that both responses I received are correct, but I ended up finding a different query which gives me exactly what I'm looking for:
SELECT
ARGUMENT_NAME,
PLS_TYPE,
DEFAULT_VALUE
FROM
USER_ARGUMENTS
WHERE
OBJECT_NAME = '<my_stored_proc>'
This has been working for me so far and pulls all the OracleParameter information that I want as well.

You find parameter metadata in DBA/ALL/USER_ARGUMENTS view.

This is the query that we use, more or less:
SELECT *
FROM
ALL_ARGUMENTS
WHERE
DATA_TYPE IS NOT NULL
-- This check removes package procedure arguments that don't really
-- seem to mean anything
AND
DATA_LEVEL = 0
-- Use this predicate to remove entries for the return value of functions
AND
POSITION > 0
ORDER BY
OWNER,
PACKAGE_NAME,
OBJECT_NAME,
OBJECT_ID,
OVERLOAD,
POSITION

Related

How to retrieve body of "verify_function" Oracle 11g

I am auditing an Oracle BD and I need to know the password policy assigned to this Database.
One way I thought to do it is retrieving the body of verify_function that is assigned to the profiles.
How can I list the body of these "verify_function"? Such as the body of utlpwdmg.sql and ora12c_strong_verify_function etc.
Thx!
As I see the problem from the comments you can't find the function "ORA_COMPLEXITY_CHECK" which is an oracle standart function. The code might be obtained under
{ORACLE_HOME}/rdbms/admin/catpvf.sql
And it could be that the catpvf.sql script wasn't executed against the instance you're on.
In general, here is the script to get the ddl of an object withour specifying it's type(might take longer time to execute).
select owner, object_name, object_type, dbms_metadata.get_ddl(object_type, object_name)
from dba_objects
where object_name = 'CFL_BITAND';
The same way you'd get the DDL for any object in the database -- dbms_metadata.get_ddl. There's nothing magic about the particular function you are after. It's just another function defined in the database.

Can "table of type" be manipulated in PL/SQL?

I have table of object type defined like this
create type user_role_ty as object (
username varchar2(32),
role_nam varchar2(32)
);
create type user_role_nt as table of user_role_ty
/
And output variable in function
p_user_role_list out bt_ww_user_role_nt
After filling with
select user_role_ty (username, role_nam)
bulk collect into p_user_role_list
(...)
How can I modify this variable of table type? I would like to remove some lines, e.g. main admin may see all, local admin shall not see main admins, user may see himself only etc. Shortened:
if is_vendor( ... ) then
NULL;
elsif is_admin( ... ) then
delete from p_user_role_list
where username in ( (...) user_name_list );
else
delete from p_user_role_list
where username <> p_username;
Simply does not work. There are several possibilities, none of which is straightforward:
Use copy-paste the same identical original select several times which slight condition modification use. Works, but awful (plus risk of future entered bugs).
Use execute immediate which I really hate - PL/SQL is great to integrate scripting language and SQL (e.g. syntax highlighting). execute immediate degradates PL/SQL to call SQL by string in any language (comparing to those it lacks many features).
Use temporary table, which content will be then copied to table-type variable. This is superfluous no-use code rubbish (code shall be readable and make sense).
Is there any other way?
The previous suggestions are spot on (do as much of the work as you can in SQL, or go "deeper" and set up Virtual Private Database roles). But if you do happen to (or need to) stick with a PL/SQL-focused solution, remember that once you have bulk collected into that collection, it is a PL/SQL variable.
So I wouldn't be thinking about using EXECUTE IMMEDIATE or a temporary table, so much as writing PL/SQL logic to apply whatever complex rules you have.
DECLARE
p_user_role_list user_role_ty;
BEGIN
SELECT user_role_ty (username, role_nam)
BULK COLLECT INTO p_user_role_list
FROM (SELECT 'steven' username, 'admin' role_nam FROM DUAL);
FOR indx IN 1 .. p_user_role_list.COUNT
LOOP
/* Apply changes like .DELETE to remove an element
or even copy the elements you want to keep to
a new collection */
NULL;
END LOOP;
END;
/
PS - I can understand hating to use EXECUTE IMMEDIATE if you don't really need to, but when you do need to execute dynamic SQL, it certainly offers a nice, simple, native way to get the job done!
I'd filter the select query that provides the data, something like:
select user_role_ty (username, role_nam)
bulk collect into p_user_role_list
from user_role_table
where case when is_vendor(...) = 'Y' then role_nam
when is_admin(...) = 'Y' and role_nam in (<list of roles that the is_admin user is allowed to see>)
then role_nam
end = role_nam
or username = p_username;
The correct solution is to apply VPD policies to the underlying tables (the bit you have hidden in (...). That way the PL/SQL collection can only be populated with the data the user is allowed to see.
Fine-grained access control is pretty powerful. Also, being baked into Oracle, is way more reliable than our hand-rolled code. Find out more.

Optional Data Input into Spotfire Text Area parameters got from a Oracle Function

I have created a Function from Oralce DB and used it as input to Spotfire report. The reason why i used a function instead of view is because the parameters had some complex logic operations and i was not able to get that done in a view.
Coming to the report i have built. Currently i am using 2 parameters in the function and i am taking both the values from Spotfire text area in Data on Demand mode. So i have set up two 'Input Field' for getting the data. Issue is that unless i enter values for both parameters i wont get the output. My requirement is that i need to add few more parameters for the report which i can but i need to set up the function and the settings in Spotfire such that if 5 parameters are there , if users enters one value for just one parameter report should run for that parameter. I know that parameters set up with complex logis are there but also i need to add additional ones and make sure it works properly. I dont know about proc in case a solution is achievable using that.
I cannot go back to use a view since that wont give me the desired result. Need any ideas or suggestions to implement it. Let me know in case i need to post additional information.
This is how i implemented in oracle :
create or replace function Function_test(p1 varchar2='',p2 varchar2='',p3 varchar2)
return SYS_REFCURSOR as
my_cursor SYS_REFCURSOR;
begin
open my_cursor for
select distinct
x.c1
x.c2
x.c3
from x
where x.c1=p3
and (p1='' or x.c2=p1)
and (p2='' or x.c3=p2);
return my_cursor;
end;
Using a STORED PROCEDURE or a TABLE VALUED FUNCTION will achieve similar results here and you can probably use either one. I understand you can't use a VIEW because VIEWS can't have parameters. I prefer PROCEDURES over VIEWS anyway while working with SPOTFIRE because if you need to add a column or parameter to the PROCEDURE, your INFORMATION LINK on the PROCEDURE will in inherit these changes, whereas using an INFORMATION LINK on a VIEW, the change will not cascade down and you'll need to recreate the INFORMATION LINK all together.
For your case there are a couple of things I would suggest. Since you are trying to make some of the parameters optional, you need to code your FUNCTION or PROCEDURE to accept this. For example, assume one parameter is #param1 and this is accepting input from {$propertyControl1}. To make this optional, you need to instruct users to leave the property control blank if they don't want it to be used to limit the results. Meanwhile, in your FUNCTION or PROCEDURE you need to default it's value to ''. Here is what it could look like using SQL Server, but it should be similar for ORACLE
CREATE FUNCTION dbo.MyFunction (#param1 VARCHAR(256) = '') --default value is blank. Remember don't use NULL since your property control can't be NULL
RETURNS
#returnTBL TABLE(
Column1 datetime,
Column2 int,
Column3 varchar(16))
AS
BEGIN
INSERT INTO #returnTBL (Column1, Column2, Column3)
SELECT
c.C1
c.C2
c.C3
FROM Table2
WHERE #param1 = '' OR c.C3 = #param1 --this returns all rows if the user passes in blank, and filters on it if they pass in a value
RETURN
END
Or, similarly, here is the same logic using a STORED PROCEDURE in SQL Server
CREATE PROCEDURE dbo.MyProcedure(#param1 VARCHAR(256) = '') --default value is blank. Remember don't use NULL since your property control can't be NULL
AS
SELECT
c.C1
c.C2
c.C3
FROM Table2
WHERE #param1 = '' OR c.C3 = #param1 --this returns all rows if the user passes in blank, and filters on it if they pass in a value
GO
Lastly, since you have multiple parameters, I wouldn't have the data on demand automatically refresh. I will have the users click the refresh button to retrieve the data. This will prevent the FUNCTION from being executed each time an individual parameter is change. If a user needs to change 3 of the 5 parameters, you really only want it executed once, versus three times.

How to handle procedure that returns 2 different results

I have a stored procedure made in Oracle 9g that returns a cursor with different columns depending on a parameter, its something like this:
CREATE OR REPLACE PROCEDURE ASCHEMA.SP_TWOCURSORS
(
aParam NUMBER,
P_RETURN OUT SYS_REFCURSOR
)
IS
BEGIN
IF aParam = 1 THEN
OPEN P_RETURN FOR
SELECT
a.column1, (number)
a.column2 (varchar2)
FROM
table1 a;
ELSE
OPEN P_RETURN FOR
SELECT
b.column1, (varchar2)
b.column2, (number)
b.column3 (number)
FROM
table1 b;
END IF;
END;
I have to consume this procedure in PowerBuilder and pass the returned data to a DataWindow1 or DataWindow2, depending on the returned cursor, these datawindows are filled in runtime by the execution of another procedures coming from other source. I can't modify the database objects (like split the sp in two), just the PowerBuilder code. My problem is how to handle this scenario in an elegant way. I have some ideas but don't know if it will work:
Create a DataWindow object that handles every column involved in both cursors returned from the sp, then copy each row to the expected DataWindow.
Create a DataStore and pass the sp with the Create method, then copy the rows in the expected DataWindow.
Execute the procedure dynamically, fetch every row and add each result into a new row of the expected DataWindow.
I haven't tried the first one because there are many columns and it will take a long time to do. The second looks good but I don't know how to handle a DataStore with no DataWindow object and don't know if this is possible (1). The third is my last option to solve this problem. I want to ask people before start implementing this solution because I'm new to PowerBuilder, and even if I won't work on it too long I want to do it in the right way.
Thanks for the help.
(1) I have found this article about using Custom DataStores but I don't know if I can use only 1 DataStore or I should use 2. Also, for the Oracle connection I don't use SQLCA but another transaction object, so I don't know how to do this.
Keep It Simple.
You know the details of the stored proc. If you are calling this sp from PB, you are knowing its aParam already before the call. Why not defining 2 datawindows, one for each version of the results ?
Each DW would have a retrieval argument (the one that is passed to the stored proc) and will get its result from the sp.
At runtime, depending on the retrieval argument, and before retrieving the values, assign the corresponding dataobject to the datawindow object that is on : either the DW that suits the aParam = 1 or the DW that suits the else part.

How to get information about a User-Defined Type?

In simplicity, PL/SQL generally follow the following:
DECLARE
Variable declaration
BEGIN
Program Execution
EXCEPTION
Exception handling
END;
I am quite new to PL/SQL and i am looking at the variable declaration section where i would like to find out more information on SALES_PRODUCT_TY_LIST.
Is there a table i may look up to check on information on SALES_PRODUCT_TY_LIST, such as checking out table column information from all_tab_cols view?
CREATE OR REPLACE PROCEDURE GET_DISCOUNTS
(
v_have_list SALES_PRODUCT_TY_LIST
)
IS
QUERY VARCHAR(5000);
...
Thanks.
The Oracle database has an extensive data dictionary (what some other DBMS products call the INFORMATION SCHEMA). You can find all the views here. Alas, the revised ToC structure makes it harder to find something in the 11g documentation unless you already know what you're looking for, so use the index instead. 8-)
Anyway, the views you need to query are ALL_TYPES and ALL_TYPE_ATTRS.
This seems to be user defined collection type. You can find some information about it querying all_types/user_types view:
select * from user_types where type_name = 'SALES_PRODUCT_TY_LIST'
The definition of the type can be found for example by querying all_source/user_source view:
select text from user_source where name = 'SALES_PRODUCT_TY_LIST' order by line
Try this to get DDL:
SELECT dbms_log.substr(dbms_metadata.get_ddl('TYPE', 'SALES_PRODUCT_TY_LIST'), 32767,1)
FROM DUAL;
see: http://www.myoracleguide.com/s/gen_schema.htm
Ok i found something:
select *
from all_objects
where object_name like 'SALES%';

Resources