关于IvorySQL和OpenGauss包SPEC与集合类型的一些思考

2023-10-13 10:32:52 浏览数 (1)

包的SPEC区

包的SPEC区可以定义下面三种类型(本篇只讨论SPEC区的情况)

  1. 变量
  2. 类型(nested table等)(注意这是包内定义的类型,与SQL创建的不通)
  3. 游标

这三种类型在PG原生中,是找不到相似的功能的:

  1. 变量:变量需要能够作用于所有PL代码中,PG中没有全局变量的这种概念,又因为PL的插件式设计和SQL层解耦,PL变量就算给SQL使用一般也只能用回调(PL的datums拼SQL的params)。
  2. 类型:这里的类型特指嵌套表、动态数组、关联数组。PG的类型全部放在pg_types中,不能在PL层创建。
  3. 游标:PG原生支持SQL层在事务内使用declare/fetch语法定义SQL层游标,但必须在事务块内;PG也支持在PL函数内定义游标,但能再当前函数内使用,不能跨函数。

三种类型有着不同的作用域:

SQL层

PL层

变量

用于函数默认值

可当做全局变量随意使用

类型

可当做基础类型随意使用

游标

只能在定义包内使用,可跨函数使用

三种类型在PG中的实现方法:

  1. 变量:
    • 每个包应该有自己的符号表(命名空间),可以由namespace.pkgname唯一指定到某一个符号表进行搜索。
      • 这里IvorySQL使用pg_variable系统表来保存变量、游标(没实现集合类型),但不会存值,包变量本来就是session级的,按理说不需落盘,推测主要是用索引加速查找。
      • OpenGauss的实现类似于内存中维护各个包的符号表,使用时先搜索函数自己的符号表,再去搜索包的符号表。全内存态没落盘,确实没必要落盘。
    • 实现时可根据pkgname,先编译包,并生成包的符号表,SQL层可回调使用包变量,PL层可直接使用包变量。
    • 在PL层使用时,例如 a := pkg.g_var;,在PL parse时对二段解析增加搜索包命名空间的逻辑即可,不要发生deep copy,将包的datums拷贝到自己的datums中,这样的话会变得非常复杂,执行完还要拷贝回包空间中。
  2. 类型:分三类讨论
    • 嵌套表、动态数组:
      • 20230410:是现在内存中加一些旁路逻辑,增加类型的搜索范围。
      • 20231008:功能等价于数组,从生命周期上来看,包SPEC的类型和包的生命周期一致,从作用域来看,和pg_type中的类型范围有区别:例如SPEC的类型不能用于表字段,但能用于函数入参返回值;BODY中定义的PRIV的类型只能用于当前包。实现时可与SQL层的CREATE NESTED TABLE统一逻辑,做成标准类型记录在pg_type中,在增加字段表示作用域,可最大化复用PG原生逻辑。
    • 关联数组:功能等价与哈希表,
    • 高斯实现了类似于指针数组的功能,避免了PG多维数组的维度锁死的问题(第一次使用定义维度,后面无法修改),实现较为合理:《分析openGauss包内集合类型的实现方法》
    • IvorySQL没实现。

SQL的嵌套表和动态数组

  1. SQL层和PL层使用一套逻辑
  2. SQL层和PL层需要使用两套不同的逻辑
    • 原因1:SQL层的表类型用多维嵌套表需要落盘,且需要当做标准类型放在pg_type中才能最大化利用PG原生逻辑,Oracle的实现是每1个维度都放一张单独的表。
    • 原因2:PL层的多维嵌套表有两种,包SPEC和函数内,无论哪一种都是纯内存结构都无需考虑落盘,且因为作用域差异,不能简单的放在pg_type中,索引应该做套纯内存多维嵌套表结构,逻辑上可参考SQL层的实现(指针数组)

0 人点赞