15. http://emag.csdn.net
1 数学 98
2 语文 86
2 数学 90
2 政治 87
3 语文 93
3 数学 88
3 英语 88
3 政治 97
9 rows selected.
第一种转换方式:
需求描述:查看每个年级在系统中存在的科目信息,并各年级的科目信息按下面的格式
显示:
GRADE_ID SUBJECT_NAME
1 语文 数学
2 语文 数学 政治
3 语文 数学 英语 政治
分析:在要求得到的结果中,每个年级的科目将变成一条记录,而且每个年级的科目是
不固定的。所以考虑写个函数来解决,输入年级信息,使用游标得到该年级的所有科目信息
并返回值。
1、建函数:
SQL> create or replace function test_fun(p_grade number) return varchar2 as
2 v_temp varchar2(100):='';
3 v_out varchar2(500):='';
4 cursor c is select a.subject_name from test_table a where
a.grade_id=p_grade;
5 begin
6 open c ; --打开游标
7 loop
8 fetch c into v_temp;
9 exit when c%notfound;
CSDN Oracle eMag 2004.02 15 of 114
16. http://emag.csdn.net
10 v_out:=v_out||' '||v_temp;
11 end loop;
12 close c; --关闭游标
13 return v_out;
14 exception
15 when others then
16 return 'An error occured';
17 end ;
18 /
Function created.
SQL> create or replace function test_fun(p_grade number) return varchar2 as
2 v_out varchar2(500):='';
3 cursor c is select a.subject_name from test_table a where
a.grade_id=p_grade;
4 begin
5 for v_temp in c loop
6 v_out:=v_out||' '||v_temp.subject_name;
7 end loop; --系统自动关闭游标
8 return v_out;
9 exception
10 when others then
11 return 'An error occured';
12 end ;
13 /
Function created.
2、调用函数得到输入结果:
SQL> select distinct a.grade_id,test_fun(a.grade_id) subject from test_table a;
GRADE_ID SUBJECT
CSDN Oracle eMag 2004.02 16 of 114
19. http://emag.csdn.net
利用游标返回数据集两则 - Delphi & VB
本文作者:chanet
[测试环境]
数据库版本:Oracle 9.2
操作系统:Win2000
一.Delphi 例子:
一、先在 Oracle 建好
CREATE OR REPLACE PACKAGE pkg_test
AS
TYPE myrctype IS REF CURSOR;
PROCEDURE get(i_test INTEGER,p_rc OUT myrctype);
END pkg_test;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE get(i_test INTEGER,p_rc OUT myrctype) IS
BEGIN
IF i_test = 0 THEN
OPEN p_rc FOR SELECT SYSDATE FROM dual;
ELSE
OPEN p_rc FOR SELECT * FROM tab;
END IF;
END get;
END pkg_test;
二、用 Delphi 调用
建一个窗体,拖动控件 AdoConnection1 , ADOStoredProc1 和 Button1.
procedure TForm1.Button1Click(Sender: TObject);
begin
try
with ADOConnection1 do
begin
ConnectionString:=
'Provider=OraOLEDB.Oracle.1;'
CSDN Oracle eMag 2004.02 19 of 114
20. http://emag.csdn.net
+ 'Password=密码;'
+ 'Persist Security Info=True;'
+ 'User ID=用户名;'
+ 'Data Source=数据库名;'
+ 'Extended Properties="PLSQLRSet=1;"';
Open;
end;
except
showMessage('连接不成功');
exit;
end;
try
with ADOStoredProc1 do
begin
Connection := ADOConnection1;
Parameters.Clear;
ProcedureName:= 'pkg_test.get';
Parameters.CreateParameter('p1',ftInteger,pdInput,10,1);
Open;
end;
except
showMessage('无法执行过程.');
end;
end;
二.VB 例子:
PL/SQL 代码:
CREATE OR REPLACE PACKAGE "PKG_TEST" AS
TYPE myrcType IS REF CURSOR;
FUNCTION get(strbarcode VARCHAR) RETURN myrcType;
END pkg_test;
CREATE OR REPLACE PACKAGE BODY "PKG_TEST" AS
FUNCTION get(strbarcode IN VARCHAR) RETURN myrcType IS
rc myrcType;
BEGIN
OPEN rc FOR strbarcode;
RETURN rc;
END get;
END pkg_test;
CSDN Oracle eMag 2004.02 20 of 114
21. http://emag.csdn.net
VB 代码:
Private Sub Command1_Click()
On Error GoTo cursorErr:
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim cmd As New ADODB.Command
cnn.ConnectionString = "Provider=OraOLEDB.Oracle.1;Password=tiger;Persist
Security Info=True;User ID=scott;Data Source=oraAny;Extended
Properties=PLSQLRSet=1"
cnn.Open
With cmd
.ActiveConnection = cnn
.CommandType = adCmdText
.CommandText = "{CALL scott.pkg_test.get(?)}"
.Parameters.Append .CreateParameter("strBarCode", adVarChar,
adParamInput, 100, "SELECT * FROM TAB")
End With
rst.CursorType = adOpenStatic
rst.LockType = adLockReadOnly
Set rst.Source = cmd
rst.Open
MsgBox rst.RecordCount
Set rst = Nothing
Set cmd = Nothing
Exit Sub
cursorErr:
Set cmd = Nothing
Set rst1 = Nothing
MsgBox Err.Description
End Sub
CSDN Oracle eMag 2004.02 21 of 114
24. http://emag.csdn.net
Oracle8 Release 8.0.4.0.0 - Production
PL/SQL Release 8.0.4.0.0 - Production
SVRMGR> connect internal
Connected.
SVRMGR> show parameter job
NAME TYPE VALUE
----------------------------------- ------- ------------------------------
job_queue_interval integer 60
job_queue_keep_connections boolean FALSE
job_queue_processes integer 0
SVRMGR> exit
Server Manager complete.
$
Oracle9.2.0.4 版本
[oracle@ocn1 oracle]$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Mon Dec 6 15:35:10 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining
options
JServer Release 9.2.0.4.0 - Production
SQL> show parameter job
CSDN Oracle eMag 2004.02 24 of 114
25. http://emag.csdn.net
NAME TYPE VALUE
------------------------------ ----------- ----------------------------
job_queue_processes integer 2
SQL>
Linux OS
[oracle@ocn1 oracle]$ ps -ef|grep cjq
oracle 26299 1 0 Oct29 ? 00:00:01 ora_cjq0_ocn1
oracle 23120 18364 0 15:36 pts/2 00:00:00 grep cjq
[oracle@ocn1 oracle]$
创建与修改 job
我有一个存储过程名称为 my_proc,需要每天中午 12:30 定时执行
declare
i number;
begin
dbms_job.submit(i,'my_proc;',trunc(sysdate)+1+12.5/24,'trunc(sysdate)+1+12.5
/24');
commit;
end;
这里想提醒一点如果我们的存储过程只执行一个简单的任务,比如 delete from t ,那
么没必要创建一个存储过程可以直接把 my_proc 替换成 begin delete from t ; end 。
我们可以通过 view user_jobs 查询相关 job 信息
select job,what, INTERVAL from user_jobs where what like 'my_proc%';
JOB WHAT NTERVAL
---------- ------------------------ - ------------------------------
147 my_proc; trunc(sysdate)+1+12.5/24
CSDN Oracle eMag 2004.02 25 of 114
26. http://emag.csdn.net
SQL> select job,NEXT_DATE,INSTANCE from user_jobs where what like
'my_proc%';
JOB NEXT_DATE INSTANCE
---------- ----------------- ----------
147 20041207 12:30:00 1
job 的创建和修改都可以通过 dbms_job 包来完成,这个包的用法很简单,要修改 job 的
属性,一般都是输入 job 编号和要修改的属性的值,主要包含以下过程或者函数
alibaba@OCN> desc dbms_job
FUNCTION BACKGROUND_PROCESS RETURNS BOOLEAN
PROCEDURE BROKEN
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
BROKEN BOOLEAN IN
NEXT_DATE DATE IN DEFAULT
PROCEDURE CHANGE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
WHAT VARCHAR2 IN
NEXT_DATE DATE IN
INTERVAL VARCHAR2 IN
INSTANCE BINARY_INTEGER IN DEFAULT
FORCE BOOLEAN IN DEFAULT
PROCEDURE INSTANCE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
CSDN Oracle eMag 2004.02 26 of 114
27. http://emag.csdn.net
INSTANCE BINARY_INTEGER IN
FORCE BOOLEAN IN DEFAULT
PROCEDURE INTERVAL
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
INTERVAL VARCHAR2 IN
PROCEDURE ISUBMIT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
WHAT VARCHAR2 IN
NEXT_DATE DATE IN
INTERVAL VARCHAR2 IN DEFAULT
NO_PARSE BOOLEAN IN DEFAULT
FUNCTION IS_JOBQ RETURNS BOOLEAN
PROCEDURE NEXT_DATE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
NEXT_DATE DATE IN
PROCEDURE REMOVE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
PROCEDURE RUN
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
FORCE BOOLEAN IN DEFAULT
CSDN Oracle eMag 2004.02 27 of 114
28. http://emag.csdn.net
PROCEDURE SUBMIT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER OUT
WHAT VARCHAR2 IN
NEXT_DATE DATE IN DEFAULT
INTERVAL VARCHAR2 IN DEFAULT
NO_PARSE BOOLEAN IN DEFAULT
INSTANCE BINARY_INTEGER IN DEFAULT
FORCE BOOLEAN IN DEFAULT
PROCEDURE USER_EXPORT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
MYCALL VARCHAR2 IN/OUT
PROCEDURE USER_EXPORT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
MYCALL VARCHAR2 IN/OUT
MYINST VARCHAR2 IN/OUT
PROCEDURE WHAT
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
JOB BINARY_INTEGER IN
WHAT VARCHAR2 IN
比如我们要修改 job 的的定期时间为凌晨 2 点 50 分
begin
dbms_job.interval(147,’trunc(sysdate)+1+170/24/60’)
CSDN Oracle eMag 2004.02 28 of 114
30. http://emag.csdn.net
KADDR RAW(4)
SID NUMBER
TYPE VARCHAR2(2)
ID1 NUMBER
ID2 NUMBER
LMODE NUMBER
REQUEST NUMBER
CTIME NUMBER
BLOCK NUMBER
这里 type 表示 lock 类型,ctime 表示锁存在了多长时间,如果 type=’JQ’并且 ctime 非常
的大(单位是秒) ,而我们的 job 通常存在问题(可能因为网络、os 等等异常导致) ,当然还
可以进一步的明确问题,在这里不做过多的介绍了,通过这里我们可以得到 SID,这表示正
在执行这个任务的 session 的 SID,然后执行
select sid,serial# from v$session where sid = ? ;
select spid from v$process where addr = (select padrr from v$session where sid
= ?);
通过查询获得的 sid 和 serial ,通过拥有 alter system 权限的数据库用户执行
alter system kill session ‘sid,serial#’;
为了保险起见,我们要在 os 上 kill 通过 v$process 获得的 spid 这个进程号,因为在实际
环境中我们发现不做这步很容易出现问题。
kill -9 spid
windows 上可以在命令行下使用 oracle 提供的 orakill 工具杀掉线程
C:Documents and Settingshz>orakill
Usage: orakill sid thread
where sid = the Oracle instance to target
thread = the thread id of the thread to kill
CSDN Oracle eMag 2004.02 30 of 114
31. http://emag.csdn.net
The thread id should be retrieved from the spid column of a query such as:
select spid, osuser, s.program from
v$process p, v$session s where p.addr=s.paddr
CSDN Oracle eMag 2004.02 31 of 114
34. http://emag.csdn.net
由于我们在实验用的存储过程中会用到 dbms_lock 包,所以需要由 sys 用户先授予 kamus
用户使用 dbms_lock 包的权限。
d:Temp>sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.5.0 - Production on 星期三 12 月 1 23:56:32 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
连接到:
Oracle9i Enterprise Edition Release 9.2.0.5.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.5.0 - Production
SQL> grant execute on dbms_lock to kamus;
授权成功。
然后用 kamus 用户登录数据库,创建我们测试使用的存储过程 sp_test_next_date。
create or replace procedure sp_test_next_date as
p_jobno number;
P_nextdate date;
begin
--将调用此存储过程的 job 的 next_date 设置为 30 分钟以后
select job into p_jobno from user_jobs where what = 'sp_test_next_date;';
execute immediate 'begin dbms_job.next_date(' || to_char(p_jobno) ||
',sysdate+1/48);commit;end;';
--修改完毕以后检查 user_jobs 视图,输出 job 目前的 next_date
select next_date
into P_nextdate
from user_jobs
where what = 'sp_test_next_date;';
CSDN Oracle eMag 2004.02 34 of 114
48. http://emag.csdn.net
Oracle 诊断案例-Job 任务停止执行
本文作者: eygle (eygle@itpub.net )
摘要:
本文通过一次 Oracle Job 任务异常案例诊断,分析其原因及解决过程,从内部揭示 Oracle
Job 任务调度及内部计时机制。
问题及环境
接到研发人员报告,数据库定时任务未正常执行,导致某些操作失败。
开始介入处理该事故.
系统环境:
SunOS DB 5.8 Generic_108528-21 sun4u sparc SUNW,Ultra-4
Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
解决过程
首先介入检查数据库任务
$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.3.0 - Production on Wed Nov 17 20:23:53 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
CSDN Oracle eMag 2004.02 48 of 114
49. http://emag.csdn.net
SQL> select job,last_date,last_sec,next_date,next_sec,broken,failures from
dba_jobs;
JOB LAST_DATE LAST_SEC NEXT_DATE NEXT_SEC B FAILURES
INTERVAL
---------- --------- ---------------- --------- ---------------- - ----------
----------------------------
31 16-NOV-04 01:00:02 17-NOV-04 01:00:00 N 0
trunc(sysdate+1)+1/24
27 16-NOV-04 00:00:04 17-NOV-04 00:00:00 N 0
TRUNC(SYSDATE) + 1
35 16-NOV-04 01:00:02 17-NOV-04 01:00:00 N 0
trunc(sysdate+1)+1/24
29 16-NOV-04 00:00:04 17-NOV-04 00:00:00 N 0
TRUNC(SYSDATE) + 1
30 01-NOV-04 06:00:01 01-DEC-04 06:00:00 N 0
trunc(add_months(sysdate,1),'MM')+6/24
65 16-NOV-04 04:00:03 17-NOV-04 04:00:00 N 0
trunc(sysdate+1)+4/24
46 16-NOV-04 02:14:27 17-NOV-04 02:14:27 N 0
sysdate+1
66 16-NOV-04 03:00:02 17-NOV-04 18:14:49 N 0
trunc(sysdate+1)+3/24
8 rows selected.
发现 JOB 任务是都没有正常执行,最早一个应该在 17-NOV-04 01:00:00 执行。但是没有
执行。
建立测试 JOB
create or replace PROCEDURE pining
CSDN Oracle eMag 2004.02 49 of 114
50. http://emag.csdn.net
IS
BEGIN
NULL;
END;
/
variable jobno number;
variable instno number;
begin
select instance_number into :instno from v$instance;
dbms_job.submit(:jobno, 'pining;', trunc(sysdate+1/288,'MI'),
'trunc(SYSDATE+1/288,''MI'')', TRUE, :instno);
end;
/
发现同样的,不执行。
但是通过 dbms_job.run(<job>)执行没有任何问题。
进行恢复尝试
怀疑是 CJQ0 进程失效,首先设置 JOB_QUEUE_PROCESSES 为 0,Oracle 会杀掉 CJQ0
及相应 job 进程
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 0;
等 2~3 分钟,重新设置
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 5;
此时 PMON 会重起 CJQ0 进程
Thu Nov 18 11:59:50 2004
CSDN Oracle eMag 2004.02 50 of 114
51. http://emag.csdn.net
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
Thu Nov 18 12:01:30 2004
ALTER SYSTEM SET job_queue_processes=10 SCOPE=MEMORY;
Thu Nov 18 12:01:30 2004
Restarting dead background process CJQ0
CJQ0 started with pid=8
但是 Job 仍然不执行,而且在再次修改的时候,CJQ0 直接死掉了。
Thu Nov 18 13:52:05 2004
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
Thu Nov 18 14:09:30 2004
ALTER SYSTEM SET job_queue_processes=10 SCOPE=MEMORY;
Thu Nov 18 14:10:27 2004
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
Thu Nov 18 14:10:42 2004
ALTER SYSTEM SET job_queue_processes=10 SCOPE=MEMORY;
Thu Nov 18 14:31:07 2004
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
Thu Nov 18 14:40:14 2004
ALTER SYSTEM SET job_queue_processes=10 SCOPE=MEMORY;
Thu Nov 18 14:40:28 2004
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
Thu Nov 18 14:40:33 2004
ALTER SYSTEM SET job_queue_processes=1 SCOPE=MEMORY;
Thu Nov 18 14:40:40 2004
ALTER SYSTEM SET job_queue_processes=10 SCOPE=MEMORY;
Thu Nov 18 15:00:42 2004
ALTER SYSTEM SET job_queue_processes=0 SCOPE=MEMORY;
CSDN Oracle eMag 2004.02 51 of 114
52. http://emag.csdn.net
Thu Nov 18 15:01:36 2004
ALTER SYSTEM SET job_queue_processes=15 SCOPE=MEMORY;
尝试重起数据库
这个必须在晚上进行
PMON started with pid=2
DBW0 started with pid=3
LGWR started with pid=4
CKPT started with pid=5
SMON started with pid=6
RECO started with pid=7
CJQ0 started with pid=8
QMN0 started with pid=9
....
CJQ0 正常启动,但是 Job 仍然不执行。
没办法了...
继续研究...居然发现 Oralce 有这样一个 bug
1. Clear description of the problem encountered:
slgcsf() / slgcs() on Solaris will stop incrementing after
497 days 2 hrs 28 mins (approx) machine uptime.
CSDN Oracle eMag 2004.02 52 of 114
53. http://emag.csdn.net
2. Pertinent configuration information
No special configuration other than long machine uptime. .
3. Indication of the frequency and predictability of the problem
100% but only after 497 days.
4. Sequence of events leading to the problem
If the gethrtime() OS call returns a value > 42949672950000000
nanoseconds then slgcs() stays at 0xffffffff. This can
cause some problems in parts of the code which rely on
slgcs() to keep moving.
eg: In kkjssrh() does "now = slgcs(&se)" and compares that
to a previous timestamp. After 497 days uptime slgcs()
keeps returning 0xffffffff so "now - kkjlsrt" will
always return 0. .
5. Technical impact on the customer. Include persistent after effects.
In this case DBMS JOBS stopped running after 497 days uptime.
Other symptoms could occur in various places in the code.
好么,原来是计时器溢出了,一检查我的主机:
bash-2.03$ uptime
10:00pm up 500 day(s), 14:57, 1 user, load average: 1.31, 1.09, 1.08
bash-2.03$ date
Fri Nov 19 22:00:14 CST 2004
刚好到事发时是 497 天多一点.ft.
CSDN Oracle eMag 2004.02 53 of 114
54. http://emag.csdn.net
安排重起主机系统..
这个问题够郁闷的,NND,谁曾想 Oracle 这都成...
Oracle 最后声称:
fix made it into 9.2.0.6 patchset
在 Solaris 上的 9206 尚未发布...晕.
好了,就当是个经历吧,如果有问题非常不可思议的话,那么大胆怀疑 Oracle 吧,是
Bug,可能就是 Bug。
重起以后问题解决,状态如下:
$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.3.0 - Production on Fri Nov 26 09:21:21 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
SQL> select job,last_date,last_sec,next_date,next_sec from user_jobs;
CSDN Oracle eMag 2004.02 54 of 114
57. http://emag.csdn.net
printf("num + 1 = 0x%xn", num + 1);
return 0;
}
[oracle@jumper oracle]$ gcc -o unsign.sh unsign.c
[oracle@jumper oracle]$ ./unsign.sh
num is 32 bits long
num = 0xffffffff
num + 1 = 0x0
[oracle@jumper oracle]$
Q:内部时钟之一应该就是这个吧: v$timer 精确到 1/100 秒的数据
A:没错!
注意前面说的:
4. Sequence of events leading to the problem
If the gethrtime() OS call returns a value > 42949672950000000
nanoseconds then slgcs() stays at 0xffffffff. This can
cause some problems in parts of the code which rely on
slgcs() to keep moving.
也就是说如果 gethrtime() 操作系统调用返回值大于 42949672950000000(单位 10 亿分
之一秒)
也就是说 Oracle 将得到一个 cs 值为 4294967295 的时间值
而 4294967295 值就是 0xffffffff
所以当时 v$timer 的计时也就是:
CSDN Oracle eMag 2004.02 57 of 114
73. http://emag.csdn.net
如何使用触发器实现数据库级守护
本文作者: eygle (eygle.com@gmail.com )
摘要:
对于重要对象,实施 DDL 拒绝,防止 create,drop,truncate,alter 等重要操作.
不管是有意还是无意的,你可能会遇到数据库中重要的数据表等对象被 drop 掉的情况,这
可能会给我们带来巨大的损失.
通过触发器,我们可以实现对于表等对象的数据库级守护,禁止用户 drop 操作.
以下是一个简单的范例,供参考:
REM this script can be used to monitor a object
REM deny any drop operation on it.
CREATE OR REPLACE TRIGGER trg_dropdeny
BEFORE DROP ON DATABASE
BEGIN
IF LOWER (ora_dict_obj_name ()) = 'test'
THEN
raise_application_error (num => -20000,
msg => '你疯了,想删除表 '
|| ora_dict_obj_name ()
|| ' ?!!!!!'
|| '你完了,警察已在途中.....'
);
END IF;
END;
/
测试效果:
CSDN Oracle eMag 2004.02 73 of 114
74. http://emag.csdn.net
SQL> connect scott/tiger
Connected.
SQL> create table test as select * from dba_users;
Table created.
SQL> connect / as sysdba
Connected.
SQL> create or replace trigger trg_dropdeny
2 before drop on database
3 begin
4 if lower(ora_dict_obj_name()) = 'test'
5 then
6 raise_application_error(
7 num => -20000,
8 msg => '你疯了,想删除表 ' || ora_dict_obj_name() || ' ?!!!!!' ||'你完
了,警察已在途中.....');
9 end if;
10 end;
11 /
Trigger created.
SQL> connect scott/tiger
Connected.
SQL> drop table test;
drop table test
*
ERROR at line 1:
CSDN Oracle eMag 2004.02 74 of 114
75. http://emag.csdn.net
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: 你疯了,想删除表 TEST ?!!!!!你完了,警察已在途中.....
ORA-06512: at line 4
Oracle 从 Oracle8i 开始,允许实施 DDL 事件 trigger,可是实现对于 DDL 的监视及控制,
以下是一个进一步的例子:
create or replace trigger ddl_deny
before create or alter or drop or truncate on database
declare
l_errmsg varchar2(100):= 'You have no permission to this operation';
begin
if ora_sysevent = 'CREATE' then
raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
elsif ora_sysevent = 'ALTER' then
raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
elsif ora_sysevent = 'DROP' then
raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
elsif ora_sysevent = 'TRUNCATE' then
raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
end if;
exception
when no_data_found then
null;
end;
/
CSDN Oracle eMag 2004.02 75 of 114
76. http://emag.csdn.net
我们看一下效果:
[oracle@jumper tools]$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Sun Oct 31 11:38:25 2004
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning option
JServer Release 9.2.0.4.0 - Production
SQL> set echo on
SQL> @ddlt
SQL> create or replace trigger ddl_deny
2 before create or alter or drop or truncate on database
3 declare
4 l_errmsg varchar2(100):= 'You have no permission to this operation';
5 begin
6 if ora_sysevent = 'CREATE' then
7 raise_application_error(-20001, ora_dict_obj_owner || '.' || ora_dict_obj_name
|| ' ' || l_errmsg);
8 elsif ora_sysevent = 'ALTER' then
9 raise_application_error(-20001, ora_dict_obj_owner || '.' || ora_dict_obj_name
|| ' ' || l_errmsg);
10 elsif ora_sysevent = 'DROP' then
11 raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
12 elsif ora_sysevent = 'TRUNCATE' then
CSDN Oracle eMag 2004.02 76 of 114
77. http://emag.csdn.net
13 raise_application_error(-20001, ora_dict_obj_owner || '.' ||
ora_dict_obj_name || ' ' || l_errmsg);
14 end if;
15
16 exception
17 when no_data_found then
18 null;
19 end;
20 /
Trigger created.
SQL>
SQL>
SQL> connect scott/tiger
Connected.
SQL> create table t as select * from test;
create table t as select * from test
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: SCOTT.T You have no permission to this operation
ORA-06512: at line 5
SQL> alter table test add (id number);
alter table test add (id number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
CSDN Oracle eMag 2004.02 77 of 114
78. http://emag.csdn.net
ORA-20001: SCOTT.TEST You have no permission to this operation
ORA-06512: at line 7
SQL> drop table test;
drop table test
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: SCOTT.TEST You have no permission to this operation
ORA-06512: at line 9
SQL> truncate table test;
truncate table test
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: SCOTT.TEST You have no permission to this operation
ORA-06512: at line 11
我们可以看到,ddl 语句都被禁止了,如果你不是禁止,可以选择把执行这些操作的用户及
时间记录到另外的临时表中.以备查询.
CSDN Oracle eMag 2004.02 78 of 114
80. http://emag.csdn.net
DBMS_ROWID 包的使用
本文作者: coolyl (allan@itpub.net )
摘要:
DBMS_ROWID 是一个比较有用的系统自带的 package,主要可以用来处理坏块的问题,
于是仔细的研究了一下,这个包可以用来了解 file、block、object id 和 rowid 之间的关系,
在 Oracle8 中被引用进来, Oracle7 不支持这个包。这个包的定义可以在 dbmsutil.sql 中找到,
在 catproc.sql 中被调用,并被给予 public 执行权限.
首先来了解一下这个包中使用的常量:
ROWID 类型:
rowid_type_restricted RESTRICTED - Restricted ROWID
rowid_type_extended EXTENDED - Extended ROWID
ROWID 验证结果:
rowid_is_valid VALID - Valid ROWID
rowid_is_invalid INVALID - Invalid ROWID
目标类型:
rowid_object_undefined UNDEFINED - Object Number not defined
(for restricted ROWIDs)
ROWID 转换类型:
rowid_convert_internal INTERNAL - convert to/from column of ROWID type
rowid_convert_external EXTERNAL - convert to/from string format
意外错误:
ROWID_INVALID invalid rowid format
ROWID_BAD_BLOCK block is beyond end of file
在 DBMS_ROWID 这个包里面可以使用下面的功能:
function ROWID_CREATE(rowid_type IN number,
object_number IN number,
relative_fno IN number,
block_number IN number,
row_number IN number)
CSDN Oracle eMag 2004.02 80 of 114
81. http://emag.csdn.net
return ROWID;
-- rowid_type - 类型(restricted=0/extended=1)
-- object_number - 对象号
-- relative_fno - relative file number
-- block_number - 文件包含的 block 号
-- row_number - block 中的行的行号
下面具体的讨论一下 DBMS_ROWID 包的用法
1.1 DBMS_ROWID.ROWID_BLOCK_NUMBER
返回一个 rowid 的 block 号
定义如下:
function dbms_rowid.rowid_block_number
(row_id in rowid)
return number
例子:
SQL> select dbms_rowid.rowid_block_number(rowid) "block" from test;
block
----------
23722
1.2 DBMS_ROWID.ROWID_CREATE
创建并返回一个基于单独行的 rowid,创建的 rowid 类型是 RESTRICTED 或者是
EXTENDED,这种功能一般都是用于测试目的,因为只有 oracle 才能创建一个合法的 rowid
指向数据。
定义如下:
function dbms_rowid.rowid_create
(rowid_type in number
,object_number in number
,relative_fno in number
CSDN Oracle eMag 2004.02 81 of 114
82. http://emag.csdn.net
,block_number in number
,row_number in number)
return rowid
例子:
创建一个 restricted rowid:
SQL> select dbms_rowid.rowid_create(0, 6877,1,23722,0) from dual;
DBMS_ROWID.ROWID_C
------------------
00005CAA.0000.0001
创建一个 extended rowid:
SQL> select dbms_rowid.rowid_create(1, 6877,1,23722,0) from dual;
DBMS_ROWID.ROWID_C
------------------
AAABrdAABAAAFyqAAAa
1.3 DBMS_ROWID.ROWID_INFO
返回一个单独组件的一个指定的 rowid,它只能用于 PL/SQL,而不能用于 sql 语句中。
定义如下:
procedure dbms_rowid.rowid_info
(rowid_in in rowid
,rowid_type out number
,object_number out number
,relative_fno out number
,block_number out number
,row_number out number)
例子:
SQL> set serverout on
SQL> set echo on
SQL> declare
CSDN Oracle eMag 2004.02 82 of 114
88. http://emag.csdn.net
SQL> select dbms_rowid.rowid_type(rowid) "type" from test;
type
----------
1
Oracle7 的 rowid 是 restricted 类型
SQL> select
dbms_rowid.rowid_type(chartorowid('00005CAA.0000.0001')) "type"
from dual;
type
----------
0
1.11 DBMS_ROWID.ROWID_VERIFY
验证一个 restricted 的 rowid 是否能够转换成 extended 的 rowid,它可以用来发现存在问
题的 rowid。
定义如下:
function rowid_verify(rowid_in IN rowid,
schema_name IN varchar2,
object_name IN varchar2,
conversion_type IN integer)
return number;
1.11 利用 DBMS_ROWID 包恢复的一个例子
介绍了这个包的用法后,其实对于我们最主要的还是利用
DBMS_ROWID.ROWID_CREATE 来解决坏块的一些问题,下面举一个具体如何使用这个包
来解决坏块的例子。
SQL> create tablespace test datafile
'd:oracleoradataorcltest.dbf' size 5M;
表空间已创建。
CSDN Oracle eMag 2004.02 88 of 114
89. http://emag.csdn.net
SQL> create user coolyl identified by coolyl
2 default tablespace test
3 temporary tablespace temp;
用户已创建。
SQL> grant connect,resource,dba to coolyl;
授权成功。
SQL> connect coolyl/coolyl
已连接。
SQL> create table test as select * from dba_objects;
表已创建。
SQL> insert into test select * from test;
已创建 6238 行。
SQL> insert into test select * from test;
已创建 12476 行
SQL> r
1* insert into test select * from test
insert into test select * from test*
ERROR 位于第 1 行:
ORA-01653: 表 COOLYL.TEST 无法通过 128(在表空间 TEST 中)扩展
SQL> select count(*) from test;
COUNT(*)
----------
24952
SQL> commit;
提交完成。
SQL> create index indx_test on test(object_id);
索引已创建。
SQL> select status from dba_indexes where index_name='INDX_TEST';
STATUS
--------
CSDN Oracle eMag 2004.02 89 of 114
91. http://emag.csdn.net
Bad check value found during dbv:
Data in bad block -
type: 6 format: 2 rdba: 0x00c00017
last change scn: 0x0000.0005cc2a seq: 0x2 flg: 0x04
consistency value in tail: 0xcc2a0602
check value in block header: 0x9206, computed block checksum: 0x314b
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
DBVERIFY - 验证完成
检查的页总数 :640
处理的页总数(数据):510
失败的页总数(数据):0
处理的页总数(索引):54
失败的页总数(索引):0
处理的页总数(其它):10
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数 :65
标记为损坏的总页数:1
汇入的页总数 :0
由 DBV 工具检测出来的结果也可以看到 TEST.DBF 文件存在一个坏块。
SQL> SELECT tablespace_name, relative_fno,segment_type, owner,
segment_name, partition_name FROM dba
_extents WHERE file_id = 3 AND 23 between block_id and block_id +
blocks -1;
TABLESPACE_NAME RELATIVE_FNO SEGMENT_TYPE
------------------------------ ------------ ------------------
OWNER
------------------------------
SEGMENT_NAME
CSDN Oracle eMag 2004.02 91 of 114
92. http://emag.csdn.net
---------------
PARTITION_NAME
------------------------------
TEST 3 TABLE
COOLYL
TEST
SQL> SELECT data_object_id FROM dba_objects WHERE object_name = 'TEST'
AND owner = 'COOLYL';
DATA_OBJECT_ID
--------------
6907
SQL> SELECT dbms_rowid.rowid_create(1,6907,3,23,0) LOW_RID from
DUAL;
LOW_RID
------------------
AAABr7AADAAAAAXAAA
SQL> SELECT dbms_rowid.rowid_create(1,6907,3,24,0) HI_RID from
DUAL;
HI_RID
------------------
AAABr7AADAAAAAYAAA
SQL> CREATE TABLE test_bak AS SELECT /*+ ROWID(A) */ * FROM coolyl.test
A WHERE rowid < 'AAABr7AADAA
AAAXAAA';
表已创建。
SQL>
SQL> INSERT INTO test_bak SELECT /*+ ROWID(A) */ * FROM coolyl.test
A WHERE rowid >= 'AAABr7AADAAAAA
YAAA';
已创建 23812 行。
CSDN Oracle eMag 2004.02 92 of 114
93. http://emag.csdn.net
SQL> commit;
提交完成。
SQL> select count(*) from test_bak;
COUNT(*)
----------
24873
可以看到丢失了 24952-24873=79 条记录。
SQL> connect coolyl/coolyl
已连接。
SQL> select status from dba_indexes where index_name='INDX_TEST';
STATUS
--------
VALID
SQL> drop table test;
表已丢弃。
SQL> create table test as select * from sys.test_bak;
表已创建。
SQL> select status from dba_indexes where index_name='INDX_TEST';
未选定行。
SQL> create index indx_test on test(object_id);
索引已创建。
SQL> select status from dba_indexes where index_name='INDX_TEST';
STATUS
--------
VALID
SQL> select count(*) from test;
COUNT(*)
----------
24873
D:oracleoradataorcl>dbv file=test.dbf blocksize=8192
CSDN Oracle eMag 2004.02 93 of 114
98. http://emag.csdn.net
ORACLE instance started.
Total System Global Area 135337420 bytes
Fixed Size 452044 bytes
Variable Size 109051904 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
Database mounted.
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
System altered.
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
System altered.
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
System altered.
SQL> ALTER DATABASE OPEN;
Database altered.
SQL> alter session set events '10046 trace name context forever,level 12';
Session altered.
SQL> alter database character set INTERNAL_USE ZHS16CGB231280
Database altered.
SQL>
CSDN Oracle eMag 2004.02 98 of 114
99. http://emag.csdn.net
这是 alert.log 文件中的记录信息:
Tue Oct 19 16:26:30 2004
Database Characterset is ZHS16GBK
replication_dependency_tracking turned off (no async multimaster replication
found)
Completed: ALTER DATABASE OPEN
Tue Oct 19 16:27:07 2004
alter database character set INTERNAL_USE ZHS16CGB231280
Updating character set in controlfile to ZHS16CGB231280
Tue Oct 19 16:27:15 2004
Thread 1 advanced to log sequence 118
Current log# 2 seq# 118 mem# 0: /opt/oracle/oradata/primary/redo02.log
Tue Oct 19 16:27:15 2004
ARC0: Evaluating archive log 3 thread 1 sequence 117
ARC0: Beginning to archive log 3 thread 1 sequence 117
Creating archive destination LOG_ARCHIVE_DEST_1:
'/opt/oracle/oradata/primary/archive/1_117.dbf'
ARC0: Completed archiving log 3 thread 1 sequence 117
Tue Oct 19 16:27:20 2004
Completed: alter database character set INTERNAL_USE ZHS16CGB231280
Shutting down instance: further logons disabled
Shutting down instance (immediate)
License high water mark = 1
Tue Oct 19 16:29:06 2004
ALTER DATABASE CLOSE NORMAL
...
格式化 10046 跟踪文件,得到以下信息(摘要):
alter session set events '10046 trace name context forever,level 12'
alter database character set INTERNAL_USE ZHS16CGB231280
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ----------
CSDN Oracle eMag 2004.02 99 of 114
100. http://emag.csdn.net
Parse 1 0.00 0.00 0 0 0 0
Execute 1 4.88 6.04 910 16825 18099 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ----------
total 2 4.88 6.04 910 16825 18099 0
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: SYS
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ----------
control file sequential read 4 0.00 0.00
control file parallel write 2 0.05 0.08
log file sync 2 0.08 0.08
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 18.06 18.06
**************************************************************************
....
update col$ set charsetid = :1
where
charsetform = :2
....
update argument$ set charsetid = :1
where
charsetform = :2
....
CSDN Oracle eMag 2004.02 100 of 114
101. http://emag.csdn.net
update collection$ set charsetid = :1
where
charsetform = :2
....
update attribute$ set charsetid = :1
where
charsetform = :2
....
update parameter$ set charsetid = :1
where
charsetform = :2
....
update result$ set charsetid = :1
where
charsetform = :2
....
update partcol$ set spare1 = :1
where
charsetform = :2
....
update subpartcol$ set spare1 = :1
where
CSDN Oracle eMag 2004.02 101 of 114
102. http://emag.csdn.net
charsetform = :2
....
update props$ set value$ = :1
where
name = :2
....
update "SYS"."KOTAD$" set SYS_NC_ROWINFO$ = :1
where
SYS_NC_OID$ = :2
....
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,
cache=:7,highwater=:8,audit$=:9,flags=:10
where
obj#=:1
....
update kopm$ set metadata = :1, length
= :2
where
name='DB_FDO'
....
ALTER DATABASE CLOSE NORMAL
CSDN Oracle eMag 2004.02 102 of 114
114. http://emag.csdn.net
Guerrilla Oracle: The Succinct Windows Perspective 原版进口
链接地址:http://www.dearbook.com.cn/book/viewbook.aspx?pno=TS0027014
作 者:Richard Staron
出 版 社:Pearson Education
ISBN 书号:0201750775
Are you frustrated by your attempts to learn Oracle or improve your
Oracle skills because of the sheer amount of technical documentation you
have to wade through? This concise tutorial walks you step-by-step
through the process, showing you exactly what you need to know to
install, create, and support a successful Oracle 8i or 9i environment with
Web capabilities.
It presents clear explanations of database, SQL, and Oracle fundamentals.
Using a real-world, large-scale example to demonstrate essential tasks,
the book follows the Oracle DBMS life cycle from business idea to
functioning database.
CSDN Oracle eMag 2004.02 114 of 114