金仓数据库 KingbaseES PL/SQL 过程语言参考手册(17. B PL/SQL名称解析)

17. B PL/SQL名称解析

本附录解释 PL/SQL名称解析;也就是说,PL/SQL 编译器如何解析对标识符的模糊引用。

如果您在其编译单元中更改标识符(即如果您添加、重命名或删除标识符),则明确的标识符引用可能会变得不明确。

注意

存储的 PL/SQL 单元的AUTHID属性会影响该单元在运行时发出的 SQL 语句的名称解析。有关详细信息,请参阅“调用者的权限和定义者的权限(AUTHID 属性)”。

17.1. 限定名称和点符号

当一个命名项属于另一个命名项时,您可以(有时必须)使用点表示法用“父”项的名称来限定“子”项的名称。例如:

引用

名称限定

语法

记录的字段

记录名称

record_name.field_name

集合方法

集合名称

collection_name.method

伪列CURRVAL

序列名称

sequence_name.CURRVAL

伪列NEXTVAL

序列名称

sequence_name.NEXTVAL

如果在命名的 PL/SQL 单元中声明了一个标识符,您可以使用该单元的名称(块、子程序或包)来限定其简单名称(其声明中的名称),使用以下语法:

unit_name.simple_identifier_name

如果标识符不可见,则必须限定其名称(请参阅“标识符的范围和可见性”)。

如果标识符属于另一个模式,则必须使用模式名称限定其名称,使用以下语法:

schema_name.package_name

一个简单的名称可以用多个名称来限定,如:ref:`示例 B-1`所示。

可能有歧义的限定名称的一些示例是: - 函数返回值的字段或属性,例如:

func_name().field_name
func_name().attribute_name
  • 另一个架构拥有的架构对象,例如:

    schema_name.table_name
    schema_name.procedure_name()
    schema_name.type_name.member_name()
    

另一个用户拥有的包对象,例如:

schema_name.package_name.procedure_name()
schema_name.package_name.record_name.field_name

包含 ADT 的记录,例如:

record_name.field_name.attribute_name record_name.field_name.member_name ()

示例 B-1 限定名称

    \set SQLTERM /
CREATE OR REPLACE PACKAGE pkg1 AUTHID DEFINER AS
  num NUMBER;
  TYPE rt IS RECORD (a NUMBER);
  var1 rt;
  TYPE ct IS TABLE OF rt INDEX BY PLS_INTEGER;
  var2 ct;
  FUNCTION f1 (a1 NUMBER) RETURN rt;
  FUNCTION f2 (a2 NUMBER) RETURN ct;
END pkg1;
/

CREATE OR REPLACE PACKAGE BODY pkg1 AS
  FUNCTION f1 (a1 NUMBER) RETURN rt IS
    n NUMBER;
  BEGIN
     n := num;             -- 不合格的变量名
     n := pkg1.num;        -- 包名限定的变量名
     n := pkg1.f1.a1;    -- 函数名限定的参数名,由包名限定
     n := var1.a;          -- 变量名后跟字段名
     n := pkg1.var1.a;     -- 包名限定的变量名后跟组件名称
     var1.a := a1;
     RETURN var1;
   END f1;

   FUNCTION f2 (a2 NUMBER) RETURN ct IS
     v_rt rt;
     v_ct ct;
   BEGIN
     v_rt.a := a2;
     v_ct(1) := v_rt;
     RETURN v_ct;
   END f2;
END pkg1;
/

17.2. 列名优先级

如果 SQL 语句引用的名称既属于列又属于局部变量或形参,则列名优先。

警告

当变量或参数名称被解释为列名称时,可能会无意中删除、更改或插入数据。

在:ref:`示例 B-2`中,名称 name 既属于局部变量又属于列(名称不区分大小写)。因此,在 WHERE 子句中,对 name 的两个引用都解析为列,并且所有行都被删除。

:ref:`示例 B-3`通过给变量一个不同的名称 来解决:ref:`示例 B-2`中的问题。

在:ref:`示例 B-4`中,函数 dept_name 有一个形式参数和一个局部变量,其名称是表 DEPARTMENTS 的列的名称。参数和变量名用函数名限定,以区别于列名。

示例 B-2 解释为列名的变量名导致意外结果

DROP TABLE IF EXISTS student;
    CREATE TABLE student (id int PRIMARY KEY, name text, score number);
    insert into student values (1, 'xx', 99);
CREATE TABLE stu_name AS
  SELECT name FROM student;
\set SQLTERM /
DECLARE
  name  TEXT := 'xa';
BEGIN
  DELETE FROM student WHERE name = name;
  RAISE NOTICE 'Deleted % rows', SQL%ROWCOUNT;
END;
/

结果:

NOTICE:  Deleted 1 rows

示例 B-3使用不同的变量名称 修复示例 B-2

    insert into student values (1, 'xx', 99);
    \set SQLTERM /
DECLARE
  v_name  TEXT := 'xa';
BEGIN
  DELETE FROM student WHERE name = v_name;
  RAISE NOTICE 'Deleted % rows', SQL%ROWCOUNT;
END;
/

结果:

NOTICE:  Deleted 0 rows

示例 B-4 名称解析的子程序名称

    \set SQLTERM /
DECLARE
  FUNCTION stu_name (id IN NUMBER) RETURN student.name%TYPE AS
      DECLARE
    v_name  student.name%TYPE;
  BEGIN
    SELECT name INTO v_name FROM student
            WHERE id = stu_name.id;
    RETURN v_name;
  END stu_name;
BEGIN
  FOR item IN (
    SELECT id
    FROM student) LOOP

      RAISE NOTICE 'Student: %', stu_name(item.id);
  END LOOP;
END;
/

结果:

NOTICE:  Student: xx

17.3. PL/SQL 和 SQL 名称解析规则的区别

PL/SQL 和 SQL 名称解析规则非常相似。然而: - PL/SQL 规则比 SQL 规则更宽松。

因为大多数 SQL 规则是上下文相关的,它们比 PL/SQL 规则识别更多的情况是合法的。

  • PL/SQL 和 SQL 以不同的方式解析限定名。

    例如,在解析表名时student:

    • PL/SQL 首先搜索 ms 当前模式中命名的包、类型、表和视图,然后搜索公共同义词,最后在 ms 模式中搜索名为 JOBS 的对象。

    • SQL 首先在 ms 模式中搜索名为 JOBS 的对象,然后在当前模式中搜索名为 ms 的包、类型、表和视图。

为避免由于 PL/SQL 和 SQL 名称解析规则之间的少量差异而导致的问题,请遵循“避免 SELECT 和 DML 语句中的内部捕获”中的建议。

注意

当 PL/SQL 编译器处理静态 SQL 语句时,它将该语句发送到 SQL 子系统,该子系统使用 SQL 规则来解析语句中的名称。详见“静态SQL语句中名称的解析”。

17.4. 静态 SQL 语句中的名称解析

静态 SQL 在PL/SQL 静态 SQL中进行了描述。

当 PL/SQL 编译器找到静态 SQL 语句时:

  1. 如果语句是SELECT语句,则 PL/SQL 编译器删除INTO子句。

  2. PL/SQL 编译器将语句发送到 SQL 子系统。

  3. SQL 子系统检查语句的语法。

    如果语法不正确,PL/SQL 单元的编译将失败。如果语法正确,SQL 子系统将确定表的名称并尝试解析 SQL 语句范围内的其他名称。

  4. 如果 SQL 子系统无法解析 SQL 语句范围内的名称,则它将名称发送回 PL/SQL 编译器。该名称称为转义标识符。

  5. PL/SQL 编译器尝试解析转义的标识符。

    首先,编译器尝试解析 PL/SQL 单元范围内的标识符。如果失败,编译器会尝试解析模式范围内的标识符。如果失败,PL/SQL 单元的编译就会失败。

  6. 如果 PL/SQL 单元的编译成功,则 PL/SQL 编译器生成与静态 SQL 语句等效的常规 SQL 语句的文本,并将该文本与生成的计算机代码一起存储。

  7. 在运行时,PL/SQL 运行时系统调用解析、绑定和运行常规 SQL 语句的例程。

    绑定变量是转义的标识符(参见步骤 4)。

  8. 如果语句是 SELECT 语句,则 PL/SQL 运行时系统将结果存储在 PL/SQL 编译器在步骤 1 中删除的 INTO 子句中指定的 PL/SQL 目标中。

注意

绑定变量可以按任何顺序计算。如果一个程序确定了评估的顺序,那么在程序这样做的时候,它的行为是未定义的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值