Oracle begin expected got create - oracle

I'm writing a PL/SQL program, I've created a procedure and the syntax is correct.
Running this on DataGrip.
`
declare
create or replace procedure salutation(x OUT number) is begin
x:= x*10;
end salutation;
begin
SYS.DBMS_OUTPUT.PUT_LINE('hello');
end;
`
I get error messages when I execute the code:
BEGIN expected, got 'create'.
[2022-12-04 23:58:09] [65000][6550]
[2022-12-04 23:58:09] ORA-06550: line 1, column 7:
[2022-12-04 23:58:09] PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
[2022-12-04 23:58:09] begin function pragma procedure subtype type
[2022-12-04 23:58:09] current cursor delete
[2022-12-04 23:58:09] exists prior
I don't think there's a problem with the syntax.
Also why does the DataGrip not allow DBMS_OUTPUT.PUT_LINE without the SYS. ? even though I've enabled the DBMSOUTPUT.

You can't have static DDL statements (like create procedure) within PL/SQL (you'd need to use dynamic SQL, but it's very rarely necessary anyway).
But if you're trying to declare a local procedure within your anonymous block - not create a permanent, stored procedure, then you don't need the create part:
declare
y number := 42;
procedure salutation(x IN OUT number) is begin
x:= x*10;
end salutation;
begin
SYS.DBMS_OUTPUT.PUT_LINE('hello');
-- call salutation here if you want...
salutation(y);
dbms_output.put_line(to_char(y));
end;
/
1 rows affected
dbms_output:
hello
420
fiddle
Note that I changed the argument to IN OUT - otherwise it would always be reset to null.
If you want to create a permanent stored procedure then do that separately, before you try to run your anonymous block:
create or replace procedure salutation(x IN OUT number) is begin
x:= x*10;
end salutation;
/
declare
y number := 42;
begin
SYS.DBMS_OUTPUT.PUT_LINE('hello');
-- call salutation here if you want...
salutation(y);
dbms_output.put_line(to_char(y));
end;
/
1 rows affected
dbms_output:
hello
420
fiddle
Also why does the DataGrip not allow DBMS_OUTPUT.PUT_LINE without the SYS. ?
That suggests your database is missing a public synonym for the package; not a DataGrip thing, you'd see the same behaviour using any client. You'd need to ask your DBA why it's missing and whether it can be reinstated. (I haven't included the schema prefix in the extra calls I added, but if those don't work for you then you'll need to add it.)

Related

Execution of Multiple procedures one after another is not working

I am trying to execute a procedure which in turn should execute four other procedures one after the other. How do I acheive this?
Create or replace procedure mainproc
as
begin
tack(400);
phno_insert;
address_insert;
academics_insert;
commit;
end;
Error report:
PLS-00905: Object phno_insert is invalid. PL/SQL: Statement ignored.
PLS-00905: Object address_insert is invalid. PL/SQL: Statement
ignored. PLS-00905: Object academics_insert is invalid. PL/SQL:
Statement ignored.
The problem seems to be in the fact that you have a procedure doing a DDL over an object that is statically referenced in another procedure; for example, if I define:
create table runtimeTable as select 1 as one from dual;
create or replace procedure createTable is
begin
execute immediate 'drop table runtimeTable';
execute immediate 'create table runtimeTable as select 1 as one from dual';
end;
create or replace procedure useTable is
vVar number;
begin
select one
into vVar
from runtimeTable;
--
dbms_output.put_line(vVar);
end;
create or replace procedure createAndUseTable is
begin
createTable;
useTable;
end;
/
when I try to execute createAndUseTable I get:
ORA-04068: existing state of packages has been discarded ORA-04065:
not executed, altered or dropped stored procedure "ALEK.USETABLE"
ORA-06508: PL/SQL: could not find program unit being called:
"ALEK.USETABLE" ORA-06512: at "ALEK.CREATEANDUSETABLE", line 4
ORA-06512: at line 1
If you strictly need to do a DDL runtime, you need to use dynamic SQL to reference the modified object; for example if I define the procedure useTable this way
create or replace procedure useTable is
vVar number;
begin
execute immediate
'select one
from runtimeTable'
into vVar;
--
dbms_output.put_line(vVar);
end;
the call to createAndUseTable will work:
SQL> exec createAndUseTable
1

How to execute one procedure within another procedure

Hi I am writing one procedure which will be called by the program and this procedure will further call to another procedure to perform different business logic. so I did something like this.
PROCEDURE calculator(service_id IN NUMBER, amount IN NUMBER) as
p_proc_name varchar(100);
begin
select sc.procedure_name into p_proc_name from test.procedure sc where sc.service_config_id = service_id;
begin
execute immediate (p_proc_name) using 1;
exception when NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('p_proc_name = ' || p_proc_name);
end;
end sb_referal_calculator;
PROCEDURE f_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end f_service;
PROCEDURE d_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end d_service;
So here calcultor procedure will find the another procedure name dynamically and try to execute it with parameter. But it gives an error.
It is just a test program.
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.CONNECT_TCP( '10.1.26.70', '55891' )
Debugger accepted connection from database on port 55891.
ORA-00900: invalid SQL statement
ORA-06512: at "test.demo_pkg", line 38
ORA-06512: at line 8
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.DISCONNECT()
Process exited.
I really do not how this procedure will work to perform this task. I remembered it was running and I was doing testing. But really do not what i have did and stop working.
Please correct me what i doing wrong.
Thanks
When you use execute immediate it runs the dynamic statement in an SQL context that isn't able to see your PL/SQL context. That has several impacts here. Firstly, you have to call your procedure from PL/SQL so you need to create an anonymous block, as Egor Skriptunoff said, and exactly the format you need depends on what the table (and thus your vaiable) contains. The shortest it might be is:
execute immdiate 'begin ' || p_proc_name || ' end;' using 1;
But that assumes the varible contains a value like:
test_pkg.d_service(:arg);
If it only contains the name of the procedure with no arguments and no package qualifier, i.e. just d_service, it might need to be as much as:
execute immdiate 'begin test_pkg.' || p_proc_name || '(:arg); end;' using 1;
Or something in between.
The other impact is that the procedure name has to be public as it is effectively being called from outside the package when it's invoked dynamically; so it has to be declared in the package specification. That may already be the case here from the order the procedures are appearing in the body.
But if you are always calling procedures in the same package, and since you must then have a limited number of possible values, it might be simpler to avoid dynamic SQL and use the value to decide which procedure to call:
case p_proc_name
when 'f_service' then
f_service(1);
when 'd_service' then
d_service(1);
-- etc.
end case;
That also lets you call private procedures.

Using Dynamic SQL With Objects

I have an object and I want to update an object table from with it dynamically. As an example
create or replace type typA as object
(
a number,
member procedure insert_self
);
/
create or replace type body typA is
member procedure insert_self is
begin
null;
end;
end;
/
create table typA_table of typA;
/
create or replace type body typA is
member procedure insert_self is
sql_stmt varchar2(200);
begin
sql_stmt := 'insert into typ_a_table values(self)';
execute immediate sql_stmt;
end;
end;
/
declare
l_typ typA;
begin
l_typ := typA(123);
l_typ.insert_self;
end;
But this returns an error due to the line which specifies 'self' in the sql_stmt.
Error report -
ORA-04063: table "SYSTEM.TYP_A_TABLE" has errors
ORA-06512: at "SYSTEM.TYPA", line 6
ORA-06512: at line 5
04063. 00000 - "%s has errors"
*Cause: Attempt to execute a stored procedure or use a view that has
errors. For stored procedures, the problem could be syntax errors
or references to other, non-existent procedures. For views,
the problem could be a reference in the view's defining query to
a non-existent table.
Can also be a table which has references to non-existent or
inaccessible types.
*Action: Fix the errors and/or create referenced objects as necessary.
Is there anyway to get around this error where I'm referencing variables that aren't easily converted to a string?
Can you not simply change your member procedure to something like the below, seems to work for me.
create or replace type body typA is
member procedure insert_self is
sql_stmt varchar2(200);
begin
insert into typ_a_table values(self.a);
end;
end;

SQLPLUS object system. is invalid

I'm stuck with some simple procedure and I can't figure out why.
This is my code, which I'm running in sqlplus:
CREATE OR REPLACE PROCEDURE NormalizeName(fullname IN NVARCHAR2)
IS
BEGIN
SELECT TRIM(fullname) INTO fullname FROM DUAL;
DBMS_OUTPUT.PUT_LINE(fullname);
END NormalizeName;
/
BEGIN
NormalizeName('Alice Wonderland ');
END;
/
When I run it, I get the error:
Warning: Procedure created with compilation errors.
NormalizeName('Alice Wonderland ');
*
ERROR at line 2:
ORA-06550: line 2, column 2:
PLS-00905: object SYSTEM.NORMALIZENAME is invalid
ORA-06550: line 2, column 2:
PL/SQL: Statement ignored
What's wrong?
1) Never create objects in the SYS or SYSTEM schema. Those are reserved for Oracle. If you want to create objects, create a new schema first.
2) When you see that a procedure has been created with compilation errors in SQL*Plus, type show errors to see the errors.
3) The error appears to be that your SELECT statement is trying to write to the fullname parameter. But that parameter is defined as an IN parameter, not IN OUT, so it is read-only. If you define the parameter as IN OUT, though, you could not pass a string constant to the procedure, you'd need to define a local variable in your calling block. It doesn't make a lot of sense to have a procedure that doesn't do anything other than call dbms_output since there is no guarantee that anyone will see the data written to that buffer. My guess is that you really want a function that returns a normalized name. Something like
CREATE OR REPLACE FUNCTION NormalizeName( p_full_name IN VARCHAR2 )
RETURN VARCHAR2
IS
BEGIN
RETURN TRIM( p_full_name );
END;
which you can then call
DECLARE
l_normalized_name VARCHAR2(100);
BEGIN
l_normalized_name := NormalizeName( 'Alice Wonderland ' );
dbms_output.put_line( l_normalized_name );
END;
If you really need a procedure because this is a homework assignment
CREATE OR REPLACE PROCEDURE NormalizeName( p_fullname IN VARCHAR2 )
AS
BEGIN
dbms_output.put_line( TRIM( p_fullname ));
END;
In the real world, you should only be using procedures when you want to manipulate the state of the database (i.e. you're doing INSERT, UPDATE, DELETE, MERGE, etc.). You use functions when you want to perform calculations without changing the state of the database or when you want to manipulate data passed in parameters.

Outputting a single row in stored procedure (oracle)

I'm trying to follow the example at http://dba-oracle.com/t_pl_sql_plsql_select_into_clause.htm
But when i however do
create or replace PROCEDURE age
is
declare
info movie%rowtype;
BEGIN
dbms_output.enable();
select * into info from movie where mo_id=1;
dbms_output.put_line('The name of the product is ' || info.mo_id);
END age;
/
It gives a couple of errors:
Error(4,1): PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior external language The symbol "begin" was substituted for "DECLARE" to continue.
and
Error(14,8): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
what's wrong with it?
Try with the following, you do not need to have declare inside a procedure.
create or replace PROCEDURE
age
is
info movie%rowtype;
BEGIN
--dbms_output.enable();
select * into info from movie where mo_id=1;
dbms_output.put_line('The name of the product is ' || info.mo_id);
END age;
/
and to execute the procedure you could do
exec age
There are a couple of things in your code to take a look at:
First. As #Polppan has already mentioned, remove DECLARE keyword from your stored procedure. There is no need of it. You will need it however when you write anonymous PL/SQL block. Second. If you use dbms_output.enable() in your procedure then to display lines, I assume you are using sql*plus for this, you will need to invoke dbms_output.get_lines() otherwise it will not give you desired result. So to simplify that use set serveroutput on command of sql*plus to enable output. And do not mix dbms_output.enable() and setserveroutput on - use either of them. Not both. Here is an example:
SQL> CREATE OR REPLACE PROCEDURE Print_data
2 is
3 l_var_1 varchar2(101);
4 BEGIN
5 select 'Some data'
6 into l_var_1
7 from dual;
8 dbms_output.put_line(l_var_1);
9 END;
10 /
Procedure created
SQL> set serveroutput on;
SQL> exec print_data;
Some data
PL/SQL procedure successfully completed
SQL>

Resources