news 2026/4/15 11:20:41

【openGauss】如何在openGauss中实现类似Oracle中constructor function、member function的功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【openGauss】如何在openGauss中实现类似Oracle中constructor function、member function的功能

背景

面向过程编程和面向对象编程,是两种编程的思维方式。在数据库中编程,大多都是用的存储过程,但是Oracle也支持面向对象的编程方式,即在自定义type中,包含constructor function、member function的声明及定义。这种方式,能够较为轻松地使用其他面向对象编程的语言进行相互移植,虽然语法上有所区别,但是重要的是主体逻辑基本不用变,甚至oracle也提供了其他开发语言对这种type对象直接调用的支持。
《ORACLE对象关系开发人员指南》
所以,实际上也存在很多在oracle中使用面向对象编程的代码。
在openGauss3.0中,是不支持这种功能的,所以本文来讨论,如何在openGauss3.0中进行改写以支持类似的功能。

改写的例子

例一:

CREATE OR REPLACE TYPE MESSAGE_RET_T AS OBJECT ( RET_CODE VARCHAR2 (6 CHAR), RET_MESSAGE VARCHAR2 (512 CHAR), CONSTRUCTOR FUNCTION MESSAGE_RET_T RETURN SELF AS RESULT ) / CREATE OR REPLACE TYPE BODY MESSAGE_RET_T AS CONSTRUCTOR FUNCTION MESSAGE_RET_T RETURN SELF AS RESULT IS BEGIN RETURN; END; END; / --使用(指定参数位置) declare a MESSAGE_RET_T:=MESSAGE_RET_T(RET_CODE=>'a1',RET_MESSAGE=>'b1'); begin dbms_output.put_line(a.RET_CODE||'-'||a.RET_MESSAGE); end;

在MESSAGE_RET_T这个type中,有一个构建函数返回了自己,也就是说,通过这一段
MESSAGE_RET_T(RET_CODE=>‘a1’,RET_MESSAGE=>‘b1’) 生成了一个对象,对象的类型为MESSAGE_RET_T。

如果在openGauss3.0中也要支持这样的功能,那么MESSAGE_RET_T就只能是个函数,因为openGauss中的type不能指定参数位置传参。
这样就变成了,既要有MESSAGE_RET_T这个函数,也得有MESSAGE_RET_T这个TYPE,很明显不行。而且如果一个type内的函数很多,不同type间有重名函数,这样必然会导致混乱和冲突。

所以这个时候可以引入package的概念,于是乎,我尝试在openGauss中创建一个type,并用这个type创建同名的package,package中必须包含一个self函数,用于返回同名package对象,比如

CREATE TYPE MESSAGE_RET_T AS ( RET_CODE VARCHAR2 (6 ), -- 交易返回代码 RET_MESSAGE VARCHAR2 (512 ) -- 交易返回信息 ); create or REPLACE package MESSAGE_RET_T is function SELF(RET_CODE varchar2,RET_MESSAGE VARCHAR2) return MESSAGE_RET_T; end MESSAGE_RET_T; create or replace package body MESSAGE_RET_T is function SELF(RET_CODE varchar2,RET_MESSAGE VARCHAR2) return MESSAGE_RET_T is val MESSAGE_RET_T; begin val.RET_CODE:=RET_CODE; val.RET_MESSAGE:=RET_MESSAGE; return val; end; end MESSAGE_RET_T; --使用(指定参数位置) declare a MESSAGE_RET_T:=MESSAGE_RET_T.self(RET_CODE=>'a1',RET_MESSAGE=>'b1'); begin dbms_output.put_line(a.RET_CODE||'-'||a.RET_MESSAGE); end;

例二:

如果type中存在返回self以外的其他函数,那么改写时,需要对其他函数都增加一个参数,用于把self生成的对象传入,比如,在oracle中

CREATE OR REPLACE TYPE MESSAGE_LOCAL_HEADER_T AS OBJECT( RET MESSAGE_RET_A, -- 交易结果 CONSTRUCTOR FUNCTION MESSAGE_LOCAL_HEADER_T RETURN SELF AS RESULT, MEMBER FUNCTION getRet RETURN MESSAGE_RET_A ); CREATE OR REPLACE TYPE BODY MESSAGE_LOCAL_HEADER_T AS CONSTRUCTOR FUNCTION MESSAGE_LOCAL_HEADER_T RETURN SELF AS RESULT IS BEGIN RETURN; END; MEMBER FUNCTION getRet RETURN MESSAGE_RET_A IS BEGIN RETURN RET; END; END; / --使用 declare a MESSAGE_LOCAL_HEADER_T; b MESSAGE_RET_A:= MESSAGE_RET_A(); c MESSAGE_RET_T; r1 MESSAGE_RET_A:= MESSAGE_RET_A(); r2 varchar2(20); begin c := MESSAGE_RET_T(RET_CODE => 'a1', RET_MESSAGE => 'b1'); b.extend; b(1) := c; a := MESSAGE_LOCAL_HEADER_T(ret => b); r1 := a.getRet; r2:=r1(1).RET_CODE; dbms_output.put_line(r2); end;

改写后

CREATE TYPE MESSAGE_LOCAL_HEADER_T AS ( RET MESSAGE_RET_A ); create or replace package MESSAGE_LOCAL_HEADER_T is function self(RET MESSAGE_RET_A ) return MESSAGE_LOCAL_HEADER_T; function getRet(self MESSAGE_LOCAL_HEADER_T) return MESSAGE_RET_A; end MESSAGE_LOCAL_HEADER_T; create or replace package body MESSAGE_LOCAL_HEADER_T is function self(RET MESSAGE_RET_A ) return MESSAGE_LOCAL_HEADER_T is val MESSAGE_LOCAL_HEADER_T; begin val:=MESSAGE_LOCAL_HEADER_T(RET); return val; end; function getRet(self MESSAGE_LOCAL_HEADER_T) return MESSAGE_RET_A is begin return self.RET; end; end MESSAGE_LOCAL_HEADER_T; --使用 declare a MESSAGE_LOCAL_HEADER_T; b MESSAGE_RET_A; c MESSAGE_RET_T; r1 MESSAGE_RET_A; r2 varchar2(20); begin c := MESSAGE_RET_T.self(RET_CODE => 'a1', RET_MESSAGE => 'b1'); b.extend; b(1) := c; a := MESSAGE_LOCAL_HEADER_T.self(ret => b ); r1:= MESSAGE_LOCAL_HEADER_T.getRet(a); r2:= r1(1).RET_CODE; dbms_output.put_line(r2); end;

其实这个改写的语法结构,很像python中的class,因为它函数的第一个参数也是self,只是不需要再传自己进来。这种改写方式,除了创建命令有所区别外,调用方式也只有一点点区别

例三:

如果例一中,不需要指定参数位置,那么其实也不需要创建package,比如,在oracle中

CREATE TYPE MESSAGE_LOCAL_HEADER_T AS ( RET MESSAGE_RET_A ); create or replace package MESSAGE_LOCAL_HEADER_T is function self(RET MESSAGE_RET_A ) return MESSAGE_LOCAL_HEADER_T; function getRet(self MESSAGE_LOCAL_HEADER_T) return MESSAGE_RET_A; end MESSAGE_LOCAL_HEADER_T; create or replace package body MESSAGE_LOCAL_HEADER_T is function self(RET MESSAGE_RET_A ) return MESSAGE_LOCAL_HEADER_T is val MESSAGE_LOCAL_HEADER_T; begin val:=MESSAGE_LOCAL_HEADER_T(RET); return val; end; function getRet(self MESSAGE_LOCAL_HEADER_T) return MESSAGE_RET_A is begin return self.RET; end; end MESSAGE_LOCAL_HEADER_T; --使用 declare a MESSAGE_LOCAL_HEADER_T; b MESSAGE_RET_A; c MESSAGE_RET_T; r1 MESSAGE_RET_A; r2 varchar2(20); begin c := MESSAGE_RET_T.self(RET_CODE => 'a1', RET_MESSAGE => 'b1'); b.extend; b(1) := c; a := MESSAGE_LOCAL_HEADER_T.self(ret => b ); r1:= MESSAGE_LOCAL_HEADER_T.getRet(a); r2:= r1(1).RET_CODE; dbms_output.put_line(r2); end;

改写后

CREATE TYPE MESSAGE_RET_T AS ( RET_CODE VARCHAR2 (6 ), RET_MESSAGE VARCHAR2 (512 ) ); --使用(不指定参数位置) declare a MESSAGE_RET_T:=MESSAGE_RET_T('a1','b1'); begin dbms_output.put_line(a.RET_CODE||'-'||a.RET_MESSAGE); end;

可以发现,使用上是一模一样的。

总结

  1. 创建type和同名package
  2. package中放一个self函数用来构造同名type对象
  3. 从原有type中将其他函数都放在package中,并且在函数的参数的第一个位置增加一个参数,指定类型为改type
  4. 使用时,返回自己使用 包名.self 函数
  5. 调用成员函数时,改写成调用 包名.函数的方式,并把原type对象作为第一个参数,其他参数往后排

理论上,这可以算一个通用改写规则了,硬生生用面向过程的处理方式,实现了面向对象的改写,但在编程思想上,仍保留有面向对象的痕迹。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/7 18:38:39

SCI特刊/专刊和正刊的区别?

sci特刊/专刊和正刊的区别?sci专刊,特刊,正刊,增刊有什么区别?下面淘淘论文给大家讲解这个问题。1.正刊所谓正刊,就是在这个期刊正常刊期之内发表的文章,就是正刊发表。这个SCI期刊,…

作者头像 李华
网站建设 2026/4/13 13:10:48

Ubuntu20.04安装TensorFlow/PyTorch GPU及开发环境

Ubuntu 20.04 搭建 GPU 加速深度学习开发环境 在当今 AI 研发的日常中,本地训练环境的搭建依然是许多工程师和研究者绕不开的第一步。尤其是在使用 PyTorch 或 TensorFlow 进行模型训练时,能否顺利启用 GPU 加速,往往直接决定了开发效率的高…

作者头像 李华
网站建设 2026/4/14 7:32:52

力扣701 二叉搜索树中的插入操作 java实现

701.二叉搜索树中的插入操作给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。注意,可能…

作者头像 李华
网站建设 2026/4/7 12:02:00

TensorFlow-GPU安装全指南:版本匹配与实操避坑

TensorFlow-GPU 安装实战指南:绕过版本陷阱,一次成功 在深度学习的世界里,本地 GPU 环境就像炼丹炉——谁不想亲手点燃那团算力之火?可现实往往是:折腾三天三夜,连 tf.device(/GPU) 都跑不通。报错信息五花…

作者头像 李华
网站建设 2026/4/11 2:33:26

LobeChat能否实现AI猜谜游戏?娱乐化交互场景开发

LobeChat能否实现AI猜谜游戏?娱乐化交互场景开发 在智能对话系统日益普及的今天,用户早已不满足于“问一句答一句”的机械互动。他们期待的是更自然、更有趣、甚至带点“人情味”的交流体验——比如和一个会出谜题、能引导思考、还会适时鼓励你的AI玩一场…

作者头像 李华
网站建设 2026/4/8 1:47:24

和鲸科技创始人CEO 范向伟受邀赴港亮相 AI 赋能・科技自立 —— 中小企业创新与机遇高峰论坛并做主题演讲

本文内容节选自:香港中小上市公司协会,内容略有删改2025年12月5日,由香港中小上市公司协会(下文简称「协会」)联同深圳市金融商会主办的「AI赋能・科技自立——中小企业创新与机遇高峰论坛」,于香港四季酒店…

作者头像 李华