【速记】Postgresql游标短暂的一生

news/2024/7/9 19:55:06 标签: postgresql, 数据库, sql

游标跟随子事务声明周期

例如Postgresql中有下面一个游标curs4:

drop table if exists t_plpgsql_transaction_20230406_01;
drop table if exists t_plpgsql_transaction_20230406_02;
create table t_plpgsql_transaction_20230406_01(a int);
create table t_plpgsql_transaction_20230406_02(a float);

CREATE or replace PROCEDURE p_inner_20230406()
LANGUAGE plpgsql
AS $$
DECLARE
    carry float;
    cnt int[];
    curs4 refcursor;
    res t_plpgsql_transaction_20230406_01%ROWTYPE;
BEGIN
    open curs4 FOR SELECT * FROM t_plpgsql_transaction_20230406_01;
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (16);
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (17);
    
    fetch curs4 into res; RAISE NOTICE 'curs4 : %', res;
    carry := 1 / 0;
    
EXCEPTION WHEN others THEN 
    commit;
    raise notice 'exception';
END;
$$;

call p_inner_20230406();

创建

curs4的在exec_stmt_open中被创建出来,创建时使用CreatePortal返回一个游标Portal:

  • 注意创建时有一层子事务,exception-transaction,事务堆栈两层。所以游标Portal归属于第二层exception-transaction上。

    Portal的resowner也挂在exception-transaction下面。

创建完resowner的样子:

     TopTransactionResourceOwner
     / 
 SubTransaction    ->    Portal(函数执行portal)
    /
  Portal(游标portal)

释放

1/0发生异常后,会自动回滚第二层exception-transaction,游标跟随exception-transaction释放:

  • 注意Portal的resowner只是指向resowner树的某一个位置,释放时resowner不随potal释放,而是随事务的resowner树释放。
  • 释放顺序:先在AbortSubTransaction把portal->resowner置为空;然后CleanupSubTransaction中完成resowner的释放,注意释放只会释放SubTransaction的resowner,游标的res是跟随释放的。
     TopTransactionResourceOwner
     / 
 SubTransaction(释放)    ->    Portal(函数执行portal)
    /
  Portal(游标portal)(释放)

释放完

     TopTransactionResourceOwner
           / 
         Portal(函数执行portal)

内层函数声明的游标无法给外层函数使用

sql">drop table if exists t_plpgsql_transaction_20230406_01;
drop table if exists t_plpgsql_transaction_20230406_02;
create table t_plpgsql_transaction_20230406_01(a int);
create table t_plpgsql_transaction_20230406_02(a float);

CREATE or replace PROCEDURE p_inner_20230406()
LANGUAGE plpgsql
AS $$
DECLARE
    carry float;
    cnt int[];
    curs4 refcursor;
    res t_plpgsql_transaction_20230406_01%ROWTYPE;
BEGIN
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (16);
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (17);
    open curs4 FOR SELECT * FROM t_plpgsql_transaction_20230406_01;
    -- carry := 1 / 0;  
EXCEPTION WHEN others THEN 
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (16);
    open curs4 FOR SELECT * FROM t_plpgsql_transaction_20230406_01;
    fetch curs4 into res; RAISE NOTICE 'curs4 : %', res;
    raise notice 'exception exception';
END;
$$;

CREATE or replace PROCEDURE p_outter_20230406()
LANGUAGE plpgsql
AS $$
DECLARE
    carry float;
    cnt int[];
    curs4 refcursor;
    res t_plpgsql_transaction_20230406_01%ROWTYPE;
BEGIN
    call p_inner_20230406();
    fetch curs4 into res; RAISE NOTICE 'curs4 : %', res;
END;
$$;



call p_outter_20230406();

结果

postgres=# call p_outter_20230406();
ERROR:  cursor variable "curs4" is null
CONTEXT:  PL/pgSQL function p_outter_20230406() line 9 at FETCH

内层函数exception声明的游标无法给外层函数使用

sql">drop table if exists t_plpgsql_transaction_20230406_01;
drop table if exists t_plpgsql_transaction_20230406_02;
create table t_plpgsql_transaction_20230406_01(a int);
create table t_plpgsql_transaction_20230406_02(a float);

CREATE or replace PROCEDURE p_inner_20230406()
LANGUAGE plpgsql
AS $$
DECLARE
    carry float;
    cnt int[];
    curs4 refcursor;
    res t_plpgsql_transaction_20230406_01%ROWTYPE;
BEGIN
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (16);
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (17);
    carry := 1 / 0;  
EXCEPTION WHEN others THEN 
    INSERT INTO t_plpgsql_transaction_20230406_01 (a) VALUES (16);
    open curs4 FOR SELECT * FROM t_plpgsql_transaction_20230406_01;
    fetch curs4 into res; RAISE NOTICE 'curs4 : %', res;
    raise notice 'exception exception';
END;
$$;

CREATE or replace PROCEDURE p_outter_20230406()
LANGUAGE plpgsql
AS $$
DECLARE
    carry float;
    cnt int[];
    curs4 refcursor;
    res t_plpgsql_transaction_20230406_01%ROWTYPE;
BEGIN
    call p_inner_20230406();
    fetch curs4 into res; RAISE NOTICE 'curs4 : %', res;
END;
$$;



call p_outter_20230406();

结果

postgres=# call p_outter_20230406();
NOTICE:  curs4 : (16)
NOTICE:  exception exception
ERROR:  cursor variable "curs4" is null
CONTEXT:  PL/pgSQL function p_outter_20230406() line 9 at FETCH

http://www.niftyadmin.cn/n/228966.html

相关文章

数据的表示和存储1

目录 数制和编码 信息的二进制编码 数值数据的表示 进制计数制 定点数和浮点数 定点数的编码表示 原码表示 补码表示 求特殊数的补码 求真值的补码 求补码的真值 移码表示Excess (biased) notiion C语言中的整数 无符号整数(unsigned integer) 带符号整数&#xff0…

Spark-SQL——DataFrame与Dataset

文章目录一、Spark SQL概述1.1、Spark SQL是什么?1.2、Hive和Spark SQL1.3、DataFrame与DataSet二、Spark SQL编程2.1、DataFrame2.1.1、创建DataFrame2.1.2、SQL语法2.1.3、DSL语法2.2、Dataset2.2.1、创建DataSet2.2.2、RDD与Dataset互转2.2.3、DataFrame 和 Data…

SEEM:微软基于 CV 大模型新作,分割“瞬息全宇宙”

文 | 智商掉了一地交互式视觉分割新作,具有语义感知的新模型~自从 Meta 发布了“分割一切”的 SAM 之后,各种二创如雨后春笋般冒出,昨天微软的一篇论文又在推特上引起讨论,虽然最开始吸引小编的是它的名字——分割“瞬息全宇宙”&…

Denoising Diffusion Probabilistic Model,DDPM阅读笔记——(一)

Denoising Diffusion Probabilistic Model一、写在前面二、相关数学知识简介二、生成模型简介:三、变分自编码器概述(VAE)一、写在前面 人工智能生成内容(AI Generated Content,AIGC)近年来成为了非常前沿…

安全测试(linux基线排查)看这一篇就够了

前言部分: 作为一个安全测试人员,在确保WEB应用程序没有漏洞外,应该也需要关注一下主机环境的安全,因为应用程序部署在主机环境提供运行环境,也应当关注一下主机环境的安全。于此,通过学习本次对linux安全加…

2023-04-13 工作记录--CSS/JS-ios 文本渐变色 和 文本超出省略号处理 共用时,出现省略号未显示问题

CSS/JS-ios 文本渐变色 和 文本超出省略号处理 共用时,出现省略号未显示问题 一、前言 ⭐️ 最近写项目,发现一个bug:ios 文本渐变色 和 文本超出省略号处理 共用时,出现省略号未显示问题,如下图:图1是非i…

Java 设计模式之组合模式

目录 1、组合模式阐述 2、组合模式的代码实现 3、组合模式在Java中的应用场景 1、组合模式阐述 Java 组合模式是一种结构型设计模式,它允许将对象组成树形结构来表达“整体-部分”的层次关系,使得客户端代码能够以统一的方式处理单个…

【软考数据库】第一章 计算机系统基础知识

目录 1.1 计算机系统 1.1.1 计算机硬件组成 1.1.2 中央处理单元 1.1.3 数据表示 1.1.4 校验码 1.2 计算机体系结构 1.2.1 体系结构分类 1.2.2 指令系统存 1.2.3 储系系统 1.2.4 输入/输出技术 1.2.5 总线结构…