news 2026/1/20 11:47:33

解析PG兼容mysql框架之整体架构)(以开源项目openHalo为例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
解析PG兼容mysql框架之整体架构)(以开源项目openHalo为例)

pg兼容mysql框架之整体架构

前言: 本文简述了openHalo兼容mysql框架的基本思路和逻辑。

1 整体架构图


图1(源于openhalo官方手册)

2 源码实现

区分mysql和pg的配置参数unvdb_database_mode实现

首先,以GUC参数 unvdb_database_mode 作为PG模式和MySQL模式的区分参数

参数定义: /* GUC variable */ int unvdb_database_mode = UNVDBTX_COMPAT_MODE; guc定义: {"unvdb_database_mode", PGC_UNVDBSVR, CUSTOM_OPTIONS, gettext_noop("Sets the database compat mode."), NULL, GUC_SUPERUSER_ONLY }, &unvdb_database_mode, UNVDBTX_COMPAT_MODE, unvdb_database_mode_options, NULL, NULL, NULL }, static const struct config_enum_entry unvdb_database_mode_options[] = { {"unvdbtx", UNVDBTX_COMPAT_MODE, false}, {"mysql", MYSQL_COMPAT_MODE, false}, {NULL, 0, false} };

以unvdb_database_mode_options[]下标作为unvdb_database_mode 值 (0为pg模式 ,1为Mysql模式)对应枚举类型:

typedef enum { UNVDBTX_COMPAT_MODE, MYSQL_COMPAT_MODE, } DatabaseCompatModeType;

因此,通过上述转换在内核源码中,以UNVDBTX_COMPAT_MODE,MYSQL_COMPAT_MODE 作为区分pg和mysql的最终依据。在每个关键模块入口用此参数走不同的执行逻辑。

3 整体架构实现源码

如图1所示 每个模块都设置了标准化引擎,在init阶段根据上述所说的unvdb_database_mode 配置情况给相关模块的引擎赋于对应模式(pg/mysql)

以下是初始化代码:

src/backend/utils/init/postinit.c 1142: /* set default namespace search path */ InitializeSearchPath(); /* initialize client encoding */ InitializeClientEncoding(); /* Initialize this backend's session state. */ InitializeSession(); /* Initialize Parser Engine */ InitParserEngine(); /* Initialize Planner Engine */ InitPlannerEngine(); /* Initialize Exector Engine */ InitExecutorEngine(); /* Initialize ADT Extension */ InitADTExt(); /* Initialize fmgr extension */ InitFmgrExtension(); /* report this backend in the PgBackendStatus array */ if (!bootstrap) pgstat_bestart();

每个引擎里定义了引擎类型和一些必要的函数指针成员 ,在初始化阶段会根据模式(pg/mysql)给引擎赋值不同的对应成员参数。

引擎结构体(以ParserEngine为例):

typedef struct ParserRoutine { NodeTag type; bool is_standard_parser; bool need_standard_parser; const ScanKeywordList *keywordlist; const uint16 *keyword_tokens; const uint8 *keyword_categories; raw_parser_function raw_parser; transformStmt_function transformStmt; transformSelectStmt_function transformSelectStmt; transformInsertStmt_function transformInsertStmt; transformDeleteStmt_function transformDeleteStmt; transformUpdateStmt_function transformUpdateStmt; transformSetOperationStmt_function transformSetOperationStmt; transformCallStmt_function transformCallStmt; transformOptionalSelectInto_function transformOptionalSelectInto; transformSetOperationTree_function transformSetOperationTree; analyze_requires_snapshot_function analyze_requires_snapshot; parse_sub_analyze_function parse_sub_analyze; transformGroupClause_function transformGroupClause; transformDistinctClause_function transformDistinctClause; transformOnConflictArbiter_function transformOnConflictArbiter; transformExpr_function transformExpr; transformCreateStmt_function transformCreateStmt; transformAlterTableStmt_function transformAlterTableStmt; assign_query_collations_function assign_query_collations; assign_list_collations_function assign_list_collations; assign_expr_collations_function assign_expr_collations; select_common_collation_function select_common_collation; preTransformWindowAgg_fn preTransformWindowAgg; finalTransformColumnRef_fn finalTransformColumnRef; ParseFuncOrColumn_function ParseFuncOrColumn; func_get_detail_function func_get_detail; make_fn_arguments_function make_fn_arguments; RewriteInterface rewrite; } ParserRoutine;

相关引擎初始化代码(以ParserEngine为例):

void InitParserEngine(void) { switch (unvdb_database_mode) { case UNVDBTX_COMPAT_MODE: parserengine = GetStandardParserEngine(); break; case MYSQL_COMPAT_MODE: if ((MyProcPort != NULL) && (nodeTag(MyProcPort->protocol_handler) == T_MySQLProtocol)) { parserengine = GetMysParserEngine(); } else { parserengine = GetStandardParserEngine(); } /* parserengine = GetMysParserEngine(); */ break; default: parserengine = GetStandardParserEngine(); break; } }

假设我们是mysql模式(unvdb模式相同),在初始化函数中 GetMysParserEngine()函数会返回已经赋值了mysql相关函数的引擎,因此在后续的调用中 统一采用 例如:parserengine->keywordlist 方式就可以访问对应模式下的处理函数。

赋值代码:

/* * MySQL Parser Engine */ static const ParserRoutine mys_parser_engine = { .type = T_ParserRoutine, .is_standard_parser = false, .need_standard_parser = true, .keywordlist = &MysScanKeywords, .keyword_tokens = MysScanKeywordTokens, .keyword_categories = MysScanKeywordCategories, .transformStmt = mys_transformStmt, .transformSelectStmt = mys_transformSelectStmt, .transformInsertStmt = mys_transformInsertStmt, .transformUpdateStmt = mys_transformUpdateStmt, .transformDeleteStmt = mys_transformDeleteStmt, .transformCallStmt = mys_transformCallStmt, .transformOptionalSelectInto = mys_transformOptionalSelectInto, .transformSetOperationStmt = mys_transformSetOperationStmt, .transformSetOperationTree = mys_transformSetOperationTree, .analyze_requires_snapshot = mys_analyze_requires_snapshot, .transformOnConflictArbiter = mys_transformOnConflictArbiter, .raw_parser = mys_raw_parser, .transformExpr = mys_transformExpr, .transformGroupClause = mys_transformGroupClause, .transformDistinctClause = mys_transformDistinctClause, .transformCreateStmt = mys_transformCreateStmt, .transformAlterTableStmt = mys_transformAlterTableStmt, .ParseFuncOrColumn = mys_ParseFuncOrColumn, .func_get_detail = mys_func_get_detail, .make_fn_arguments = mys_make_fn_arguments };

4 引擎执行源码解析(以语法解析为例)

当以mysql模式运行时,代码正常执行,进入语法解析阶段。代码如下:

List * raw_parser(const char *str, RawParseMode mode) { List *raw_parsetree = NIL; MemoryContext oldctx = CurrentMemoryContext; if (parserengine == NULL) parserengine = GetStandardParserEngine(); Assert(parserengine != NULL); Assert(parserengine->raw_parser != NULL); PG_TRY(); { raw_parsetree = parserengine->raw_parser(str, mode); } PG_CATCH();

当执行到raw_parsetree = parserengine->raw_parser(str, mode); 片段时,为进入语法解析的入口,此时由于

parserengine 已经被赋值为mysql的引擎,所以调用的函数raw_parser成员,对应的是mys_raw_parser函数。到此正式进入mysql raw_parser 解析逻辑。

其他引擎略有出入,但总体上实现逻辑是一样的。

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

10、CloudForms 4.0 事件处理机制深度解析

CloudForms 4.0 事件处理机制深度解析 1. 事件处理组件 在 CloudForms 4.0 中,事件处理涉及多个新组件,主要包括事件流对象类型、事件总控板(Event Switchboard)和事件处理程序。 1.1 事件流对象 事件现在由 EventStream 对象处理,该对象派生自父类 EventStream 。…

作者头像 李华
网站建设 2025/12/17 11:17:32

14、虚拟机器配置的命名、放置与对话框定制

虚拟机器配置的命名、放置与对话框定制 命名过程输出 在虚拟机配置过程中,命名方法会产生一些关键输出,并将其添加到任务选项哈希中: - vm_target_name :代表新虚拟机的名称,添加到任务选项哈希的方式为 miq_provision.options[:vm_target_name] 。 - vm_target_…

作者头像 李华
网站建设 2026/1/18 3:32:37

21、云服务管理:实例、方法与退休流程详解

云服务管理:实例、方法与退休流程详解 在云服务管理中,为了填充服务对话框的动态元素,需要创建多个实例和方法。下面将详细介绍这些实例和方法的相关内容。 动态对话框 动态对话框的实例和方法定义在 /Integration/Satellite/DynamicDialogs 命名空间下。Methods 类的模…

作者头像 李华
网站建设 2026/1/4 14:44:07

24、云自动化:分布式处理、参数传递与实用技巧

云自动化:分布式处理、参数传递与实用技巧 1. 分布式自动化处理 自动化任务可在多个设备间分配,以在工作负载增加时扩展自动化基础架构。规划部署时,通常每 300 - 500 个托管虚拟机配备一个工作设备,但实际情况因工作负载而异。若自动化任务处理时间超出预期,可监控各工作…

作者头像 李华
网站建设 2025/12/17 11:16:55

GESP认证C++编程真题解析 | B3866 [GESP202309 二级] 数字黑洞

​欢迎大家订阅我的专栏:算法题解:C与Python实现! 本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战! 专栏特色 1.经典算法练习:根据信息学竞赛大纲,精心挑选…

作者头像 李华
网站建设 2026/1/16 2:31:08

【Java毕设全套源码+文档】基于springboot的网购商城管理系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华