I am new to Oracle and SQL and am trying to execute a simple test function from within SQL*Plus. My function is called tf (for Test Function) and it is defined in a file called tf.sql as follows ;
create or replace
function
tf
(
arg1 in varchar2
)
return number
as
return_value number;
begin
return_value := 0;
dbms_output.put_line('Argument 1 = ' || arg1);
return return_value;
end;
/
I am able to successfully load this function into Oracle using the following command ;
SQL> start ./tf.sql
As a result of executing this command, SQL*Plus simply states ;
Function created.
When I then execute the following command from the SQL*Plus command prompt (after I have invoked set serveroutput on) ;
SQL> exec dbms_output.put_line(SYSTEM.TF('Hello'));
I get the following output ;
Argument = Hello
0
PL/SQL procedure successfully completed.
Now, if I attempt to execute my function directly from the SQL*Plus command prompt, using the following command ;
SQL> exec SYSTEM.TF('Hello');
then I get presented with the following error message from SQL*Plus ;
BEGIN SYSTEM.TF('Hello'); END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00221: 'TF' is not a procedure or is undefined
ORA-06550: ;ine 1, column 7
PL/SQL: Statement ignored
Is anyone able to shed any light on this for me? I can't work out why my function appears to execute successfully in the first case, but not in the second case.
If I execute the following command from the SQL*Plus command prompt ;
SQL> select * from user_objects where object_name = 'TF';
then I get the following results returned ;
OBJECT_NAME
-----------
TF
SUBOBJECT_NAME
--------------
OBJECT_ID
---------
74475
DATA_OBJECT_ID
--------------
OBJECT_TYPE
-----------
FUNCTION
CREATED
-------
05-FEB-12
LAST_DDL_
---------
05-FEB-12
TIMESTAMP
---------
2012-02-05:02:11:15
STATUS
------
VALID
T
-
N
G
-
N
S
-
N
EDITION_NAME
------------
1
Any help on this would be immensely appreciated.
Thanks in advance.
Craig
exec does not work with functions because it does not know what to do with the return value. This is similar to a regular PL/SQL statement; if you call a function you must assign the return value to something.
If you want to use a function in SQL*Plus, you should use SQL instead:
select tf('asdf') from dual;
Also, you should never create objects in SYSTEM. This can cause some really weird problems.
Following on from #jonearles answer,which highlights the difference between a function and a procedure from SQL*Plus' perspective, and #MS Stp's comment, one way to run it is:
variable rc number;
exec :rc := tf('Hello');
Argument = Hello
PL/SQL procedure successfully completed.
To see the return code you can then do:
print rc
0
exec is really just shorthand for an anonymous PL/SQL block, as you can see from the error message you got. variable lets you declare a bind variable at SQL*Plus level, rather than in the block. You can also declare the argument as bind variable, and set it with a separate exec call:
variable rc number;
variable arg varchar2(5);
exec :arg := 'Hello';
exec :rc := tf(:arg);
I often use this construct for testing an existing procedure call, e.g. something copied from Pro*C code, without having to replace the variables in that call with fixed values. It can make it easier to call repeatedly with different arguments, and you can reuse variables in several calls - so you could pass :rc to another function later.
Related
I am trying to make some of my code dynamic. While typing the question how to use UDFs in dynamic SQL, I figured out the answer:
One can call the UDF from outside!
This works:
Update my_table
Set col1 = get_some_value(col2,col2)
Where 1 = 1;
This did not work:
Execute Immediate '
Update my_table
Set col1 = get_some_value(col2,col3)
Where 1 = 1
';
But this works:
Execute Immediate '
Update my_table
Set col1 = my_package_name.get_some_value(col2,col3)
Where 1 = 1
';
I am using Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
In case you have an idea, how to skip the call from outside, feel free to let me know.
Many greeetings,
Peter
Check your grants and make sure you either include explicit schema owner in the quoted call, use a synonym, or connect directly as schema owner.
Remember that stored procedures execute normally with the privileges of the code creator, so you should make certain that the username you use to run the execute immediate has direct grant (not via a role) access to execute the function.
This works fine in Oracle 12c when logged in as schema owner:
create function myfunc(p_text in varchar2) return varchar2 is
begin
return initcap(p_text);
end;
/
begin
execute immediate 'update emp set ename = myfunc(ename)';
end;
/
select ename from emp;
Returns:
King
Blake
Clark
...
EDIT:
Based on the additional information that function and calling procedure are in the same package, it is likely that the problem is merely naming and scope.
When using execute immediate, the statement is parsed and executed at runtime, by Oracle's SQL engine, with very limited context of the surrounding code.
In short, the payload of execute immediate doesn't know it's running in a package.
Here's a demo that should clear things up a bit.
create or replace package mytest as
function public_func(p_text in varchar2) return varchar2;
procedure demo;
end;
/
create or replace package body mytest as
-------------------------------------------------------------------------------
function public_func(p_text in varchar2) return varchar2 is
begin
return initcap(p_text);
end;
-------------------------------------------------------------------------------
function private_func(p_text in varchar2) return varchar2 is
begin
return lower(p_text);
end;
-------------------------------------------------------------------------------
procedure demo is
begin
-- Test 1 should fail because the function name is not fully qualified
begin
execute immediate 'update emp set ename = public_func(ename)';
exception when others then
dbms_output.put_line('Test1: ' || SQLERRM);
end;
-- Test 2 should pass
begin
execute immediate 'update emp set ename = mytest.public_func(ename)';
exception when others then
dbms_output.put_line('Test2: ' || SQLERRM);
end;
-- Test 3 should fail because the private function is not visible
begin
execute immediate 'update emp set ename = mytest.private_func(ename)';
exception when others then
dbms_output.put_line('Test3: ' || SQLERRM);
end;
end;
end;
/
Here's the results:
SQL> set serveroutput on;
SQL> begin
2 mytest.demo;
3 end;
4 /
Test1: ORA-00904: "PUBLIC_FUNC": invalid identifier
Test3: ORA-00904: "MYTEST"."PRIVATE_FUNC": invalid identifier
PL/SQL procedure successfully completed.
SQL>
For test 1, the SQL engine is looking for something called "public_func" and can't find it. This make sense because you could have two packages that each have something called "public_func" in them. The SQL engine does not know that it is being invoked from within a package.
Test 2 is what you did, and it works as expected.
For test 3, a function is called that exists only within the package body. Normally, other procedures in the package can see private functions, but since this is interpreted at runtime and the SQL engine doesn't know it's being called within the scope of the package, this call fails as well.
Since my school does not allow me to post the code, hence i had to come back home and put up an example to show the issue i am facing. My school asked me to do a homework on dynamic sql to create a table and later insert one dummy record to it. But while doing it I am facing the below issue. Please find the code below for your reference. Thank you.
Procedure:
create or replace procedure table_creation(table_name in varchar2,col1 varchar2,col2 varchar2)
is
l_stat varchar2(3000);
v_stat varchar2(1000);
a varchar2(10):='1';
b varchar2(10):='Dummy';
begin
l_stat:='create table '||table_name||' ("'||col1||'" varchar2(10),"'||col2||'" varchar2(10))';
execute immediate l_stat;
execute immediate 'insert into '||table_name||'('||col1||','||col2||') values (:x,:y)' using a,b;
end;
/
Plsql Block to call the procedure:
set serveroutput on;
declare
a varchar2(10);
b varchar2(10);
c varchar2(10);
begin
a:='Example';
b:='id';
c:='nm';
table_creation(a,b,c);
dbms_output.put_line('Yes');
end;
/
The procedure is getting created perfectly and while running the above block i am getting the below error .
declare
*
ERROR at line 1:
ORA-00904: "NM": invalid identifier
ORA-06512: at "SYS.TABLE_CREATION", line 9
ORA-06512: at line 9
But when I checked the created table. The table exists with 0 records. The structure of the table is as follows.
Name Null? Type
----------------------------------------- -------- ---------------
ID VARCHAR2(10)
NM VARCHAR2(10)
Any help from your end is much appreciated.
Nick,
Please note that the above procedure will create the column with a double qoutes ("ID","NM") hence the error occurred. Please find the updated code and check if the issue has resolved.
According to oracle=>
Oracle is case sensitive in column and table names. It just converts everything to upper case by default. But if you use names in double quotes, you tell Oracle to create the column in the exact spelling you provided (lower case in the CREATE statement).
Code:
create or replace procedure table_creation(table_name in varchar2,col1 varchar2,col2 varchar2)
is
l_stat varchar2(3000);
v_stat varchar2(1000);
a varchar2(10):='1';
b varchar2(10):='Dummy';
begin
l_stat:='create table '||table_name||' ('||col1||' varchar2(10),'||col2||' varchar2(10))';
execute immediate l_stat;
execute immediate 'insert into '||table_name||'('||col1||','||col2||') values (:x,:y)' using a,b;
end;
/
Note: I have not touched any other logic of the code. Please try and let us know the result.
Only change is
From :
l_stat:='create table '||table_name||' ("'||col1||'" varchar2(10),"'||col2||'" varchar2(10))';
to :
l_stat:='create table '||table_name||' ('||col1||' varchar2(10),'||col2||' varchar2(10))';
/
create or replace procedure search_proc(p_string varchar2,p_table varchar2,p_col varchar2,search_result OUT sys_refcursor)
is
SQL_QRY VARCHAR2(2000);
BEGIN
SQL_QRY:='SELECT EMPNO,:1 FROM :2';
--DBMS_OUTPUT.PUT_LINE('SQL:'||SQL_QRY);
OPEN SEARCH_RESULT FOR SQL_QRY USING p_col,p_table;
END;
/
VARIABLE REFC REFCURSOR;
EXEC SEARCH_PROC('TEST','EMP','ENAME',:REFC);
PRINT REFC;
/
I am trying to return empno and employee name using a procedure which contains dynamically built SQL query .The query is built using bind variables.but getting the following error.May be something is wrong with the way i am calling the procedure
ORA-06512: at line 1 00903. 00000 - "invalid table name"
You can't use bind variables to take the place of identifiers, such as table names or column names. Those things must be known at the time the statement is parsed, which occurs before bind variables are bound to values. (Part of the whole purpose of using bind variables is to be able to parse a statement once then execute it with variable values.)
In this case, the solution is simple, since you are already putting the query string into a variable.
BEGIN
SQL_QRY:='SELECT EMPNO,' || p_col || ' FROM ' || p_table;
--DBMS_OUTPUT.PUT_LINE('SQL:'||SQL_QRY);
OPEN SEARCH_RESULT FOR SQL_QRY;
This question already has answers here:
Printing the value of a variable in SQL Developer
(9 answers)
Closed 4 years ago.
I'm just getting into PL/SQL, and I tried to run the following code, and I am getting anonymous block completed, but I think I should be getting Testing output. Does any know what I am doing wrong?
DECLARE
message varchar2(20) := 'Testing output';
BEGIN
dbms_output.put_line(message);
END;
/
Viewing the DBMS_OUTPUT depends on the program.
SQL*Plus and Oracle SQL Developer
Run SET SERVEROUTPUT ON; first. This is all that's necessary in SQL*Plus or recent versions of Oracle SQL Developer.
SET SERVEROUTPUT ON;
begin
dbms_output.put_line('Testing output');
end;
/
PL/SQL Developer
Output is automatically detected and displayed in the "Output" tab.
Yes, in Oracle SQL Developer put the statement:
SET SERVEROUTPUT ON;
just before your DECLARE keyword and this should work.
I couldn't find View -> DBMS Output and I'm using version 1.5.5.
Yes. There is way to see output in SQL Developer.
Click ->View->Dbms Output and then click + symbol on Dbms output window. now you can run the procedure and can see output.
`The following statement will give the possible solution try this out
SET SERVEROUTPUT ON;
Then Run this code will get the following output
declare
a integer :=10;
b integer :=20;
c integer;
f real;
begin
c := a+b;
dbms_output.put_line('value of c: ' || c);
f := 70.0/3.0;
dbms_output.put_line('value of f: ' || f);
end;
/
The code will give the following output
value of c: 30
value of f: 23.3333333333333333333333333333333333333
PL/SQL procedure successfully completed.
Yes, this is correct. You need to use before this block:
SET SERVEROUTPUT ON
Then, message get displayed on window.
Else we can check in SQL Developer select "View" -> "DBMS Output".
and in PLSQL developer under the OutPut tab we can check message.
If you are getting "anonymous block completed" while executing the procedure by typing "EXECUTE ;" then run the below command & again execute the procedure.
command is
SET SERVEROUTPUT ON;
**SET SERVEROUTPUT ON;**
DECLARE
a INTEGER :=10;
b INTEGER :=20;
c float ;
d real ;
BEGIN
c :=a+b;
dbms_output.put_line('the value of C is :'|| c);
d := 70.0/3.3;
dbms_output.put_line('the value of d is:'|| d);
END;
This will give you the output
the value of C is: 30
the value of d is: 21.21212121212121212121212121212121212121
I am having trouble testing this simple stored procedure in Oracle Sql Developer. The stored procedure does a simple select and returns a cursor.
create or replace
PROCEDURE GET_PROJECT_DRF_HISTORY
( projectId IN NUMBER,
resultset_out OUT sys_refcursor
) AS
BEGIN
OPEN resultset_out for
SELECT * from GLIDE_HISTORY
where GLIDE_HISTORY.PRJ_ID = projectId;
/* DBMS_OUTPUT.PUT_LINE(resultset_out);*/
END GET_PROJECT_DRF_HISTORY;
To test this procedure, I used the below script:
variable results sys_refcursor;
exec get_project_drf_history(3345, :results);
print :results;
Being new to both oracle and the Sql Developer tool, I am struggling to understand what is the mistake here. I cannot check this in Sql*Plus because I dont have the password to do so. I am using Oracle Sql Developer 1.1.2.25 and Oracle 10g.
Can anybody help me out please? Thank you in advance.
Sammy,
The variable declaration should be refcursor instead of sys_refcursor.
Also when you print the results, you are printing the variable itself, so there is no need for a : (which is used to indicateit is a bind variable).
I was able to run the following script sucessfully in SQL Developer (and of course sql plus.)
For SQL Developer, run it as a script using F5.
--Creating Procedure
create or replace procedure test_ref(
i_limit number,
o_results out sys_refcursor
) is
begin
open o_results for
'select object_name
from all_objects
where rownum < ' || i_limit;
end;
/
And then the script that calls this procedure. (excute as a script using F5).
var c1 refcursor;
exec test_ref(10,:c1);
print c1;
here is a working example, declare the refcursor then assign the value by calling you proc in an anonymous block.
then you print it
var x REFCURSOR ;
declare
/*a no cleanup procedure*/
procedure GetMeMyRefCursor(outter out nocopy sys_refcursor)
as
begin
open outter for
select level
from dual
connect by level <= 5;
end GetMeMyRefCursor;
begin
GetMeMyRefCursor(:x);
/*note you pass in the refcursor you created via the :X*/
end ;
/
print x;
/*now print it*/
/*LEVEL
----------------------
1
2
3
4
5*/
based on comment:
now using your comment, you are having an issue with IN/OUT params and not with the print (didn't read the title just the question and the other response)
this works: (based on your code)
create or replace
PROCEDURE GET_PROJECT_DRF_HISTORY
( projectId IN NUMBER,
resultset_out OUT sys_refcursor
) AS
BEGIN
OPEN resultset_out for
SELECT level from dual connect by level <= projectId;
/* DBMS_OUTPUT.PUT_LINE(resultset_out);*/
END GET_PROJECT_DRF_HISTORY;
/
var results REFCURSOR;
--this needs to be REFCURSOR (at least in 10g and 11i)
exec GET_PROJECT_DRF_HISTORY(5, :results);
print results;
/
You can also debug packages and procedures directly from SQL Developer (this can be a real life saver)
if you want to debug in SQL Developer it is really easy:
in the connections->your schema here-->procedures -> GET_PROJECT_DRF_HISTORY right click and 'Compile for debug'. Then in the procedure place a break point in it, then right click and 'debug' it (this will create an anonymous block -- see below -- where you can put in your values and such)
DECLARE
PROJECTID NUMBER;
RESULTSET_OUT sys_refcursor;
BEGIN
PROJECTID := NULL;
GET_PROJECT_DRF_HISTORY(
PROJECTID => PROJECTID,
RESULTSET_OUT => RESULTSET_OUT
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('RESULTSET_OUT = ' || RESULTSET_OUT);
END;
(http://www.oracle.com/technetwork/developer-tools/sql-developer/sqldeveloperwhitepaper-v151-130908.pdf page 11)
otherwise, the error doesn't look as it should appear if you are doing this all from Developer.
But what I really think is happening is your VAR is incorrect and thus it doesn't exists!
variable results sys_refcursor;
Usage: VAR[IABLE] [ <variable> [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |
VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |
NVARCHAR2 (n) | CLOB | NCLOB | REFCURSOR |
BINARY_FLOAT | BINARY_DOUBLE ] ]
so, going from my initial example "var x REFCURSOR ;" should work
I recommend asking your administrator to upgrade your SQL Developer version. Yours is significantly outdated and you may be running into some obscure bugs. (I did when I tried to use version 1) You should be on 2.1 by now.