# 43.6.控制结构
控制结构可能是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_例外情况_上下文
返回相同种类的堆栈跟踪,但描述检测到错误的位置,而不是当前位置。