How to solve ORA-29471 on dbms_sql.open_cursor? - oracle

I'm using Oracle 11.2.0.1.0 and am trying to get the dbms_sql package to work.
However, I keep getting the ORA-29471 error, as shown below:
DECLARE
c INTEGER;
BEGIN
c := dbms_sql.open_cursor();
END;
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1017
ORA-06512: at line 4
The oracle docs say the following about this:
Checks are made when binding and executing. Optionally, checks may be
performed for every single DBMS_SQL subprogram call. The check is:
The current_user is the same on calling the subprogram as it was on calling the most recent parse.
The enabled roles on calling the subprogram must be a superset of the enabled roles on calling the most recent parse.
Consistent with the use of definer's rights subprograms, roles do not
apply. If either check fails, and ORA-29470 error is raised.
As far as I can tell, both conditions don't apply to my code, because the code does not cross schemas.
The Oracle support (requires login) website proposes that I explicitly add the security_level parameter into dbms_sql.open_cursor. Adding any of the values (0/1/2) doesn't solve the issue.
The puzzling thing for me is that I get the error at the dbms_sql.open_cursor, which is where the security level is first defined.
The support website also proposes a workaround that involves setting:
alter system set "_dbms_sql_security_level" = 384 scope=spfile;
I haven't tried that yet. I prefer to think of it as a last resort, because it involves disabling a security layer and it is an unsupported oracle feature. Hardly ideal circumstances for production use. Also, it doesn't really solve the issue at all, just hides it.
How can I solve this error?

The only reason(cannot see another one at this moment) why your code raises the ORA-29471 is you already made dbms_sql inoperable in your session by providing an invalid cursor ID:
/* dbsm_sql detects invalid cursor ID in this session */
SQL> declare
2 c_1 number := 5; -- invalid cursor ID. There is no cursor
3 l_res boolean; -- opened with ID = 5
4 begin
5 l_res := dbms_sql.is_open(c_1);
6 end;
7 /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1104
ORA-06512: at line 5
/* An attempt to execute this simple anonymous PL/SQL block after
an invalid cursor ID has already been detected by the dbms_sql
in the current session will lead to ORA-29471 error
*/
SQL> declare
2 c_2 number;
3 begin
4 c_2 := dbms_sql.open_cursor();
5 end;
6 /
declare
*
ERROR at line 1:
ORA-29471: DBMS_SQL access denied
ORA-06512: at "SYS.DBMS_SQL", line 1084
ORA-06512: at line 4
Try to execute that code in a newly established session.

A solution could be to have a look into the v$Session view.
If the cursor exists in the list, then it means you can still us it. Then identify it from its sql_id, and you can check. Here you generate the list:
select sql_id, sql_text, count(*) as "OPEN CURSORS", user_name
from v$open_cursor
where user_name <>'SYS'
group by sql_text, user_name
order by count(*) desc;
More here.

Related

PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ; - Not sure what is wrong in code

I am trying to create trigger as below but getting error specified below. Can any one please help me to figure out what is wrong with the code. Thank you in advance
Code:
CREATE OR REPLACE EDITIONABLE TRIGGER TEST_DATA.IVR_SEQ
BEFORE INSERT ON TEST_DATA.TRANSACTION
FOR EACH ROW
BEGIN
SELECT TEST_DATA.IVR_SEQ.NEXTVAL
INTO :new.IVRID
FROM dual;
END;
/
Error:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ;
Tool: Oracle SQL Developer
Strange, as there's nothing wrong with it, but I get the same error as you do when executing it literally.
SQL> create or replace -- EDITIONABLE
2 trigger scott.trg_ivr_seq
3 before insert on scott.transaction
4 for each row
5 begin
6 select scott.ivr_seq.nextval
7 into :new.ivrid
8 from dual;
Warning: Trigger created with compilation errors.
SQL> show err trigger trg_ivr_Seq
Errors for TRIGGER TRG_IVR_SEQ:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/11 PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
;
(editionable is not an option in my 11gXE so I removed it).
As you can see, error points to line #4, column #11 which is
4 for each row
Rewritten from scratch (and "improved" a little bit):
SQL> create or replace trigger scott.ivr_seq
2 before insert on scott.transaction
3 for each row
4 begin
5 :new.ivrid := scott.ivr_seq.nextval;
6 end;
7 /
Trigger created.
SQL>
It works with select as well (just that you wouldn't think that it is wrong):
SQL> create or replace trigger scott.ivr_seq
2 before insert on scott.transaction
3 for each row
4 begin
5 select scott.ivr_seq.nextval
6 into :new.ivrid
7 from dual;
8 end;
9 /
Trigger created.
SQL>
So ... rewrite it. I don't see any garbage characters (in Notepad++), I have no idea what's wrong with it.
[EDIT]
Luke Woodward's comment made me do another test. Yes, Luke is right!
Comment in the 1st line, before actually stating what I'm creating causes an error:
SQL> create or replace -- comment
2 trigger trg_test
3 before insert on dept
4 for each row
5 begin
6 null;
Warning: Trigger created with compilation errors.
But, comment in the 1st line AFTER stating what's being created doesn't cause any errors:
SQL> create or replace trigger -- comment here
2 trg_test
3 before insert on dept
4 for each row
5 begin
6 null;
7 end;
8 /
Trigger created.
Thank you, Luke!
There are several ways you can get this error:
Your SQL is malformed, you are missing a ; somewhere
Not present in the provided snippet.
Your SQL is malformed, the parser is being tripped up and believes things to be things they are not, finally failing when it get to the end of the file.
Not obviously present in the provided snippet. However i can't test the EDITIONABLE clause as it is not present in my db version, so it may be introducing some addition required syntax.
Your interface is mangling the SQL before it sends it to the database to be compiled.
Unlikely as SQL developer is way better at not doing this than SQL*Plus was, but if you have any custom configuration there are all kinds of things that could be happening, check what is actually getting to the database by looking at trigger in the database and see if it matches what you expect to be there.
Invalid characters in your code
Not a common issue but can be eliminated by either retyping the trigger manually, not using copy paste, or by pasting from a know clean source. (copy/paste from the web can include lots of weird character replacements used to get the layout right in the browser (no-break spaces, etc.), and apps like word can mangle things like quotes (e.g.Word replaces ' ' with ‘ ’)
Code in the same file before the trigger definition that has errors.
I am assuming you have run this separately from any other code, but if not put this trigger create statement in its own file and run it there.
Scenario 2 is being triggered by a non obvious misparse of the code.
This could be caused by other objects in this or a different schema with identical names, keyword use, etc. and can depend on which schema is running the DDL statement.
Try quoting TEST_DATA.TRANSACTION as TEST_DATA."TRANSACTION", TRANSACTION is a keyword in oracle, and while some keywords can be used in some contexts, possibly your version of oracle is treating it as a keyword and messing up the rest of the parsing. This compiles fine on my DB without the quotes so i would lean more toward the next possibility, but I have this issue with a schema named "SEARCH" on my database, in some contexts you need to quote the name to prevent compile errors.
Check for name reuse on schemas, tables, views, etc. In your example your trigger and your sequence have the same name TEST_DATA.IVR_SEQ. On its own this is not an issue, but can cause seemingly random compile errors depending on where the duplication is.
I could not reproduce your specific compile error, but I was able to create a few different compile errors by creating different name collisions (example creating a table in the TEST_DATA schema named TEST_DATA, creating a function named TEST_DATA, creating a package, sequence named TEST_DATA, a function named IVR_SEQ in a package named TEST_DATA, etc.). It is possible on your version of Oracle this or a similar collision is creating the EOF error.

In Oracle DB how to avoid decompiling of objects dependent on a DBLink?

There is a DBLink to a remote DB and a package MY_PACKAGE (in the local schema) indirectly depending on it through MY_VIEW.
When DBLink is not valid (for whatever reason, i.e. connection is lost or credentials are changed on the remote) then the package becomes invalid. But it would be great to have it working, because this package has other responsibilities aside from negotiating through this DBLink. And overall, I do not think it is a desirable situation to have the schema object validity depending on an unstable parts like network connection.
I found this situation in a legacy code (see MY_PACKAGE.doSomething()) and I am not sure even whether this is a correct design. Could you share your opinion on this?
What is the proper approach to keep the package in a VALID state even when some DBLinks are not available?
For example, would it be correct to use a dynamic cursor referencing MY_VIEW, which fails to open ONLY when DBLink is not OK (i.e. MY_PACKAGE.doSomethingAgain()). Of course maybe there is a more natural approach to this problem. I will be glad to hear all options that could be appropriate for safe usage of DBLinks in Oracle.
Code:
-- DBLink --------------------------------------------------------------
CREATE DATABASE LINK "MY_LINK"
CONNECT TO "MY_USER" IDENTIFIED BY VALUES ':1' USING 'WHATEVER';
------------------------------------------------------------------------
-- Synonym -------------------------------------------------------------
CREATE OR REPLACE EDITIONABLE SYNONYM "MY_SYNONYM"
FOR "MY_REMOTE_SCHEMA"."MY_REMOTE_VIEW"#"MY_LINK";
------------------------------------------------------------------------
-- View ----------------------------------------------------------------
CREATE OR REPLACE VIEW "MY_VIEW" AS
SELECT a,b,c FROM "MY_SYNONYM";
> Compiler Error
> ORA-02063: preceding 2 lines from MY_LINK
> ORA-01017: invalid username/password; logon denied
> [Oracle][ODBC SQL Server Wire Protocol driver][SQL Server]
> Login failed for user 'MY_USER'. {28000,NativeErr = 18456}
------------------------------------------------------------------------
.
-- Package body --------------------------------------------------------
CREATE OR REPLACE PACKAGE BODY MY_PACKAGE AS
PROCEDURE doSomething()
IS
i NUMBER := 0;
BEGIN
FOR rec IN (SELECT * FROM "MY_VIEW")
LOOP
i := i + 1;
END LOOP;
END;
PROCEDURE doSomethingAgain()
IS
i NUMBER := 0;
my_cur SYS_REFCURSOR;
BEGIN
OPEN my_cur FOR 'SELECT * FROM MY_VIEW';
LOOP
FETCH my_cur -- ...
-- etc ...
i := i + 1;
END LOOP;
END;
END MY_PACKAGE;
> Compiler Error
> 7/4 PL/SQL: SQL Statement ignored
> 7/35 PL/SQL: ORA-04063: view "MY_VIEW" has errors
------------------------------------------------------------------------
The best option you have is to keep database links alive and kicking, I presume.
Another option is to move procedures - that use those suspicious database links - out of that package and make them either standalone stored procedures so that if they become invalid, only they are invalid (and not the whole package), or - possibly - put those procedures (that share the same destiny) into a separate package.
Yet another option is to use dynamic SQL because Oracle doesn't care whether any objects involved are valid or not until you actually try to use them. Something like this:
SQL> create database link my_link
2 connect to whoever
3 identified by whatever
4 using 'database_that_does_not_exist';
Database link created.
SQL> create or replace view my_view as
2 select * from some_table#my_link;
select * from some_table#my_link
*
ERROR at line 2:
ORA-12154: TNS:could not resolve the connect identifier specified
SQL> create or replace procedure my_proc as
2 l_id number;
3 begin
4 select id into l_id
5 from my_view;
6 end;
7 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE MY_PROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/3 PL/SQL: SQL Statement ignored
5/8 PL/SQL: ORA-00942: table or view does not exist
But, with dynamic SQL:
SQL> create or replace procedure my_proc as
2 l_id number;
3 begin
4 execute immediate 'select id from my_view' into l_id;
5 end;
6 /
Procedure created.
SQL>
Looks OK, but not for long:
SQL> exec my_proc;
BEGIN my_proc; END;
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SCOTT.MY_PROC", line 4
ORA-06512: at line 1
SQL>
Yes, I know - not all code is simple enough to put it into dynamic SQL. Bigger it is, worse problems you have to maintain it, so that's just possibility I wouldn't really want to use.

How to catch the event where in PL/SQL code the first commit occurs in Oracle?

Is the way in Oracle automatically catch the event where in PL/SQL code the first commit occurs?
I have a big problem with PL/SQL procedure which should not do any commits but it does a commit somewhere.
This procedure runs a huge amount of pl/sql code, a lot of dynamic pl/sql code, some packages are wrapped and some packages are not granted for debug.
Maybe someone had it a similar problem and can help me?
Your PL/SQL block will never COMMIT the changes until and unless you have explicitly mentioned COMMIT.
However, you might have DDL statements executed as dynamic SQL which might be going for an implicit commit. Search for the commit in the code.
You could look into USER_SOURCE.
SELECT *
FROM USER_SOURCE
WHERE NAME = '<PROCEDURE NAME IN UPPER CASE>'
AND TYPE = 'PROCEDURE'
AND UPPER(TEXT) LIKE '%COMMIT%'
Update
To find the DDL statements, you could look for keywords like CREATE, DROP, ALTER
SELECT *
FROM USER_SOURCE
WHERE NAME = '<PROCEDURE NAME IN UPPER CASE>'
AND TYPE = 'PROCEDURE'
AND UPPER(TEXT) LIKE '%CREATE%'
OR UPPER(TEXT) LIKE '%DROP%'
OR UPPER(TEXT) LIKE '%ALTER%'
I found the answer:
ALTER SESSION DISABLE COMMIT IN PROCEDURE
This command disables the possibility of commit and, what is most
important for me the oracle error message shows the exact place where
in pl/sql code the commit is.
SQL> create or replace procedure tst_commit is
2 begin
3 dbms_output.put_line('before commit');
4 COMMIT;
5 dbms_output.put_line('after commit');
6 end tst_commit;
7 /
Procedure created
SQL> BEGIN
2 EXECUTE IMMEDIATE 'ALTER SESSION DISABLE COMMIT IN PROCEDURE';
3 INSERT INTO viliusg.log VALUES(SYSDATE,'test commit');
4 tst_commit;
5 dbms_output.put_line('THE END');
6 END;
7 /
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION DISABLE COMMIT IN PROCEDURE';
INSERT INTO viliusg.log VALUES(SYSDATE,'test commit');
tst_commit;
dbms_output.put_line('THE END');
END;
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at "FORPOST.TST_COMMIT", line 4
ORA-06512: at line 4

Including the schema name when calling a PL/SQL procedure doesn't work in one schema but does in another

This problem came up when trying out the Unit Testing capabilities of SQLDeveloper.
When running a test for a procedure that is created within my schema I am seeing an error however when the same procedure is run in one of the oracle supplied schemas it works without an issue.
SQL Developer generates the following calls:
1) This one doesn't work (error is shown below):
BEGIN
"IANC"."SIMPLE_PARAMETER"(P_X => 123);
END;
2) This one does:
BEGIN
"HR"."SIMPLE_PARAMETER"(P_X => 123);
END;
This is the procedure:
CREATE OR REPLACE PROCEDURE SIMPLE_PARAMETER
(
P_X IN NUMBER
)
IS
BEGIN
null;
END SIMPLE_PARAMETER;
The following is the output from SQLPLUS, where you can see when the procedure is run in my schema I see an error whilst when running the same procedure in another schema the procedure works as expected:
In case of need my I am using Oracle Enterprise Edition 11.2.0.1.0
Update
Screen shot showing procedure signatures
I should also mention that if I remove the schema name from the procedure call then the procedure runs and completes as expected.
Thanks in advance for any help received.
Are you sure that the SIMPLE_PARAMETER procedure in IANC is the same (or at least has the same signature) as the one in HR? What do you get from `DESCRIBE "IANC"."SIMPLE_PARAMETER".
(P.S. since your identifiers are all upper-case, you shouldn't need the double quotes at all.)
Added: Another possibility is that you have a package called IANC in the IANC schema, so Oracle is looking for a procedure in that package called SIMPLE_PARAMETER that does not exist. Example:
SQL> exec bigdecimaltest
PL/SQL procedure successfully completed.
SQL> exec dcosta.bigdecimaltest
PL/SQL procedure successfully completed.
SQL> create or replace package dcosta as
2 end;
3 /
Package created.
SQL> exec dcosta.bigdecimaltest
BEGIN dcosta.bigdecimaltest; END;
*
ERROR at line 1:
ORA-06550: line 1, column 14:
PLS-00302: component 'BIGDECIMALTEST' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
This seems like buggy behavior -- if the attempt to resolve the name as package.member doesn't succeed, I think Oracle ought to then try it as schema.object, but it looks like once it has found a match on the package name it won't reconsider that.

How to make Oracle error messages more verbose?

The message that drives me crazy is ORA-01008 - Not all variables bound.
Is there a way to know which one of the 42 possible variable names I have misspelled without staring at the monitor till my eyes pop out?
Update: I use ADO.NET to access the database. Perhaps it does lose some information in Oracle exceptions, as #Justin Cave has suggested. But I'm positive that the parameter name never appears even in SQL Plus.
In general, Oracle provides the line and column number of any errors, but it is up to the particular API you are using (unless you happen to be writing an OCI application, which is probably unlikely) as to whether and how those APIs are called. Since the answer is likely to end up being API-specific, what API are are you using and what does your code look like when the error occurs (i.e. JDBC, ODBC, OLE DB, etc)?
As an example, if I write a PL/SQL block with a misspelled variable name, SQL*Plus will report the line and column number of the error in addition to the error message. Many APIs, on the other hand, will just report the PLS-00201 error by default.
SQL> declare
2 i integer;
3 begin
4 j := 1;
5 end;
6 /
j := 1;
*
ERROR at line 4:
ORA-06550: line 4, column 3:
PLS-00201: identifier 'J' must be declared
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
Similarly, if you execute a SQL statement with an invalid variable name, SQL*Plus will get the column and line position and put a * under the offending character, i.e.
SQL> create table a( col1 number );
Table created.
SQL> insert into a( colN ) values ( 1 );
insert into a( colN ) values ( 1 )
*
ERROR at line 1:
ORA-00904: "COLN": invalid identifier
Most PL/SQL IDE's (TOAD, SQL Developer, etc.) will do something similar by interrogating the appropriate OCI APIs under the covers. Precisely how this is done, however, will depend on the API.
I don't know of any way to get Oracle to make the error more specific. Maybe some future version will improve this error message.
Instead of just staring at it, though, there are other things you can try. For example, convert each variable in the SQL statement to a literal one at a time, until the error goes away. If possible, generate the list of variable names instead of typing them manually.

Resources