Compiling a stored procedure with local functions on Oracle 9i - oracle

I have a legacy application that is still running on Oracle 9i. We'll me migrating to 11g later this year, but for the moment, I need to run some test scripts on the current environment.
My test uses a stored procedure, but when I try to compile the procedure I get the following error.
"PLS-00103: Encountered the symbol "end-of-file" when expecting one of
the following:"
This is strange as the stored procedure compiled on the same server about two years ago. The only difference is that the database has been overwritten with a copy of the production database since (this procedure is only used in test, so is not present in the production database).
The problem seems to stem from local functions within the procedure. Here's a very simple procedure that illustrates the error I'm getting:
create or replace procedure test
as
l_dt date;
function dt
return date
is
begin
return sysdate;
end;
begin
l_dt := dt;
dbms_output.put_line(to_char(l_dt, 'dd-mm-yyyy'));
end;
Edit: Here's the complete output when I try to compile this:
1 ORA-24344: success with compilation error
10 PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
10
10 begin function package pragma procedure form
13 ORA-06550: line 2, column 3:
13 PLS-00201: identifier 'L_DT' must be declared
13 ORA-06550: line 2, column 3:
13 PL/SQL: Statement ignored
14 ORA-06550: line 3, column 32:
14 PLS-00201: identifier 'L_DT' must be declared
14 ORA-06550: line 3, column 3:
14 PL/SQL: Statement ignored
14 SQL parse error location
It definitely seems to be the local function that's causing it, as if I take it out, it compiles just fine. Here's the above procedure with the local function removed, and that working:
create or replace procedure test
as
l_dt date;
begin
l_dt := sysdate;
dbms_output.put_line(to_char(l_dt, 'dd-mm-yyyy'));
end;
I wonder if anyone else has encountered this problem, or knows if there's any reason local functions wouldn't compile under Oracle 9i?
Thanks,
James

The error is being reported against line 10, after the end of the function, so the enclosing procedure isn't being parsed properly. What you're doing is fine though, and works through other clients, and with the version of SqlDbx I tried. It looks like the procedure is being treated as two statements, and sent to the database in two chunks, neither of which is valid on its own.
This problem is reported on the SqlDbx Oracle forum, which mentions the bug exists in versions 3.64 and 4.0. It doesn't appear to be specific to the Oracle version. On 2014-04-14 the response was:
This is a bug and it will be fixed in a follow up to the latest release in about two weeks.
The release notes for version 4.1 include:
Fixes:
1. Corrupted text returned in Unicode version
2. Error parsing nested function (Oracle)
...
So you need to upgrade to version 4.1 or later; the current version is 4.3, and I don't see this problem with that version against a 9i or 11g database.

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.

Object is invalid PLSQL Procedure

I use a dataset that has billing information:
Table Image
And I want to create a procedure that gives information about a specific bill by giving an invoice id
CREATE OR REPLACE PROCEDURE print_information(
invoiceID varchar(11);
) IS
p_smtable supermarket%ROWTYPE;
BEGIN
SELECT * INTO p_smtable FROM SUPERMARKET
WHERE invoice_id = invoiceID;
DBMS_OUTPUT.PUT_LINE(p_smtable.brancj || p_smtable.city);
END;
The compilation is successful.
Compile
begin
print_information('750-67-8428');
end;
But I get an error that says:
Error starting at line : 12 in command -
begin
print_information('750-67-8428');
end;
Error report -
ORA-06550: line 2, column 1:
PLS-00905: object SYSTEM.PRINT_INFORMATION is invalid
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
The code in the screenshot is different to the version in your question, but both have an error at line 2. The parameter should be varchar2 or supermarket.invoice_id%type, with no semicolon.
Also, we normally use a p_ prefix for parameters, not variables. (There are other conventions, but whatever you use, p_ for a variable is just confusing.)
A fixed version might be:
create or replace procedure print_information
( p_invoice_id supermarket.invoice_id%type )
as
l_market supermarket%rowtype;
begin
select * into l_market
from supermarket
where invoice_id = p_invoice_id;
dbms_output.put_line(l_market.brancj || ' '|| l_market.city);
end;
Whatever tool you are using for development, you need to become familiar with how to display compilation errors.
brancj might be a typo for branch.
I've assumed you want a space between branch and city, otherwise the output would be something like TottenhamLondon rather than Tottenham London.
In Oracle a schema belongs to one user, created with the CREATE USER command. An Oracle Database is the entire thing (all users, all data, storage, memory, processes, everything) so you would not normally create one for something like this.

Oracle PLSQL: different behavior with two different DBs

I wrote myself a little PL/SQL utility. Executing it (using SQL-Developer) against one DB (an Oracle XE installation on my Windows 10 Laptop) it works perfectly fine, but executing it against an other DB (also Oracle XE but on a Linux server) I am getting compile errors in my script!?!? How can that be?
The errors I get are:
ORA-06550: line 17, column 35:
PLS-00491: numeric literal required
ORA-06550: line 18, column 35:
PLS-00491: numeric literal required
ORA-06550: line 19, column 35:
PLS-00491: numeric literal required
ORA-06550: line 20, column 35:
PLS-00491: numeric literal required
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
The referenced locations are in this section at the begin of my script:
DECLARE
-- limits and boundaries
MAX_NAME_LENGTH CONSTANT NUMBER(3) := 30; -- for table and column names
MAX_VALUE_LENGTH CONSTANT NUMBER(5) := 10000; -- for column values
-- our starting point:
m_owner VARCHAR2(MAX_VALUE_LENGTH) := 'C##TEST';
m_start_table_name VARCHAR2(MAX_NAME_LENGTH) := 'XML_MELDUNG_QUEUE';
m_start_column_name VARCHAR2(MAX_NAME_LENGTH) := 'XML_MELDUNG_ID';
m_start_value VARCHAR2(MAX_VALUE_LENGTH) := '5647';
...
and the exact spot turned out to be the usages of the constants, i.e. the "...(MAX_....)"-clauses.
It seems as if on the second system the CONSTANT-definitions and the usage of these constants in further declarations does not work the same way as it does when targeting my local DB.
I am completely puzzled! What is the problem here? Why would such a PL/SQL declaration work using one Oracle XE DB but not when using another? I mean: I would understand, if some entity can not be found, but compile errors (or not) depending on the DB used???
Any idea or pointer?
Declaring variable lengths using constants is a feature added in Oracle Database 12.2.
So I suspect that your local installation of XE is 18c. And the other is 11.2.
You can verify this by running:
select * from v$version;

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