how to increase column length without making dependent types invalid in oracle - oracle

I need to increase a column length in oracle table. But there is type defined on same table inside a package specification. This package is being used in more than 1000 packages.
So when I alter column, all packages become invalid.
Is there a way, so I can increase column length without making dependent type invalid.
Thanks.

You don't need to do anything; Oracle will recompile (or, at least try to do so) those packages and make them VALID (unless something else prevents that).
Here's a simple demonstration.
Test case first:
SQL> create table test (name varchar2(5));
Table created.
SQL> insert into test
2 select 'Littl' from dual union all
3 select 'Foot' from dual;
2 rows created.
SQL> create or replace package pkg_test as
2 function f_test return test.name%type;
3 end;
4 /
Package created.
SQL> create or replace package body pkg_test as
2 function f_test return test.name%type is
3 retval test.name%type;
4 begin
5 select max(name) into retval from test;
6 return retval;
7 end;
8 end;
9 /
Package body created.
SQL>
Let's check package's status and see function's result:
SQL> select object_name, status From user_objects where object_name = 'PKG_TEST';
OBJECT_NAM STATUS
---------- -------
PKG_TEST VALID
PKG_TEST VALID
SQL> select pkg_test.f_test from dual;
F_TEST
--------------------------------------------------------------------------------
Littl
SQL>
Everything is OK.
Now, enlarge the column and see what happens:
SQL> alter table test modify name varchar2(10);
Table altered.
SQL> select object_name, status From user_objects where object_name = 'PKG_TEST';
OBJECT_NAM STATUS
---------- -------
PKG_TEST INVALID
PKG_TEST INVALID
SQL> select pkg_test.f_test from dual;
F_TEST
--------------------------------------------------------------------------------
Littl
SQL> select object_name, status From user_objects where object_name = 'PKG_TEST';
OBJECT_NAM STATUS
---------- -------
PKG_TEST VALID
PKG_TEST VALID
SQL>
See? It just works. Package was initially INVALID, was recompiled in the background and became VALID.
So, no worries. I'd just say congratulations you decided to declare everything so that it inherits column's datatype. If you hardcoded it, then you'd have a BIG problem in manually modifying all those variables, whatnot, to make everything work.

You can check online table redefinition in which case only affected column's dependent objects will become invalid. For example if the column you are altering is not dependant on the type in the same table declared in packages then those packages will remain valid.Even for normal alter command this condition applies but online redefinition allows using a interim table to support dml operations during the alterations
Anyway since it is a production system I suggest testing this feature in UAT and then work it out in production

Related

sql developer, function and procedures gets out of compiling

I work in a company where there are many processes that are executed on an ORACLE server, with lots of functions and procedures that are constantly running different data (all types of data)
Yesterday, we noticed a slowdown in the system, and even a partial halt in traffic on the DB side. After testing our DBA man using SQL DEVELOPER, he founds about 15 functions and procedures that came out of compilation.
That is, no changes were made to them, but the icons of all of those 15 functions/procedures showed that they were not compiled, it was necessary to click on 'Recompile' to use them again, thus restoring the system to normal operation.
Up to this moment, we do not know how to explain what caused 15 functions and a procedure to go out of compilation at the same time, but certainly no employee has touched on these functions / procedures. First time such a thing happens to us, and we have not heard of a similar case.
Does anyone have any idea what could have made this happen? Maybe a problematic type of information got into DB that caused a problematic chain reaction?
Maybe some other object - that is used by all those functions and procedures - was modified (e.g. package specification), and it "invalidated" all objects that reference it.
Basically, you don't have to do anything - Oracle will automatically recompile them as soon as someone calls them.
Here's an example.
Package with a single function:
SQL> create or replace package pkg_test as
2 function f_test (par_number in number) return number;
3 end;
4 /
Package created.
SQL> create or replace package body pkg_test as
2 function f_test (par_number in number) return number
3 is
4 begin
5 return par_number;
6 end;
7 end;
8 /
Package body created.
Standalone function that references (calls) function from the package;
SQL> create or replace function f_test_2 (par_number in number)
2 return number
3 is
4 begin
5 return pkg_test.f_test(par_number);
6 end;
7 /
Function created.
What is its status? It is VALID:
SQL> select object_name, object_type, status from user_objects where object_name = 'F_TEST_2';
OBJECT_NAME OBJECT_TYPE STATUS
-------------------- ------------------- -------
F_TEST_2 FUNCTION VALID
Does it work? YES:
SQL> select f_test_2 (100) result from dual;
RESULT
----------
100
SQL>
OK, let's now slightly modify the packaged function's spec (I'll add the DEFAULT clause):
SQL> create or replace package pkg_test as
2 function f_test (par_number in number default 0) return number;
3 end;
4 /
Package created.
SQL> create or replace package body pkg_test as
2 function f_test (par_number in number default 0) return number
3 is
4 begin
5 return par_number;
6 end;
7 end;
8 /
Package body created.
I didn't modify standalone function f_test_2. What is its status? It is now INVALID:
SQL> select object_name, object_type, status from user_objects where object_name = 'F_TEST_2';
OBJECT_NAME OBJECT_TYPE STATUS
-------------------- ------------------- -------
F_TEST_2 FUNCTION INVALID --> see? INVALID
Can I use it (without recompiling it)? Yes, I can:
SQL> select f_test_2 (500) result from dual;
RESULT
----------
500
SQL>
Usually this occurs when someone changes a dependency (for example: TYPE, TABLE, FUNCTION, PROCEDURE, PACKAGE, etc.) of the function/procedure.
For example:
CREATE TYPE obj IS OBJECT (a INT, b INT);
CREATE PROCEDURE proc(v_obj IN obj)
IS BEGIN NULL; END;
/
Then both are valid. If you then do:
CREATE OR REPLACE TYPE obj IS OBJECT (a NUMBER(5,0), b NUMBER(5,0));
Then SELECT object_name, object_type, status FROM USER_OBJECTS; outputs:
OBJECT_NAME
OBJECT_TYPE
STATUS
OBJ
TYPE
VALID
PROC
PROCEDURE
INVALID
If you then do:
ALTER PROCEDURE proc COMPILE;
Then the procedure is valid again.
db<>fiddle here

SQL statement ignored and missing opening parenthesis

I get these errors during a creation of a trigger but I don't understand why
create or replace NONEDITIONABLE TRIGGER magazzino_bef_ins
BEFORE INSERT ON MAGAZZINO
FOR EACH ROW
DECLARE
tempcodice varchar2(8);
cacc char(3);
ogg int;
CURSOR cursore_disp IS
SELECT cacciatore, oggetto
FROM TABLE EDDY.disponibilita
WHERE ID_DISPONIBILITA = :NEW.disponibilità;
BEGIN
CURSOR cursore_disp IS
SELECT cacciatore, oggetto
FROM TABLE DISPONIBILITA
WHERE ID_DISPONIBILITA = :NEW.disponibilità;
open cursore_disp;
fetch cursore_disp into cacc,ogg;
temp:= pk_gestione_magazzino.genera_catalogo(cacc,ogg);
:new.codcatalogo:=temp;
END;
The errors are:
Error(5,9): PL/SQL: SQL Statement ignored
Errore(6,20): PL/SQL: ORA-00906: missing opening parenthesis
Errore(9,8): PLS-00103: encountered symbol "CURSORE_DISP" instead of one of the following: := . ( # % ;
I can't understand these errors, I'm just trying to take the values from a table in where the id inserted is equal in the other table.
Here's how. I created test environment which is kind of stupid, but it makes the following code work.
SQL> create table magazzino (disponibilita number, codcatalogo varchar2(8));
Table created.
SQL> create table disponibilita (cacciatore char(3), oggetto number, id_disponibilita number);
Table created.
SQL> create or replace package pk_gestione_magazzino as
2 function genera_catalogo (cacc number, ogg number) return varchar2;
3 end;
4 /
Package created.
SQL> create or replace package body pk_Gestione_magazzino as
2 function genera_catalogo (cacc number, ogg number) return varchar2 is
3 begin
4 return 'Little';
5 end;
6 end;
7 /
Package body created.
Trigger which causes you trouble: no need for a cursor; moreover, you have two of them (was it just a typo)? It looks as if you used it to avoid no data found error. If so, don't do it - it just makes confusion. Handle exceptions properly. By the way, you "forgot" to close the cursor.
SQL> create or replace trigger magazzino_bef_ins
2 before insert on magazzino
3 for each row
4 declare
5 cacc char(3);
6 ogg int;
7 begin
8 select cacciatore, oggetto
9 into cacc, ogg
10 from disponibilita
11 where id_disponibilita = :new.disponibilita;
12
13 :new.codcatalogo := pk_gestione_magazzino.genera_catalogo (cacc, ogg);
14 end;
15 /
Trigger created.
Testing:
SQL> insert into disponibilita values (1, 1, 1);
1 row created.
SQL> insert into magazzino (disponibilita) values (1);
1 row created.
SQL> select * From magazzino;
DISPONIBILITA CODCATAL
------------- --------
1 Little
SQL>
Works, kind of.

declare and call variable in trigger in oracle

I am trying to declare a variable and accessing it again to update same table for a particular id.(Updating STATUS from 'E' to 'R')
create or replace trigger resume_trgr
before update on temp_jobs
DECLARE
job_status varchar(2);
begin
select STATUS into :job_status from temp_jobs where id=6120;
if :job_status='E'
then
update temp_jobs set STATUS='R' where id=6120;
end if;
end;
/
But it returning error while executing above code. Error code is below:
Trigger resume_trgr compiled
Errors: check compiler log
Error(5,27): PLS-00049: bad bind variable 'STATUS'
In the question you said that the error refers to STATUS, but that doesn't match your posted code You shoudl be getting two errors referring to JOB_STATUS.
That's because it's defined as a local variable, and you're trying to refer to it as a bind variable. It should not have the colon prefix; so this compiles:
create or replace trigger resume_trgr
before update on temp_jobs
declare
job_status temp_jobs.status%type;
begin
select STATUS into job_status from temp_jobs where id=6120;
if job_status='E'
then
update temp_jobs set STATUS='R' where id=6120;
end if;
end;
/
as does this, which skips the variable completely:
create or replace trigger resume_trgr
before update on temp_jobs
begin
update temp_jobs set STATUS='R' where id=6120 and status = 'E';
end;
/
Whether that's a useful, valid or sensible thing to be doing inside a trigger is another matter. It seems like a separate update you should be doing manually before your 'real' update, possibly in a procedure - if you really want to always update the row for that specific ID regardless of whatever else you are actually doing in your 'real' (triggering) update.
If what you are really trying to do is make sure the status changes to R even if the caller doesn't explicitly do that, then you probably want a row-level trigger that sets the pseudorow value, rather than a statement-level trigger with a hard-coded ID.
Error you got is ... well, strange. A few comments:
There's no variable STATUS in your code.
When selecting into a variable, you don't need a colon (i.e. it is not into :job_status but into job_status).
You should rather use VARCHAR2 datatype, not VARCHAR.
That should, probably, be a row-level trigger (so you miss the FOR EACH ROW) and, once you fix everything, you'll hit the mutating table error
Why did you hardcode ID? Is this really going to do something only for that ID?
What you might do is this: first, test case:
SQL> create table temp_jobs
2 (id number,
3 status varchar2(10));
Table created.
SQL> insert into temp_jobs values (1, 'E');
1 row created.
SQL> insert into temp_jobs values (6120, 'E');
1 row created.
SQL> select * from temp_jobs;
ID STATUS
---------- ----------
1 E
6120 E
Trigger: note the differences between your and my code.
SQL> create or replace trigger resume_trgr
2 before update on temp_jobs
3 for each row
4 DECLARE
5 JOB_STATUS VARCHAR2(2);
6 begin
7 :new.status := case when :old.status = 'E' then 'R'
8 else :new.status
9 end;
10 end;
11 /
Trigger created.
Testing:
SQL> update temp_jobs set status = 'Y' where id = 6120;
1 row updated.
SQL> select * from temp_jobs;
ID STATUS
---------- ----------
1 E
6120 R
SQL> update temp_jobs set status = 'Y' where id = 6120;
1 row updated.
SQL> select * from temp_jobs;
ID STATUS
---------- ----------
1 E
6120 Y
SQL>

ALL_PROCEDURES view doesn't show the PROCEDURE_NAME

Why can't I see my procedure in user_procedures view? Why is the procedure_name filter on all_procedures view returns no rows.
This question is primarily to aid those who are searching for a similar question. I hope that anyone looking for such question would find a answer here.
Test case :
SQL> show user
USER is "LALIT"
SQL> CREATE OR REPLACE
2 PROCEDURE new_proc
3 AS
4 BEGIN
5 NULL;
6 END;
7 /
Procedure created.
SQL>
SQL> SELECT owner,
2 object_name,
3 procedure_name,
4 object_type
5 FROM all_procedures
6 WHERE owner='LALIT'
7 AND procedure_name='NEW_PROC';
no rows selected
SQL>
From documentation,
ALL_PROCEDURES lists all functions and procedures, along with
associated properties. For example, ALL_PROCEDURES indicates whether
or not a function is pipelined, parallel enabled or an aggregate
function. If a function is pipelined or an aggregate function, the
associated implementation type (if any) is also identified.
It doesn't clarify whether it would list a STAND ALONE PROCEDURE and a procedure wrapped in a PACKAGE the same way or does it consider it differently. Since, the procedure_name would not list the name of a stand alone procedure as seen in the test case in the question above.
PROCEDURE_NAME column will only have the procedure name for the procedures which are part of a PACKAGE. For STAND ALONE PROCEDURES you need to use OBJECT_NAME.
SQL> show user
USER is "LALIT"
SQL> CREATE OR REPLACE
2 PROCEDURE new_proc
3 AS
4 BEGIN
5 NULL;
6 END;
7 /
Procedure created.
SQL>
SQL> SELECT owner,
2 object_name,
3 procedure_name,
4 object_type
5 FROM all_procedures
6 WHERE owner='LALIT'
7 AND object_name='NEW_PROC';
OWNER OBJECT_NAME PROCEDURE_NAME OBJECT_TYPE
----- --------------- --------------- ---------------
LALIT NEW_PROC PROCEDURE
SQL>
You could get the list of procedures using procedure_name only if it is wrapped in a package.
SQL> -- package
SQL> CREATE OR REPLACE
2 PACKAGE new_pack
3 IS
4 PROCEDURE new_proc;
5 END new_pack;
6 /
Package created.
SQL>
SQL> -- package body with a procedure
SQL> CREATE OR REPLACE
2 PACKAGE BODY new_pack
3 IS
4 PROCEDURE new_proc
5 IS
6 BEGIN
7 NULL;
8 END;
9 END new_pack;
10 /
Package body created.
SQL> SELECT owner,
2 object_name,
3 procedure_name,
4 object_type
5 FROM all_procedures
6 WHERE owner='LALIT'
7 AND procedure_name='NEW_PROC';
OWNER OBJECT_NAME PROCEDURE_NAME OBJECT_TYPE
----- --------------- --------------- -----------
LALIT NEW_PACK NEW_PROC PACKAGE
SQL>
Now you could see the procedure_name as the actual procedure, and the object_name as the package_name.
Of course, mostly in production systems we would have packages, and not stand alone procedures. But, while testing and demos, we do compile and run stand alone procedures. So, it is good to know how Oracle maintains the information in *_PROCEDURES views.

Create Oracle procedure error - declare custom type

I'm attempting to create a procedure in Oracle Express Server (Application Express 2.1.0.00.39) using the web interface.
This is the SQL I'm running via the SQL Commands option in the web interface
CREATE OR REPLACE PROCEDURE my_procedure (listOfNumbers num_list,
v_value varchar2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE my_table
SET my_column = v_value
WHERE my_row_id IN (SELECT column_value
FROM TABLE(listOfNumbers));
COMMIT;
END;
UPDATE:
Changed SELECT column_value FROM TABLE to SELECT column_value FROM TABLE(listOfNumbers) but now I get the following error:
PLS-00201: identifier 'num_list' must
be declared
UPDATE 2:
Here is how I created my type:
CREATE OR REPLACE TYPE "num_list" as table of NUMBER(38,1)
/
Seems the error is being caused on the parameter declaration line:
(listOfNumbers num_list, v_value varchar2)
Below is the object details as displayed by the Oracle Database Express Edition web interface.
Try ...TABLE(CAST(listOfNumbers AS num_list)).
The SQL parser simply sees a bind placeholder in place of listOfNumbers, and since it's a custom type you need to tell it what type it is.
This will only work if num_list has been defined as a type in the schema, not just declared as a type in a PL/SQL block.
Your code works - providing the array type has been declared correctly (see below). As you are still having a problem I suspect that is where you are going wrong. But you need to post the code you are using to create the NUM_LIST type in order for us to correct it.
My test data:
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
APC 1
XYZ 2
JFK 3
SQL>
In order to use a type in a SQL statement we must create it as a SQL object:
SQL> create type num_list as table of number;
2 /
Type created.
SQL>
SQL>
SQL> create or replace procedure my_procedure
2 (listofnumbers num_list,
3 v_value varchar2)
4 is
5 begin
6
7 update my_table
8 set my_column = v_value
9 where my_row_id in (select column_value
10 from table(listofnumbers));
11
12 end;
13 /
Procedure created.
SQL>
Executing the procedure:
SQL> declare
2 n num_list := num_list(1,3);
3 begin
4 my_procedure (n , 'FOX IN SOCKS');
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
And lo!
SQL> select * from my_table
2 /
MY_COLUMN MY_ROW_ID
-------------------- ----------
FOX IN SOCKS 1
XYZ 2
FOX IN SOCKS 3
SQL>
Apparently I was creating the type with quotes around the name:
The following didn't work:
CREATE OR REPLACE TYPE "NUMBER_T" as table of NUMBER(38,1)
When I did it without the quotes and then created the procedure, it was able to recognize it.
The following did work:
CREATE OR REPLACE TYPE NUMBER_T as table of NUMBER(38,1)
I'm not sure why, but it worked.

Resources