Package referencing a private db link becomes periodically invalid - how to debug? - oracle

I reference a private db link inside a package but the package body becomes periodically invalid and I don't know why.
CREATE DATABASE LINK my_link
CONNECT TO foo IDENTIFIED BY bar
USING '(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = ...
CREATE OR REPLACE
PACKAGE TEST AS
PROCEDURE test;
END TEST;
/
CREATE OR REPLACE
PACKAGE BODY TEST AS
PROCEDURE test
AS
cur SYS_REFCURSOR;
BEGIN
OPEN cur FOR SELECT * FROM mytable#my_link;
END test;
END TEST;
/
SELECT COUNT(1)
FROM user_objects
WHERE object_name = 'TEST'
AND object_type = 'PACKAGE BODY'
AND status != 'VALID';
1
When I call that package it becomes valid. But in some time it's invalid again. How to debug?
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
Many thanks in advance.

Oracle invalidates things for its own internal reasons when dependencies are affected. As you noted, objects are automatically validated when then are again used. There is nothing to do here, or to debug.

The next time the package is invalid, use DBA_OBJECTS and DBA_AUDIT_TRAIL to try to find out who changed what objects when the package was invalidated. Make sure to run these queries before you recompile the package since recompiling will change the LAST_DDL_TIME column.
--Find when the package was modified, and any other objects modified around the same time.
select *
from dba_objects
order by last_ddl_time desc;
--Find activity around the same time as the object changes.
--(This query will only work if you have specific types of auditing enabled.)
select *
from dba_audit_trail
where timestamp between timestamp '2021-06-17 12:00:00' and timestamp '2021-06-17 13:00:00'
order by timestamp;
Although dependencies are complicated, and the objects may get automatically validated when they are needed, it's a good idea to track down these invalidations. In practice, databases either have zero invalid objects or hundreds of invalid objects so keep your database clean.

Related

How to know if a db-link is used somewhere in a DB

I would like to know if it exists an Oracle command to know if a DB-LINK (name: myBDLink) is used somewhere in a DB and how to display the objects (views,materialized views, procedures, functions, ...) which use it.
Could you please help me with that ?
Thanks for your help
Well, you could try to query various system views and see whether any of them contains a string you're looking for. As you want to check the whole database, you'll probably connect as a privileged user and check dba_ views; otherwise, all_ or user_ would do.
For example, to check procedures, functions, packages, ...:
select owner, name, type, line
from dba_source
where owner not in ('SYS', 'SYSTEM')
and lower(text) like '%mydblink%';
To check views, you'll need a function which will search through its LONG datatype column (as you can't use it directly in SQL):
create or replace function f_long(par_view in varchar2, par_String in varchar2)
return varchar2
is
l_text varchar2(32000);
begin
select text
into l_text
from dba_views
where owner not in ('SYS', 'SYSTEM')
and view_name = par_view;
return case when instr(lower(l_text), lower(par_string)) > 0 then 1
else 0
end;
end;
/
and then
select owner, view_name
from dba_views
where f_long(view_name, 'mydblink') = 1;
I excluded SYS and SYSTEM as they should not contain anything of users' stuff. Perhaps you'd want to exclude some more users.
To see some more (re)sources, query the dictionary, e.g.
select table_name, comments
from dictionary;
TABLE_NAME COMMENTS
------------------------------ --------------------------------------------------
USER_CONS_COLUMNS Information about accessible columns in constraint
definitions
ALL_CONS_COLUMNS Information about accessible columns in constraint
definitions
DBA_CONS_COLUMNS Information about accessible columns in constraint
definitions
<snip>
There is no complete answer. How would the database know of code that is outside of the database? It can't. So if you have a sql script, or some application that does not rely on stored procedures to do everything, the database will not know of them.
That said, for dependencies that are in stored procedures in the database, you can try this:
select *
from dba_dependencies
where referenced_link_name is not null
;
To add to the other (correct) answers that have been posted by #Littlefoot and #EdStevens, a quick-and-dirty analysis can also be made against the Automated Workload Repository (AWR).
The benefit of this approach is it will find usages of remote objects from SQL submitted to the database whether that SQL is in DBA_SOURCE or not (e.g., is embedded in an external application).
-- Find any objects referenced across a database link (sort of)
select object_node, object_name, count(distinct sql_id) sql_id_count
from dba_hist_sql_plan
where object_type = 'REMOTE'
group by object_node, object_name
order by object_node, object_name
;
The problem is that AWR data isn't 100% complete. First of all, it's not kept around forever, so a database link last used more than a month (or two months or however long your DBAs keep AWR data for) wouldn't be seen. Second of all, AWR only takes snapshots periodically, say every hour. So it's theoretically possible for a SQL to use a database link and then get aged out of the library cache before the next AWR snapshot.
I think the chance of missing something due to that last bit is small on the systems I work with. But, if you have poorly written applications (i.e., no bind variables) and limited shared pool space, it's something to worry about.

Create matview refresh fast on commit fails with ORA-12033

Oracle Database - Standard Edition - Version 12.1.0.2.0, platform Windows 64-bit
I'm getting ora-12033 error while trying to create mview, all necessary columns are already included in the mview log. When i'm trying to do same thing on 11g version it works, but 12c throwing ora error.
Please help me solve this problem or provide links that may help.
Here is code:
CREATE MATERIALIZED VIEW LOG ON contract_details
with rowid (count, contract_id) including new values;
CREATE MATERIALIZED VIEW m_contract_sum
refresh fast on commit
as
select d.contract_id as contract_id,
count(*) as count_grp,
count(d.count) as cnt_count,
sum(d.count) as sm_count
from contract_details d
group by d.contract_id;
Thanks in advance!
There might be a problem with extended stats, which are automatically created to gather stats on group of columns.
You can verify it by executing following query:
SELECT column_name, data_default, virtual_column, hidden_column
FROM dba_tab_cols
WHERE table_name = 'CONTRACT_DETAILS' AND hidden_column = 'YES';
If this is a case, you need to drop the stats (using dbms_stats.drop_extended_stats) before (re-)creating materialized view.
e.g.
BEGIN
dbms_stats.drop_extended_stats('master', 'contract_details', '(x, y)');
END;
/
Afterwards you probably would like to gather the stats again, by using
BEGIN
dbms_stats.create_extended_stats('master', 'contract_details', '(x, y)')
END;
/

existing state of package has been invalidated

I am facing this error.
I have two Schema Schema A and Schema B
Schema B contains a table my_table in which values are being Inserted.
There is also a triggger my_trigger written for my_table in schemaB for each row
CREATE OR REPLACE TRIGGER schemaB.my_trigger
ON schemaA.my_table
FOR EACH ROW
BEGIN
IF INSERTING THEN
schemaA.my_package.my_procedure (:NEW.field_A,NEW.field_B, :NEW.field_C);
END IF;
EXCEPTION
WHEN OTHERS THEN
Insert into my_log(DBMS_UTILITY.format_error_stack,sysdate);
END my_trigger;
/ AFTER INSERT
This trigger written on my_table of schemaB is calling a procedure which is present in Schema A.
However when the trigger is being fired I am getting the below error in my logs
ERROR: ORA-04061: existing state of package "schemaA.my_package" has been invalidated
ORA-04065: not executed, altered or dropped package "schemaA.my_package"
ORA-06508: PL/SQL: could not find program unit being called: "schemaA.my_package"
ORA-06512: at "schemaB.my_trigger", line 17 10/1/2015 6:38:07 PM
Also the procedure in schemaA is declared as PRAGMA_AUTONOMOUS_TRANSACTION
Is this some grants issue as i checked all the grants has been given, I have checked dependencies of the both trigger and procedure
and all seems to valid. Can you kindly help?
I have tried using Pragma serially_reusable in the calling package but still giving me same error
Many thanks
Possible issues you can have is:
The package/procedure you are calling is invalid
check this query whether you have an entry of your package or objects used in your package in this all_objects view
select * from all_objects where status = 'INVALID' and owner = 'SCHEMA_NAME';
Check your package is having global variables? if yes then check if those variable is not being changed by any other session
run below script to compile all the objects in your schema
begin
dbms_utility.compile_schema('SCHEMA_NAME',false);
end;
Last option if none of the above works then remove all the procedures/function from your package, add new function and try to run your function from the trigger. check if this works then your package is in special lock. after adding a new function it's state will be valid again and then you can add all your actual funcs/procs and remove the newly added one.

Calling a function on a remote database requires commit. SQL Developer

I have a requirement to call a function on a remote database (defined by a public database link) within a query. Everything works as expected except that when selecting "Disconnect" from the local database connection in SQL Developer it brings up the dialog:
Connection "localDB" has uncommited changes....
even though the remote function only reads from tables, and the invoking query isn't an update / insert / delete. I'm concerned that using this architecture may cause problems in the future where uncompleted transactions on the localDB diminish resources.
Have tried using the "PRAGMA AUTONOMOUS_TRANSACTION;" instruction in the remote db but to no avail. Any suggestions?
The following demonstrates the behaviour I'm experiencing:
RemoteDB function:
create or replace
FUNCTION FN_test (inempid in number) RETURN varchar2 is PRAGMA AUTONOMOUS_TRANSACTION;
sReturn varchar2(20);
BEGIN
sReturn:=to_char(sysdate,'dd-Mon-yyyy HH24:mi');
return sReturn;
END FN_test;
Invoke from localDB:
select fn_test#RemoteDB.World(123) from Dual;
Thanks!
Any remote call opens transaction - even this executes just query. Oracle can't predict what exactly you do on remote side and tries to prevent uncommitted distributed transaction.
In example below I mere created local database link connecting to native host and just requested data from DUAL table using db link. Oracle has opened the local transaction in respond:
SQL> create database link locallink connect to scott identified by tiger
2 using '127.0.0.1:1521/test';
Database link created.
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
SQL> select * from dual#locallink;
D
-
X
SQL> select dbms_transaction.local_transaction_id from dual;
LOCAL_TRANSACTION_ID
--------------------------------------------------------------------------------
17.13.10520
Autonomous transaction is useless because it opens and closes the transaction what is differ from the main one. So you need to commit changes in main transaction if you use remote calls.

Can I recover older Oracle pl/sql source code from a package body after i have replaced with newer code

I had created an Oracle PL/SQL package with a header and a body with lots of code.
Later, I ended up accidentally erasing the code from that body after reran the CREATE OR REPLACE PACKAGE BODY... statement with different source code (which actually I intended to save under a different package name).
Is there any way I can recover my older replaced source code from the package?
You might be able to get it back by using a flashback query on all_source.
e.g. my package body is currently at version 2, executing this query as a standard user:
SQL> select text
2 from all_source
3 where name = 'CARPENTERI_TEST'
4 and type = 'PACKAGE BODY';
TEXT
package body carpenteri_test
is
procedure do_stuff
is
begin
dbms_output.put_line('version 2');
end do_stuff;
end carpenteri_test;
10 rows selected.
I know I changed this around 9:30 this evening so after connecting as a SYSDBA user I ran this query:
SQL> select text
2 from all_source
3 as of timestamp
4 to_timestamp('04-JUN-2010 21:30:00', 'DD-MON-YYYY HH24:MI:SS')
5 where name = 'CARPENTERI_TEST'
6 and type = 'PACKAGE BODY';
TEXT
----------------------------------------------------------------------------
package body carpenteri_test
is
procedure do_stuff
is
begin
dbms_output.put_line('version 1');
end do_stuff;
end carpenteri_test;
10 rows selected.
More information on flashback can be found here. Tom Kyte also demostrates how to use flashback with all_source here.
Unless you have logging/auditing of DDL commands enabled, or a backup of the database, then the answer is almost certainly not
Database definitions, including stored procedures, should always be treated like source code, and maintained in a code repository

Resources