如果运行一个过程、函数或者包,或者对视图执行查询,Oracle会检查访问的对象的状态,如果对象状态不正确,则Oracle会尝试自动编译对象。
因此绝大部分情况下,可以直接尝试执行过程,来省略编译的步骤。但是有的时候,直接运行并不起作用。
看一个简单的例子。
在本地的tnsnames.ora中加入下面的配置:
TEST112 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.25.198.230)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test112)
)
)
下面建立本地的数据库链,指向远端的数据库:
SQL> CREATE DATABASE LINK TEST112
2 CONNECT TO TEST IDENTIFIED BY TEST
3 USING 'TEST112';
数据库链接已创建。
SQL> SELECT * FROM GLOBAL_NAME@TEST112;
GLOBAL_NAME
----------------------------------------------------------------------------
TEST112
建立一个视图访问远端T表,并建立一个过程,在过程中访问视图:
SQL> CREATE VIEW V_T112
2 AS SELECT ID FROM T@TEST112;
视图已创建。
SQL> CREATE OR REPLACE PROCEDURE P_TEST AS
2 BEGIN
3 UPDATE V_T112 SET ID = ID + 1;
4 END;
5 /
过程已创建。
SQL> EXEC P_TEST
PL/SQL 过程已成功完成。
下面修改TNSNAMES.ORA里面TEST112的配置,将配置的名称改变:
TEST1121 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.25.198.230)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test112)
)
)
需要注意,由于DATABASE LINK已经处于打开的状态,因此再次访问并不会报错,必须手工关闭数据库,再次访问远端对象,Oracle才会利用TNSNAMES.ORA重新解析数据库链:
SQL> EXEC P_TEST
PL/SQL 过程已成功完成。
SQL> ROLLBACK;
回退已完成。
SQL> ALTER SESSION CLOSE DATABASE LINK TEST112;
会话已更改。
SQL> EXEC P_TEST
BEGIN P_TEST; END;
*第 1 行出现错误:
ORA-12154: TNS: 无法解析指定的连接标识符
ORA-06512: 在 "TEST.P_TEST", line 3
ORA-06512: 在 line 1
检查过程和视图的状态:
SQL> SELECT OBJECT_NAME, STATUS
2 FROM USER_OBJECTS
3 WHERE OBJECT_NAME IN ('P_TEST', 'V_T112');
OBJECT_NAME STATUS
------------------------------ -------
P_TEST VALID
V_T112 VALID
显然Oracle并没有认为运行时的错误是由于对象失效造成的。
下面将TNSNAMES.ORA里面的配置修改回来:
TEST112 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.25.198.230)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test112)
)
)
重新执行过程P_TEST:
SQL> EXEC P_TEST
PL/SQL 过程已成功完成。
这个现象是正常的,下面再次重复刚才的步骤,将TNSNAMES.ORA中的配置修改为TEST1121,然后运行P_TEST过程:
SQL> EXEC P_TEST
PL/SQL 过程已成功完成。
SQL> ALTER SESSION CLOSE DATABASE LINK TEST112;
会话已更改。
SQL> EXEC P_TEST
BEGIN P_TEST; END;
*第 1 行出现错误:
ORA-12154: TNS: 无法解析指定的连接标识符
ORA-06512: 在 "TEST.P_TEST", line 3
ORA-06512: 在 line 1
所有的操作都和刚才一样,现在不一样的操作出现了,尝试直接访问视图:
SQL> SELECT * FROM V_T112;
SELECT * FROM V_T112
*第 1 行出现错误:
ORA-12154: TNS: 无法解析指定的连接标识符
SQL> ALTER VIEW V_T112 COMPILE;
警告: 更改的视图带有编译错误。
SQL> SELECT OBJECT_NAME, STATUS
2 FROM USER_OBJECTS
3 WHERE OBJECT_NAME IN ('V_T112', 'P_TEST');
OBJECT_NAME STATUS
------------------------------ -------
P_TEST INVALID
V_T112 INVALID
由于视图的重新编译,使得视图和过程的状态都变成INVALID。
下面将TNSNAMES.ORA中的配置修改正确,再次运行P_TEST过程:
SQL> EXEC P_TEST
BEGIN P_TEST; END;
*第 1 行出现错误:
ORA-06550: 第 1 行, 第 7 列:
PLS-00905: 对象 TEST.P_TEST 无效
ORA-06550: 第 1 行, 第 7 列:
PL/SQL: Statement ignored
执行仍然报错,这时手工编译P_TEST过程也是无效的:
SQL> ALTER PROCEDURE P_TEST COMPILE;
警告: 更改的过程带有编译错误。
SQL> SHOW ERR
PROCEDURE P_TEST 出现错误:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/1 PL/SQL: SQL Statement ignored
3/8 PL/SQL: ORA-04063: view "TEST.V_T112" 有错误
无论是直接运行过程,还是手工编译过程,都无法解决视图的问题,这时只能通过手工编译错误的视图才能解决这个错误。
SQL> ALTER VIEW V_T112 COMPILE;
视图已变更。
SQL> ALTER PROCEDURE P_TEST COMPILE;
过程已更改。
SQL> EXEC P_TEST
PL/SQL 过程已成功完成。