# 43.6.控制结构

43.6.1. 从函数返回

43.6.2. 从手术室回来

43.6.3. 调用程序

43.6.4. 条件句

43.6.5. 简单循环

43.6.6. 循环查询结果

43.6.7. 在数组中循环

43.6.8. 陷阱错误

43.6.9. 获取执行位置信息

控制结构可能是PL/pgSQL中最有用(也是最重要)的部分。通过PL/pgSQL的控制结构,您可以以非常灵活和强大的方式操作PostgreSQL数据。

# 43.6.1.从函数返回

有两个命令可用于从函数返回数据:回来下一个回来.

# 43.6.1.1.回来

RETURN expression;

回来使用表达式终止函数并返回*表示*给打电话的人。此表单用于不返回集合的PL/pgSQL函数。

在返回标量类型的函数中,表达式的结果将自动转换为函数的返回类型,如赋值所述。但要返回复合(行)值,必须编写一个表达式,精确地传递请求的列集。这可能需要使用显式转换。

如果用输出参数声明函数,只需编写回来没有表情。将返回输出参数变量的当前值。

如果您声明了要返回的函数无效的A.回来语句可以用来提前退出函数;但不要在下面写一个表达式回来.

函数的返回值不能未定义。如果控件到达函数顶层块的末尾,而没有点击回来语句时,将发生运行时错误。此限制不适用于具有输出参数和返回函数的函数无效的然而在这些情况下回来如果顶层块完成,语句将自动执行。

例如:

-- functions returning a scalar type
RETURN 1 + 2;
RETURN scalar_var;

-- functions returning a composite type
RETURN composite_type_var;
RETURN (1, 2, 'three'::text);  -- must cast columns to correct types

# 43.6.1.2. 下一个回来返回查询

RETURN NEXT expression;
RETURN QUERY query;
RETURN QUERY EXECUTE command-string [ USING expression [, ... ] ];

当PL/pgSQL函数被声明为返回一套*某种类型的*,遵循的程序略有不同。在这种情况下,要返回的单个项目由一系列下一个回来返回查询命令,然后是最终的回来不带参数的命令用于指示函数已完成执行。下一个回来可以与标量和复合数据类型一起使用;对于复合结果类型,将返回整个结果“表”。返回查询将执行查询的结果附加到函数的结果集中。下一个回来返回查询可以在一组返回函数中自由混合,在这种情况下,它们的结果将被串联。

下一个回来返回查询实际上并不从函数返回——它们只是将零行或多行附加到函数的结果集中。然后继续执行PL/pgSQL函数中的下一条语句。连续的下一个回来返回查询执行命令,建立结果集。决赛回来,这将导致控件退出函数(或者您可以让控件到达函数的末尾)。

返回查询有变种返回查询执行,它指定要动态执行的查询。参数表达式可以通过使用,方法与处决命令

如果用输出参数声明函数,只需编写下一个回来没有表情。每次执行时,输出参数变量的当前值将被保存,以便最终作为结果行返回。请注意,必须将函数声明为返回一套记录当有多个输出参数时,或一套*某种类型的*当只有一个类型为的输出参数时*某种类型的*,以创建带有输出参数的设置返回函数。

下面是一个使用下一个回来:

CREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT);
INSERT INTO foo VALUES (1, 2, 'three');
INSERT INTO foo VALUES (4, 5, 'six');

CREATE OR REPLACE FUNCTION get_all_foo() RETURNS SETOF foo AS
$BODY$
DECLARE
    r foo%rowtype;
BEGIN
    FOR r IN
        SELECT * FROM foo WHERE fooid > 0
    LOOP
        -- can do some processing here
        RETURN NEXT r; -- return current row of SELECT
    END LOOP;
    RETURN;
END;
$BODY$
LANGUAGE plpgsql;

SELECT * FROM get_all_foo();

下面是一个使用返回查询:

CREATE FUNCTION get_available_flightid(date) RETURNS SETOF integer AS
$BODY$
BEGIN
    RETURN QUERY SELECT flightid
                   FROM flight
                  WHERE flightdate >= $1
                    AND flightdate < ($1 + 1);

    -- Since execution is not finished, we can check whether rows were returned
    -- and raise exception if not.
    IF NOT FOUND THEN
        RAISE EXCEPTION 'No flight at %.', $1;
    END IF;

    RETURN;
 END;
$BODY$
LANGUAGE plpgsql;

-- Returns available flights or raises exception if there are no
-- available flights.
SELECT * FROM get_available_flightid(CURRENT_DATE);

# 笔记

当前实施的下一个回来返回查询如上所述,在从函数返回之前存储整个结果集。这意味着,如果PL/pgSQL函数生成非常大的结果集,性能可能会很差:数据将写入磁盘以避免内存耗尽,但函数本身在生成整个结果集之前不会返回。PL/pgSQL的未来版本可能允许用户定义不受此限制的集合返回函数。目前,数据开始写入磁盘的时间点由工作_记忆配置变量。具有足够内存以存储较大结果集的管理员应考虑增加此参数。

# 43.6.2.从手术室回来

过程没有返回值。因此,一个过程可以在没有回来陈述如果你想使用回来语句提前退出代码,只需编写回来没有表情。

如果过程有输出参数,则输出参数变量的最终值将返回给调用者。

# 43.6.3.调用程序

PL/pgSQL函数、过程或块可以使用呼叫.输出参数的处理方式与呼叫在纯SQL中工作。每个出来伊努特程序的参数必须与呼叫语句,并且无论过程返回什么,在返回后都会被赋回该变量。例如:

CREATE PROCEDURE triple(INOUT x int)
LANGUAGE plpgsql
AS $$
BEGIN
    x := x * 3;
END;
$$;

DO $$
DECLARE myvar int := 5;
BEGIN
  CALL triple(myvar);
  RAISE NOTICE 'myvar = %', myvar;  -- prints 15
END;
$$;

与输出参数相对应的变量可以是简单变量,也可以是复合类型变量的字段。目前,它不能是数组的元素。

# 43.6.4.条件句

如果案例语句允许您根据特定条件执行替代命令。PL/pgSQL有三种形式的如果:

  • 如果然后如果结束

  • 如果然后其他的如果结束

  • 如果然后埃尔西夫。。。然后其他的如果结束

    以及两种形式的案例:

  • 案例什么时候然后其他的结案

  • 如果。。。然后其他的结案

# 43.6.4.1. 如果-那么

IF boolean-expression THEN
    statements
END IF;

如果-那么语句是语言的最简单形式如果.双方的声明然后如果结束如果条件为真,将执行。否则,它们将被跳过。

例子:

IF v_user_id <> 0 THEN
    UPDATE users SET email = v_email WHERE user_id = v_user_id;
END IF;

# 43.6.4.2. 如果-然后-否则

IF boolean-expression THEN
    statements
ELSE
    statements
END IF;

如果-然后-否则声明增加了如果-那么通过让您指定一组在条件不为真时应执行的替代语句。(注意,这包括条件计算为NULL的情况。)

例如:

IF parentid IS NULL OR parentid = ''
THEN
    RETURN fullname;
ELSE
    RETURN hp_true_filename(parentid) || '/' || fullname;
END IF;
IF v_count > 0 THEN
    INSERT INTO users_count (count) VALUES (v_count);
    RETURN 't';
ELSE
    RETURN 'f';
END IF;

# 43.6.4.3. IF-THEN-ELSIF

IF boolean-expression THEN
    statements
[ ELSIF boolean-expression THEN
    statements
[ ELSIF boolean-expression THEN
    statements
    ...
]
]
[ ELSE
    statements ]
END IF;

有时不止两种选择。IF-THEN-ELSIF提供了一种方便的方法,可以依次检查多个备选方案。这个如果连续测试条件,直到找到第一个正确的条件。然后执行相关联的语句,然后控制传递到后面的下一个语句如果结束(任何后续的如果条件是经过测试。)如果没有如果条件是真的,那么其他的执行块(如果有)。

下面是一个例子:

IF number = 0 THEN
    result := 'zero';
ELSIF number > 0 THEN
    result := 'positive';
ELSIF number < 0 THEN
    result := 'negative';
ELSE
    -- hmm, the only other possibility is that number is null
    result := 'NULL';
END IF;

关键词埃尔西夫也可以拼写埃尔塞夫.

完成相同任务的另一种方法是嵌套如果-然后-否则语句,如下例所示:

IF demo_row.sex = 'm' THEN
    pretty_sex := 'man';
ELSE
    IF demo_row.sex = 'f' THEN
        pretty_sex := 'woman';
    END IF;
END IF;

但是,此方法需要编写匹配的如果结束每人如果,因此它比使用埃尔西夫当有很多选择的时候。

# 43.6.4.4.简单的案例

CASE search-expression
    WHEN expression [, expression [ ... ]] THEN
      statements
  [ WHEN expression [, expression [ ... ]] THEN
      statements
    ... ]
  [ ELSE
      statements ]
END CASE;

简单形式的案例提供基于操作数相等的条件执行。这个*搜索表达式评估(一次)并依次与每个表示什么时候条款。如果找到匹配项,则相应的声明*执行,然后控制传递到之后的下一个语句结案(随后)什么时候表达式不会被计算。)如果未找到匹配项,则其他的 *声明*被处决;但如果其他的如果不存在,那么未找到案例提出了例外情况。

下面是一个简单的例子:

CASE x
    WHEN 1, 2 THEN
        msg := 'one or two';
    ELSE
        msg := 'other value than one or two';
END CASE;

# 43.6.4.5.搜索案例

CASE
    WHEN boolean-expression THEN
      statements
  [ WHEN boolean-expression THEN
      statements
    ... ]
  [ ELSE
      statements ]
END CASE;

搜索到的案例基于布尔表达式的真值提供条件执行。每个什么时候条款的*布尔表达式依次进行评估,直到发现符合事实的.然后是相应的声明*执行,然后控制传递到之后的下一个语句结案(随后)什么时候表达式不会被计算。)如果未找到真实结果,则其他的 *声明*被处决;但如果其他的如果不存在,那么未找到案例提出了例外情况。

下面是一个例子:

CASE
    WHEN x BETWEEN 0 AND 10 THEN
        msg := 'value is between zero and ten';
    WHEN x BETWEEN 11 AND 20 THEN
        msg := 'value is between eleven and twenty';
END CASE;

这种形式的案例完全等同于IF-THEN-ELSIF,但不包括以下规则:其他的子句导致错误,而不是什么都不做。

# 43.6.5.简单循环

, 出口, 持续, 虽然, 对于弗雷奇语句,您可以安排PL/pgSQL函数重复一系列命令。

# 43.6.5.1. 

[ <<label>> ]
LOOP
    statements
END LOOP [ label ];

定义一个无条件循环,该循环无限期重复,直到被出口回来陈述可选的*标签*可供出口持续嵌套循环中的语句,以指定这些语句引用的循环。

# 43.6.5.2. 出口

EXIT [ label ] [ WHEN boolean-expression ];

如果没有*标签给定时,终止最里面的循环,并执行以下语句端环下一步执行。如果标签*给定时,它必须是当前或嵌套循环或块的某个外部级别的标签。然后终止命名的循环或块,并在循环/块的相应终止.

如果什么时候指定时,循环退出仅在*布尔表达式*这是真的。否则,控件将在出口.

出口可用于所有类型的回路;它不限于与无条件循环一起使用。

当与开始出口将控制传递给块结束后的下一条语句。请注意,必须为此使用标签;未标记的出口从未被认为与开始块(这是对PostgreSQL 8.4之前版本的更改,该版本允许未标记的出口匹配开始街区。)

例如:

LOOP
    -- some computations
    IF count > 0 THEN
        EXIT;  -- exit loop
    END IF;
END LOOP;

LOOP
    -- some computations
    EXIT WHEN count > 0;  -- same result as previous example
END LOOP;

<<ablock>>
BEGIN
    -- some computations
    IF stocks > 100000 THEN
        EXIT ablock;  -- causes exit from the BEGIN block
    END IF;
    -- computations here will be skipped when stocks > 100000
END;

# 43.6.5.3. 持续

CONTINUE [ label ] [ WHEN boolean-expression ];

如果没有*标签给定后,开始最内层循环的下一次迭代。也就是说,将跳过循环体中剩余的所有语句,并且控制返回到循环控制表达式(如果有),以确定是否需要另一个循环迭代。如果标签*存在时,它指定将继续执行的循环的标签。

如果什么时候则循环的下一次迭代仅在以下情况下开始:*布尔表达式*这是真的。否则,控件将在持续.

持续可用于所有类型的回路;它不限于与无条件循环一起使用。

例如:

LOOP
    -- some computations
    EXIT WHEN count > 100;
    CONTINUE WHEN count < 50;
    -- some computations for count IN [50 .. 100]
END LOOP;

# 43.6.5.4. 虽然

[ <<label>> ]
WHILE boolean-expression LOOP
    statements
END LOOP [ label ];

这个虽然语句重复一系列语句,只要*布尔表达式*计算结果为真。在循环体的每个条目之前检查表达式。

例如:

WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
    -- some computations here
END LOOP;

WHILE NOT done LOOP
    -- some computations here
END LOOP;

# 43.6.5.5. 对于(整数变量)

[ <<label>> ]
FOR name IN [ REVERSE ] expression .. expression [ BY expression ] LOOP
    statements
END LOOP [ label ];

这种形式的对于创建在整数值范围内迭代的循环。变量*名称*自动定义为类型整数并且只存在于循环中(在循环中忽略变量名的任何现有定义)。给出范围下限和上限的两个表达式在进入循环时计算一次。如果通过如果迭代步骤为1,则未指定子句,否则为通过子句,在循环条目上再次对其求值一次。如果颠倒然后在每次迭代后减去而不是添加步长值。

整数的一些例子对于循环:

FOR i IN 1..10 LOOP
    -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;

FOR i IN REVERSE 10..1 LOOP
    -- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop
END LOOP;

FOR i IN REVERSE 10..1 BY 2 LOOP
    -- i will take on the values 10,8,6,4,2 within the loop
END LOOP;

如果下限大于上限(或小于颠倒在这种情况下,根本不执行循环体。没有出现错误。

如果*标签附在对于循环然后整数循环变量可以用限定名引用,使用标签*.

# 43.6.6.循环查询结果

使用不同类型的对于循环,您可以遍历查询结果并相应地操作该数据。语法是:

[ <<label>> ]
FOR target IN query LOOP
    statements
END LOOP [ label ];

这个*目标是记录变量、行变量或以逗号分隔的标量变量列表。这个目标连续地分配从查询*循环体针对每一行执行。下面是一个例子:

CREATE FUNCTION refresh_mviews() RETURNS integer AS $$
DECLARE
    mviews RECORD;
BEGIN
    RAISE NOTICE 'Refreshing all materialized views...';

    FOR mviews IN
       SELECT n.nspname AS mv_schema,
              c.relname AS mv_name,
              pg_catalog.pg_get_userbyid(c.relowner) AS owner
         FROM pg_catalog.pg_class c
    LEFT JOIN pg_catalog.pg_namespace n ON (n.oid = c.relnamespace)
        WHERE c.relkind = 'm'
     ORDER BY 1
    LOOP

        -- Now "mviews" has one record with information about the materialized view

        RAISE NOTICE 'Refreshing materialized view %.% (owner: %)...',
                     quote_ident(mviews.mv_schema),
                     quote_ident(mviews.mv_name),
                     quote_ident(mviews.owner);
        EXECUTE format('REFRESH MATERIALIZED VIEW %I.%I', mviews.mv_schema, mviews.mv_name);
    END LOOP;

    RAISE NOTICE 'Done refreshing materialized views.';
    RETURN 1;
END;
$$ LANGUAGE plpgsql;

如果循环终止于出口语句中,循环之后仍然可以访问最后分配的行值。

这个*查询*用于这种类型的对于语句可以是向调用方返回行的任何SQL命令:选择是最常见的情况,但也可以使用插入, 使现代化删去用一个返回条款一些实用程序命令,例如解释这也行。

PL/pgSQL变量被查询参数替换,查询计划被缓存以供可能的重用,如中详细讨论的第43.11.1节第43.11.2节.

这个FOR-IN-EXECUTE语句是迭代行的另一种方式:

[ <<label>> ]
FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP
    statements
END LOOP [ label ];

这与上一个表单类似,只是源查询被指定为字符串表达式,该表达式在查询的每个条目上进行计算和重新规划对于环这允许程序员选择预先计划的查询的速度或动态查询的灵活性,就像选择普通查询一样处决陈述就像处决,参数值可以通过使用.

另一种指定查询的方法是将其声明为游标,该查询的结果应该被遍历。这在中进行了描述第43.7.4节.

# 43.6.7.在数组中循环

这个弗雷奇loop很像一个对于循环,但它不是遍历SQL查询返回的行,而是遍历数组值的元素。(总的来说,弗雷奇用于循环通过复合值表达式的组件;未来可能会添加阵列之外的复合材料循环变体。)这个弗雷奇循环数组的语句是:

[ <<label>> ]
FOREACH target [ SLICE number ] IN ARRAY expression LOOP
    statements
END LOOP [ label ];

没有,或者如果切片0指定时,循环将遍历通过计算*表示这个目标*变量按顺序分配给每个元素值,并为每个元素执行循环体。下面是一个循环整数数组元素的示例:

CREATE FUNCTION sum(int[]) RETURNS int8 AS $$
DECLARE
  s int8 := 0;
  x int;
BEGIN
  FOREACH x IN ARRAY $1
  LOOP
    s := s + x;
  END LOOP;
  RETURN s;
END;
$$ LANGUAGE plpgsql;

这些元素是按存储顺序访问的,与阵列维数无关。虽然*目标*通常只是一个变量,当循环通过复合值(记录)数组时,它可以是一个变量列表。在这种情况下,对于每个数组元素,变量都是从复合值的连续列中赋值的。

以积极的态度价值弗雷奇迭代数组的各个部分,而不是单个元素。这个值必须是不大于数组维数的整数常量。这个*目标*变量必须是数组,它接收数组值的连续切片,其中每个切片的维数由.下面是一个迭代一维切片的示例:

CREATE FUNCTION scan_rows(int[]) RETURNS void AS $$
DECLARE
  x int[];
BEGIN
  FOREACH x SLICE 1 IN ARRAY $1
  LOOP
    RAISE NOTICE 'row = %', x;
  END LOOP;
END;
$$ LANGUAGE plpgsql;

SELECT scan_rows(ARRAY[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]);

NOTICE:  row = {1,2,3}
NOTICE:  row = {4,5,6}
NOTICE:  row = {7,8,9}
NOTICE:  row = {10,11,12}

# 43.6.8.陷阱错误

默认情况下,PL/pgSQL函数中发生的任何错误都会中止函数和周围事务的执行。您可以通过使用开始用木块挡住例外条款该语法是开始街区:

[ <<label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
EXCEPTION
    WHEN condition [ OR condition ... ] THEN
        handler_statements
    [ WHEN condition [ OR condition ... ] THEN
          handler_statements
      ... ]
END;

如果没有错误发生,这种形式的块只会执行所有*声明,然后控制传递到后面的下一个语句终止.但如果在声明,进一步处理声明被放弃,控制权移交给例外列表在列表中搜索第一个条件匹配发生的错误。如果找到匹配项,则相应的handler_语句*执行,然后控制传递到之后的下一个语句终止。如果未找到匹配项,则错误会向外传播,就像例外子句根本不存在:错误可以被包含例外,或者如果没有,它将中止函数的处理。

这个*条件*名称可以是中显示的任何名称附录A.类别名称与其类别中的任何错误匹配。特殊条件名称其他的匹配所有错误类型,除了查询被取消断言失败(按名称捕获这两种错误类型是可能的,但通常是不明智的。)条件名称不区分大小写。此外,错误条件可以由SQLSTATE密码例如,这些是等效的:

WHEN division_by_zero THEN ...
WHEN SQLSTATE '22012' THEN ...

如果所选系统中出现新错误*handler_语句*,这是不可能的例外子句,但被传播出去。周围环境例外我可能会抓住它。

当一个错误被一个例外子句中,PL/pgSQL函数的局部变量保持错误发生时的状态,但块内对持久数据库状态的所有更改都会回滚。作为一个例子,考虑这个片段:

INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones');
BEGIN
    UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones';
    x := x + 1;
    y := x / 0;
EXCEPTION
    WHEN division_by_zero THEN
        RAISE NOTICE 'caught division_by_zero';
        RETURN x;
END;

当控制权到达分配给y,它将以失败告终除法错误这将被例外条款中返回的值回来语句将是十、,但是使现代化命令将被回滚。这个插入但是,块前面的命令不会回滚,因此最终结果是数据库包含汤姆·琼斯乔·琼斯.

# 提示

包含一个例外进入和退出一个街区的费用要比没有一个街区的要高得多。因此,不要使用例外没有必要。

例43.2.例外情况使现代化/插入

本例使用异常处理来执行使现代化插入,视情况而定。建议应用程序使用插入具有关于冲突,请更新而不是实际使用这种模式。此示例主要用于说明PL/pgSQL控制流结构的使用:

CREATE TABLE db (a INT PRIMARY KEY, b TEXT);

CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS
$$
BEGIN
    LOOP
        -- first try to update the key
        UPDATE db SET b = data WHERE a = key;
        IF found THEN
            RETURN;
        END IF;
        -- not there, so try to insert the key
        -- if someone else inserts the same key concurrently,
        -- we could get a unique-key failure
        BEGIN
            INSERT INTO db(a,b) VALUES (key, data);
            RETURN;
        EXCEPTION WHEN unique_violation THEN
            -- Do nothing, and loop to try the UPDATE again.
        END;
    END LOOP;
END;
$$
LANGUAGE plpgsql;

SELECT merge_db(1, 'david');
SELECT merge_db(1, 'dennis');

这种编码假定唯一违反错误是由插入,而不是一个插入在表上的触发器函数中。如果表上有多个唯一索引,它也可能会出现错误,因为不管是哪个索引导致了错误,它都会重试该操作。通过使用下面讨论的特性来检查捕获的错误是否是预期的错误,可以获得更大的安全性。

# 43.6.8.1.获取有关错误的信息

异常处理程序通常需要识别发生的特定错误。有两种方法可以获取PL/pgSQL中当前异常的信息:特殊变量和获取堆叠诊断命令

在异常处理程序中,特殊变量SQLSTATE包含与引发的异常相对应的错误代码(请参阅表A.1查看可能的错误代码列表)。特殊变量SQLERRM包含与异常关联的错误消息。这些变量在异常处理程序之外是未定义的。

在异常处理程序中,还可以使用获取堆叠诊断命令,其形式如下:

GET STACKED DIAGNOSTICS variable { = | := } item [ , ... ];

每个*项目是一个关键字,用于标识要分配给指定对象的状态值变量*(应该是正确的数据类型来接收它)。中显示了当前可用的状态项表43.2.

表43.2.错误诊断项

名称 类型 描述
返回的SQL状态 文本 异常的SQLSTATE错误代码
列名 文本 与异常相关的列的名称
你的名字 文本 与异常相关的约束的名称
PG_数据类型_名称 文本 与异常相关的数据类型的名称
短信 文本 异常的主要消息的文本
表2\u名称 文本 与异常相关的表的名称
模式名称 文本 与异常相关的架构的名称
PG_例外情况_详情 文本 异常详细信息的文本(如果有)
PG_异常提示 文本 异常提示消息的文本(如果有)
PG_例外情况_上下文 文本 描述异常时调用堆栈的文本行(请参见第43.6.9节)

如果异常未为项设置值,则将返回空字符串。

下面是一个例子:

DECLARE
  text_var1 text;
  text_var2 text;
  text_var3 text;
BEGIN
  -- some processing which might cause an exception
  ...
EXCEPTION WHEN OTHERS THEN
  GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
                          text_var2 = PG_EXCEPTION_DETAIL,
                          text_var3 = PG_EXCEPTION_HINT;
END;

# 43.6.9.获取执行位置信息

这个获取诊断信息命令,如前所述第43.5.5节,检索有关当前执行状态的信息(而获取堆叠诊断上面讨论的命令报告了有关上一个错误的执行状态的信息)。它的PG_语境状态项用于标识当前执行位置。PG_语境返回一个文本字符串,其中包含描述调用堆栈的文本行。第一行是指当前函数和当前正在执行的函数获取诊断信息命令第二行和随后的任何一行都指调用堆栈上的调用函数。例如:

CREATE OR REPLACE FUNCTION outer_func() RETURNS integer AS $$
BEGIN
  RETURN inner_func();
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION inner_func() RETURNS integer AS $$
DECLARE
  stack text;
BEGIN
  GET DIAGNOSTICS stack = PG_CONTEXT;
  RAISE NOTICE E'--- Call Stack ---\n%', stack;
  RETURN 1;
END;
$$ LANGUAGE plpgsql;

SELECT outer_func();

NOTICE:  --- Call Stack ---
PL/pgSQL function inner_func() line 5 at GET DIAGNOSTICS
PL/pgSQL function outer_func() line 3 at RETURN
CONTEXT:  PL/pgSQL function outer_func() line 3 at RETURN
 outer_func
 ------------
           1
(1 row)

把诊断码叠起来。。。PG_例外情况_上下文返回相同种类的堆栈跟踪,但描述检测到错误的位置,而不是当前位置。