【MogDB】MogDB5.2.0重磅发布第六篇-支持自定义复杂对象类型

一、前言

在期货行业的ORACLE数据库中,经常可以看到有大量的自定义复杂对象类型,类似以下代码

CREATE OR REPLACE TYPE Ty_test as OBJECT
(
  col1 NUMBER(8),
  COL2 CHAR(8),
  CONSTRUCTOR FUNCTION Ty_test RETURN SELF AS RESULT,
  MEMBER FUNCTION UF_2STRING RETURN VARCHAR2
);
/
create or replace type body Ty_test as 
  CONSTRUCTOR FUNCTION Ty_test RETURN SELF AS RESULT is
  begin
  return;
  end;
  MEMBER FUNCTION UF_2STRING RETURN VARCHAR2 is
  begin
  return 'Ty_test('||
          'col1 =>'''||col1||','||
          'col2 =>'''||col2||''')';
  end;
end;
/

create or replace type tyt_test as table of  Ty_test ;
/

CREATE OR REPLACE TYPE Ty_R_test as OBJECT
(
  col1 NUMBER(8),
  COL2 CHAR(8),
  col3 char(8),
  CONSTRUCTOR FUNCTION Ty_R_test RETURN SELF AS RESULT,
  MEMBER PROCEDURE up_copy(i_ty_test IN ty_test),
  MEMBER FUNCTION UF_2STRING RETURN VARCHAR2
);
/
create or replace type body Ty_R_test as 
  CONSTRUCTOR FUNCTION Ty_R_test RETURN SELF AS RESULT is
  begin
  return;
  end;
  MEMBER PROCEDURE up_copy(i_ty_test IN ty_test) is
  begin
  col1:=i_ty_test.col1;
  end;
  MEMBER FUNCTION UF_2STRING RETURN VARCHAR2 is
  begin
  return 'Ty_R_test('||
          'col1 =>'''||col1||','||
          'col2 =>'''||col2||''')';
  end;
end;
/

create or replace type tyt_r_test as table of  Ty_R_test ;
/

ORACLE甚至专门为这种对象类型弄了一整本文档:
《Object-Relational Developer's Guide》
而openGauss并不支持创建这种对象,只能支持不带type body的复合类型。截止到20240930的openGauss 6.0版本发布,也仍旧不支持(不过从2024年10月14号起,openGauss源码中已经有部分支持了)。

所以早期openGauss/MogDB在适配有这种对象类型的应用时,需要进行非常多的人工改写(可以批量正则替换),虽然改了后的确能用,但是这些应用的开发模式本来就是围绕着这些对象类型来的,直接颠覆了十多年的开发模式所造成的影响可能会非常深远。

因此MogDB在5.2.0版本中,引入了对象类型的实现,新增的功能涉及SQL引擎/PLSQL引擎/JDBC驱动/客户端工具等。

二、SQL引擎

1.ddl/dcl

  • 增加 or replace语法
    原本openGauss5.0版本中,不支持对任何的type进行replace,如果要修改自定义的type,必须先drop原有的,再创建新的(在没有被其他对象依赖时,支持alter)。在MogDB 5.2.0版本中,支持对object-type和嵌套表类型(table of)执行create or replace type

  • grant /revoke 权限时,相应的type/function同步处理
    在创建一个object-type时,会自动创建一个复合类型,并且逐个创建type内定义的构造函数、成员函数、成员过程,因此执行grant /revoke时需要进行自动的级联授权(和openGauss中的package相关逻辑类似)

2.查询构造

  • 支持直接执行 select typename(col1_name,col2_name) from tablename,或作为游标

三、PLSQL引擎

1.默认值构造

  • 不带new
  • 带new
  • 默认构造函数
  • 自定义构造函数
declare
v1 Ty_test :=Ty_test();
v2 Ty_test :=new Ty_test();
v3 Ty_test :=new Ty_test(1,'a');
BEGIN
NULL;
END;

2.赋值构造

  • 不带new
  • 带new
  • 默认构造函数
  • 自定义构造函数
declare
v1 Ty_test ;
begin
v1:=Ty_test();
v1:=new Ty_test();
v1:=new Ty_test(1,'a');
BEGIN
NULL;
END;

3.查询构造 into

  • 单行单个对象 into
  • 单行多个对象 into
  • 多行 bulk collect into
create table tab_a(col1 number,col2 varchar2(20));
create table tab_b(col1 number,col2 varchar2(20));
insert into tab_a values(1,'a');
insert into tab_b values(1,'a');

declare
v1 Ty_test;
v2 Ty_test;
v3 tyt_test;
v4 tyt_test;
begin
select Ty_test(1,'a') into v1 from dual;
select Ty_test(1,'a'),Ty_test(2,'b') into v1,v2 from dual;
select Ty_test(tab_a.col1,tab_a.col2),Ty_test(tab_b.col1,tab_b.col2) bulk collect into v3,v4 from tab_a,tab_b;

4.引用成员属性

  • 单对象的成员属性
  • 集合内某个对象的成员属性
declare
v1 Ty_test:=new Ty_test(1,'a');
v2 number;
v3 tyt_test:=new tyt_test();
begin
v2:=v1.col1;
v3.extend;
v3(1):=v1;
v2:=v3(1).col1;
end;

5.引用成员函数

  • 单对象的成员函数
  • 集合内某个对象的成员函数
declare
v1 Ty_test:=new Ty_test(1,'a');
v2 varchar2(100);
v3 tyt_test:=new tyt_test();
begin
v2:=v1.UF_2STRING();
v3.extend;
v3(1):=v1;
v2:=v3(1).UF_2STRING;

6.调用成员过程

  • 单对象的成员过程
declare
v1 Ty_test:=new Ty_test(1,'a');
v2 ty_r_test:=new ty_r_test();
begin
v2.up_copy(v1);
END;

7.对象是否为空的判断

  • object是否为空
  • collection是否为空
declare
v1 Ty_test;
v2 tyt_test;
begin
if v1 is null then 
dbms_output.put_line('1');
end if;
if v1 is not null then 
dbms_output.put_line('2');
end if;
v1:=new Ty_test();
if v1 is null then 
dbms_output.put_line('3');
end if;
if v1 is not null then 
dbms_output.put_line('4');
end if;
-----
if v2 is null then 
dbms_output.put_line('5');
end if;
if v2 is not null then 
dbms_output.put_line('6');
end if;
v2:=new Tyt_test();
if v2 is null then 
dbms_output.put_line('7');
end if;
if v2 is not null then 
dbms_output.put_line('8');
end if;
end;
/

1
4
5
8

8.重载

  • 成员函数重载
  • 构造函数重载
  • 作为重载函数的参数类型

9.集合方法

  • first
  • last

支持table of object的变量使用table of object的first/last属性作为下标

declare
v2 tyt_test;
begin
......
where col1 = v2(v2.First).col1
  • delete
  • extend
  • count

对齐ORACLE里的计数及判空逻辑

10.支持自治事务

(非特性,略,修复openGauss中相关BUG)

四、JDBC驱动

  • createStruct
  • createArrayOf

云和恩墨已将该功能部分贡献至openGauss社区,可能是目前PG/OG系唯一的对obejct-type调用的jdbc开源代码(注:最佳体验建议使用MogDB的官方jdbc驱动5.0.0.9版本)

源码中的测试用例:
https://gitee.com/opengauss/openGauss-connector-jdbc/blob/master/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PGStructTest.java
https://gitee.com/opengauss/openGauss-connector-jdbc/blob/master/pgjdbc/src/test/java/org/postgresql/test/jdbc2/PgCallableStatementArrayTypeTest.java

五、元数据

1.元数据视图

  • 新增 gs_object视图,用于查询object-type列表以及定义
MogDB=# \dS+ gs_object
               View "pg_catalog.gs_object"
    Column    | Type | Modifiers | Storage  | Description
--------------+------+-----------+----------+-------------
 oid          | oid  |           | plain    |
 objnamespace | oid  |           | plain    |
 objowner     | oid  |           | plain    |
 objname      | name |           | plain    |
 objspecsrc   | text |           | extended |
 objbodysrc   | text |           | extended |
  • dba_arguments视图中能识别存储过程中的object及table参数类型

2.定义查询函数

  • 新增pg_get_typedef(text) 函数,可查询所有type的ddl定义语句,包括object-type,支持schemaname.typename以及typename 两种格式的传参

六、客户端工具

1.命令行工具

  • gs_dump/gs_restore (逻辑备份/还原)

    • 全备时增加object-type的定义语句生成
    • 在指定 --type参数时,可以导出或导入指定名称的type,包括object-type
  • 在执行 create or replace type {typename} is|as object以及create or replacee type body语句时,语句结束符自动切换到 /,保持和sqlplus一致

  • 为了兼容 create type {typename} is table of {typename}语句的结束符 /,可配置操作系统环境变量 export PGENABLESQLPLUS=true忽略单独执行的 /

2.图形化开发工具

注:从 mogeaver 23.3.1.202409290624 版本开始支持

  • 查询定义:在数据库导航中,在数据类型目录下,双击需要查看定义的数据类型名称,切换到源,即可查看定义

七、总结

MogDB 5.2.0版本引入的对象类型,支持了对象类型最常用的语法,并且在这些语法的执行结果上,保持了和ORACLE一致;周边工具和连接驱动也都做了相应的功能的修改及新增,全链条保障功能的可用性。自此,对于大量使用对象类型的ORACLE应用系统,迁移到MogDB将变得更加无损。

附:部分常见国产数据库支持object-type的情况(标记?的由于获取不到介质或文档,暂无法确认)

数据库 是否支持创建object type 本文中特性是否全部支持
DM8 Y N
KINGBASE 8 Y N
OCENABASE 4.0 Y ?
POLARDB-O 2.0 Y ?
TDSQL-PG(Oracle兼容版) Y ?
UXDB N N
GAUSSDB 503.1.0.SPC1700 N N
OPENGAUSS 6.0.0 N N
GBase8cV5 S5.0.0B28 N N
VASTBASE G100 V2.2 BUILD 16 Y N
翰高 6.0.4 N N
崖山 Y N
神通 ? ?
海盒 ? ?
MogDB 5.2.0 Y Y

注:ORACLE中的object-type远不止本文中的这些功能,MogDB5.2.0也仅仅只是根据实际客户项目中的所有用法做了实现。而有几家国产数据库的文档中描述的功能列表几乎和ORACLE保持一致,但是仍然无法全部通过本文中的测试用例。

posted on 2024-11-02 00:48  DarkAthena  阅读(6)  评论(0编辑  收藏  举报

导航