写点什么

开发 postgreSQL connector 支持 update/delete 操作的代码

作者:openLooKeng
  • 2022 年 1 月 28 日
  • 本文字数:2557 字

    阅读完需:约 8 分钟

背景与需求

当前 openLooKeng postgreSQL connector 不支持对数据表的 update 和 delete 操作,本文拟在 openLooKeng 框架的基础上,开发 postgreSQL connector 支持 update/delete 操作的代码。

分析

openLooKeng 语句执行流程:


一条 SQL 语句的执行的整体流程如下图所示:



这里面主要涉及到两种类型的节点,分别为 Coordinator 和 Worker 节点。


  • Coordinator 节点是用来解析语句,执行计划分析和管理 openLooKeng 的 Worker 节点,同时 Coordinator 跟踪每个 Work 的活动情况并协调查询语句的执行。Coordinator 为每个查询建立模型,模型包含多个 Stage,每个 Stage 再转为 Task 分发到不同的 Worker 上执行。

  • Worker 是负责执行任务和处理数据。Worker 从 Connector 获取数据。Worker 之间会交换中间数据。Coordinator 是负责从 Worker 获取结果并返回最终结果给 Client。


具体步骤为:


  1. 客户端通过协议发送一条查询语句给 openLooKeng 集群的 Coordinator;

  2. Coordinator 接手到客户端传送到的查询语句,对语句进行解析、生成查询执行计划,根据查询执行计划一次生成 sqlQueryExecution->sqlStageExecution->HttpRemoteTask;

  3. Coordinator 将每个 task 分发到所需要处理的数据所在的 Worker 节点上执行;

  4. Task 通过 Connector 从数据源中读取数据,并执行 Source Stage 的 task;

  5. 处于下游的 Stage 中的 task 会读取上游 Stage 产生的输出结果,并在该 Stage 的每个 task 所处的 Worker 的内存中进行后续处理;

  6. Coordinator 从发布的 task 后,持续地从 Singe Stage 中的 task 获取结果,并将结果缓存到 buffer 中,知道查询结束;

  7. Client 从提交查询之后,会持续地从 Coordinator 获取本次查询的计算结果,知道获得所有的计算结果。

openLooKeng 内核调用

openLooKeng 的多源查询能力是通过 Connector 机制来实现的。其中 MySQL、postgreSQL 等 Connector 是主要是通过 presto-base-jdbc 中的代码来实现对 SQL 等数据源的读写。



其中 openLooKeng-spi 中主要定义了一些公共接口,供 openLooKeng-main 中的代码进行调用。


openLooKeng-base-jdbc 是数据库连接器的公共模块,对 openLooKeng-main 进行了实现和补充。其代码经过编译后,会对应加载到 mysql-plugin 等插件中,实现 mysql 对数据源的访问功能。base-jdbc 本身自己不会编译单独的插件。


通过断点调试,对 openLooKeng 接受一条 update SQL 语句的函数栈调用流程进行梳理总结,如下图所示。



结合源码分析,发现一条 update 语句在 connector jdbc 中的执行流程为 beginUpdate()->getConnection()->buildUpdateSql()->setUpdateSql()->finishUpdate()。在这个过程中需要一个字段作为行标识符来表示数据行。


其中 buildUpdateSql 将 openLooKeng 传入的 update SQL 语句转换为 connector 更新时的预编译语句,这里用到获取的行标识符作为 where 的筛选条件;setUpdateSql 作用是以 where 条件对数据行进行更新。


因此若想要实现 postgreSQL conncetor 的 update/delete table 功能,我们需要重写上述函数即可完成。

代码实现

方案设计及论证

通过前期的调研,共形成了以主键为标识符和以 ctid 字段为标识符的两种开发方案。


方案一:以主键为标识符


主键的定义为:表中经常有一个列或列的组合,其值能唯一地标识表中的每一行。由定义可知,主键对应到一张数据表中会设计到多种场景,分别为:没有主键、单字段主键以及多字段组合成的复合主键,因此需要考虑的情况较多。


方案二:以 ctid 字段为标识符


ctid 表示数据行在它所处的表内的物理位置,ctid 字段的类型是 tid。尽管 ctid 可以快速定位数据行,每次 vacuum full 之后,数据行在块内的物理位置就会移动,即 ctid 会发生变化,所以 ctid 不能作为长期的行标识符。因此如果要以 ctid 字段为标识符进行代码开发,需首先验证 ctid 在同一事务中进行 update/delete 操作是否会发生变化。


ctid 在同一事务中的变化情况


为了验证 ctid 字段能否用于 postgreSQL 的 update/delete 操作,我们分别在单线程和多线程的情况下去验证 ctid 在同一事务和不同事务的变化情况。


单线程


通过 jdbc 模拟了单线程,在线程中对数据表进行 update 操作,分别查询 update 前后的信息,观察 ctid 的变化情况。



autocommit=false 时,结果显示 ctid 未发生变化:



autocommit=true 时,结果显示 ctid 发生变化:



多线程


同理,通过 jdbc 模拟了两个线程,在两个线程中分别对数据表进行 update 操作,分别查询 update 前后的信息,观察 ctid 的变化情况。


autocommit=false 时,结果显示 ctid 未发生变化:



autocommit=true 时,结果显示 ctid 发生变化:



由验证实验结果来看,在同一事务中,update 未提交前或者回滚之后 ctid 是不变的。

开发方案选择

综合对比两种方案,其优缺点对比如下:



ctid 字段为行标识符的代码开发


autocommit 设置为 false,即保证能在同一事务中进行操作,ctid 是可以保证唯一性的。而 PostgreSql 的继承关系为



因此我们的主要开发重点在于重写 beginUpdate()-> getConnection()-> buildUpdateSql-> setUpdateSql ->finishUpdate()getUpdateRowIdColumnHandle() 用于获取行标识符



beginUpdate()



getConnection 重写 BaseJdbcClient 该方法,用于将只读模式设为 false,以便于进行更新操作



buildUpdateSql 将 openLooKeng 传入的 update SQL 语句转换为 oracle 更新时的预编译语句,其内部调用关系为


buildUpdateSql()buildRemoteSchemaTableName()getColumnNameFromDataSource()getColumnNameMap()
复制代码


其中 buildRemoteSchemaTableName()获取数据表名,getColumnNameFromDataSource()用于从源数据中获取要更新的字段名,getColumnNameMap()用于构建字段名的映射关系,将原始字段统一转换为小写字母。具体实现如下图所示:



setUpdateSql 是以 where 条件对数据行进行更新,其内部调用关系为


setUpdateSql()setStatement()
复制代码


其中 setStatement()用于对需要更新的字段根据数据类型进行赋值。具体实现如下图所示:



到此,我们完成了 postgreSQL connector 的 update 功能代码,而 delete 功能代码与此具有很大的相似性,此处不做展开讲述,具体可参考PostgreSqlClient实现

功能展示

此处我们简单演示 postgreSQL connector 的 update/delete 特性。首先需对代码进行编译,运行 mvn clean install -DskipTests -T 1C 即可,编译完成之后,拷贝 hetu-server-1.5.0-SNAPSHOT 文件夹及 hetu-cli-1.50-SNAPSHOT-executable.jar 包。紧接着相关配置可参考社区文档。


在 web 界面输入 ip 及端口号,显示



数据表已经建好,具体实例为



针对 update,执行语句及结果包括



功能点 SQL 结果




发布于: 刚刚阅读数: 2
用户头像

openLooKeng

关注

愿景:让大数据更简单 2021.04.14 加入

openLooKeng是一款高效的数据虚拟化引擎,提供统一SQL接口,具备跨数据源/数据中心分析能力,致力于为用户提供极简的数据分析体验。社区官网:https://openlookeng.io

评论

发布
暂无评论
开发postgreSQL connector支持update/delete操作的代码