暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Postgres源码分析——CREATE CAST

原创 chirpyli 2022-11-07
851

CREATE CAST源码分析

CREATE CAST用法

CREATE CAST —— 定义一个用户自定义的类型转换
用法如下:

CREATE CAST (source_type AS target_type) WITH FUNCTION function_name [ (argument_type [, ...]) ] [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type AS target_type) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type AS target_type) WITH INOUT [ AS ASSIGNMENT | AS IMPLICIT ]

如何使用以及用法请参考PostgreSQL文档中CREATE CAST一节。下面我们主要分析一下其源码,看一下是如何实现的。

源码分析

因为CREATE CAST属于Utility型语句,无需查询优化,其主流程如下:

exec_simple_query --> pg_parse_query // 语法解析 --> pg_analyze_and_rewrite // 语义分析 --> parse_analyze --> pg_rewrite_query --> pg_plan_queries // 生成执行计划 --> PortalStart --> PortalRun // 执行器执行 --> PortalRunMulti --> PortalRunUtility --> ProcessUtility --> standard_ProcessUtility --> ProcessUtilitySlow --> CreateCast // 进入CreateCast处理函数处理CREATE CAST语句 --> PortalDrop

主要的处理逻辑都在CreateCast函数中完成。后续会重点分析一下这个函数。

解析部分

我们首先分析一下其语法解析部分,这部分比较简单,核心是CreateCastStmt的定义,定义如下:

/* ---------------------- * CREATE CAST Statement * ---------------------- */ typedef struct CreateCastStmt { NodeTag type; TypeName *sourcetype; TypeName *targettype; ObjectWithArgs *func; CoercionContext context; bool inout; } CreateCastStmt;

CREATE CAST其在gram.y中定义的表示如下:

/************************************************* * * CREATE CAST / DROP CAST * *************************************************/ CreateCastStmt: CREATE CAST '(' Typename AS Typename ')' WITH FUNCTION function_with_argtypes cast_context { CreateCastStmt *n = makeNode(CreateCastStmt); n->sourcetype = $4; n->targettype = $6; n->func = $10; n->context = (CoercionContext) $11; n->inout = false; $$ = (Node *)n; } | CREATE CAST '(' Typename AS Typename ')' WITHOUT FUNCTION cast_context { CreateCastStmt *n = makeNode(CreateCastStmt); n->sourcetype = $4; n->targettype = $6; n->func = NULL; n->context = (CoercionContext) $10; n->inout = false; $$ = (Node *)n; } | CREATE CAST '(' Typename AS Typename ')' WITH INOUT cast_context { CreateCastStmt *n = makeNode(CreateCastStmt); n->sourcetype = $4; n->targettype = $6; n->func = NULL; n->context = (CoercionContext) $10; n->inout = true; $$ = (Node *)n; } ; cast_context: AS IMPLICIT_P { $$ = COERCION_IMPLICIT; } | AS ASSIGNMENT { $$ = COERCION_ASSIGNMENT; } | /*EMPTY*/ { $$ = COERCION_EXPLICIT; } ; DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_behavior { DropStmt *n = makeNode(DropStmt); n->removeType = OBJECT_CAST; n->objects = list_make1(list_make2($5, $7)); n->behavior = $9; n->missing_ok = $3; n->concurrent = false; $$ = (Node *)n; } ; opt_if_exists: IF_P EXISTS { $$ = true; } | /*EMPTY*/ { $$ = false; } ;

非常容易理解,下面我们重点分析一下CreateCast函数的实现。

执行部分

用户通过CREATE CAST语句自定义一个类型转换,数据库肯定有个地方将这个转换的信息存起来,这个地方就是pg_cast系统表。pg_cast系统表存在数据类型转换路径,包括内建和用户自定义的。

postgres@postgres=# \d pg_cast Table "pg_catalog.pg_cast" Column | Type | Collation | Nullable | Default -------------+--------+-----------+----------+--------- oid | oid | | not null | castsource | oid | | not null | -- 源数据类型的OID casttarget | oid | | not null | -- 目标数据类型的OID castfunc | oid | | not null | -- 执行该转换的函数的OID。如果该转换方法不需要一个函数则存储0。 castcontext | "char" | | not null | -- 指示该转换能被调用的环境 castmethod | "char" | | not null | -- 指示转换如何被执行。 Indexes: "pg_cast_oid_index" UNIQUE, btree (oid) "pg_cast_source_target_index" UNIQUE, btree (castsource, casttarget)

CreateCast函数的主要内容就是将用户自定义的类型转换信息插入到pg_cast系统表中。

CreateCast --> LookupFuncWithArgs // 查到pg_proc系统表,看是否已存在 --> LookupFuncNameInternal --> FuncnameGetCandidates --> IsBinaryCoercible(Oid srctype, Oid targettype) //Check if srctype is binary-coercible to targettype. --> CastCreate // 将类型转换信息插入pg_cast系统表中
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论