• 金仓数据库 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 目标中。

    注意

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

  • 相关阅读:
    linux,从零安装mysql 8.0.30 ,并且更新至mysql 8.0.36
    外置告警蜂鸣器使用小坑
    博途PLC S7-1200/1500 ModbusTcp通信SCL代码篇(轮询)
    软件工程的介绍
    海外服务器相较于国内服务器有何特点?亚马逊海外服务器为何零跑全球
    springMVC02之CRUD和文件上传下载
    MySQL锁
    后端程序员入门react笔记(七)- React路由
    Docker实践:使用Docker搭建个人开发环境
    JavaScript中的设计模式
  • 原文地址:https://blog.csdn.net/arthemis_14/article/details/126488035