ITPub博客

首页 > 数据库 > PostgreSQL > PostgreSQL 源码解读(210)- 隐式类型转换(func_match_argtypes)

PostgreSQL 源码解读(210)- 隐式类型转换(func_match_argtypes)

原创 PostgreSQL 作者:husthxd 时间:2019-07-16 16:03:02 0 删除 编辑

本节简单介绍了PostgreSQL隐式类型转换中使用哪些操作符(pg_operator)的实现函数func_match_argtypes.

一、数据结构

FuncCandidateList
该结构体存储检索得到的所有可能选中的函数或操作符链表.


/*
 *  This structure holds a list of possible functions or operators
 *  found by namespace lookup.  Each function/operator is identified
 *  by OID and by argument types; the list must be pruned by type
 *  resolution rules that are embodied in the parser, not here.
 *  See FuncnameGetCandidates's comments for more info.
 *  该结构体存储检索得到的所有可能选中的函数或操作符链表.
 *  每一个函数/操作符通过OID和参数类型唯一确定,
 *  通过集成到分析器中的type resolution rules来确定裁剪该链表(但不是在这里实现)
 *  详细可参考FuncnameGetCandidates函数.
 */
typedef struct _FuncCandidateList
{
    struct _FuncCandidateList *next;
    //用于namespace检索内部使用
    int         pathpos;        /* for internal use of namespace lookup */
    //OID
    Oid         oid;            /* the function or operator's OID */
    //参数个数 
    int         nargs;          /* number of arg types returned */
    //variadic array的参数个数
    int         nvargs;         /* number of args to become variadic array */
    //默认参数个数
    int         ndargs;         /* number of defaulted args */
    //参数位置索引
    int        *argnumbers;     /* args' positional indexes, if named call */
    //参数类型
    Oid         args[FLEXIBLE_ARRAY_MEMBER];    /* arg types */
}          *FuncCandidateList;

二、源码解读

func_match_argtypes
给定候选函数列表(正确的函数名称/参数个数匹配)和输入数据类型OIDs数组,生成实际可匹配输入数据类型(完全匹配或可转换)的候选函数链表,然后符合条件的候选函数个数.


/* func_match_argtypes()
 *
 * Given a list of candidate functions (having the right name and number
 * of arguments) and an array of input datatype OIDs, produce a shortlist of
 * those candidates that actually accept the input datatypes (either exactly
 * or by coercion), and return the number of such candidates.
 * 给定候选函数列表(正确的函数名称/参数个数匹配)和输入数据类型OIDs数组,
 * 生成实际可匹配输入数据类型(完全匹配或可转换)的候选函数链表,然后符合条件的候选函数个数
 *
 * Note that can_coerce_type will assume that UNKNOWN inputs are coercible to
 * anything, so candidates will not be eliminated on that basis.
 * can_coerce_type函数假定UNKNOWN输入可转换为任意类型.
 *
 * NB: okay to modify input list structure, as long as we find at least
 * one match.  If no match at all, the list must remain unmodified.
 * 注意:如果只是找到一个匹配的候选函数,修改输入链表结构是OK的.如无匹配,则链表保持不变.
 */
int
func_match_argtypes(int nargs,
                    Oid *input_typeids,
                    FuncCandidateList raw_candidates,
                    FuncCandidateList *candidates)  /* return value */
{
    FuncCandidateList current_candidate;//当前候选
    FuncCandidateList next_candidate;//下一候选
    int         ncandidates = 0;
    *candidates = NULL;
    for (current_candidate = raw_candidates;
         current_candidate != NULL;
         current_candidate = next_candidate)//遍历候选函数
    {
        next_candidate = current_candidate->next;
        if (can_coerce_type(nargs, input_typeids, current_candidate->args,
                            COERCION_IMPLICIT))//可匹配输入数据类型(完全匹配或可转换)
        {
            current_candidate->next = *candidates;
            *candidates = current_candidate;
            ncandidates++;
        }
    }
    return ncandidates;
}                               /* func_match_argtypes() */

在pg_operator中,输入参数类型与operator的参数类型匹配或可转换,可进入候选函数链表.

三、跟踪分析

测试脚本


create cast(integer as text) with inout as implicit;
select id||'X' from t_cast;

跟踪分析


(gdb) c
Continuing.
Breakpoint 2, oper_select_candidate (nargs=2, input_typeids=0x7ffeb9cca190, candidates=0x13db8a0, operOid=0x7ffeb9cca22c)
    at parse_oper.c:330
330     ncandidates = func_match_argtypes(nargs, input_typeids,
(gdb) p *candidates
$1 = {next = 0x13db870, pathpos = 0, oid = 3284, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db8c8}
(gdb) p *candidates->next
$2 = {next = 0x13db840, pathpos = 0, oid = 3681, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db898}
(gdb) p *candidates->next->next
$3 = {next = 0x13db810, pathpos = 0, oid = 3633, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db868}
(gdb) p *candidates->next->next->next
$4 = {next = 0x13db7e0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db838}
(gdb) p *candidates->next->next->next->next
$5 = {next = 0x13db7b0, pathpos = 0, oid = 374, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db808}
(gdb) p *candidates->next->next->next->next->next
$6 = {next = 0x13db780, pathpos = 0, oid = 349, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db7d8}
(gdb) p *candidates->next->next->next->next->next->next
$7 = {next = 0x13db750, pathpos = 0, oid = 375, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db7a8}
(gdb) p *candidates->next->next->next->next->next->next->next
$8 = {next = 0x13db720, pathpos = 0, oid = 1797, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db778}
(gdb) p *candidates->next->next->next->next->next->next->next->next
$9 = {next = 0x13db6f0, pathpos = 0, oid = 2779, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db748}
(gdb) p *candidates->next->next->next->next->next->next->next->next->next
$10 = {next = 0x13db6c0, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db718}
(gdb) p *candidates->next->next->next->next->next->next->next->next->next->next
$11 = {next = 0x0, pathpos = 0, oid = 2018, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db6e8}
(gdb) p *candidates->next->next->next->next->next->next->next->next->next->next->next
Cannot access memory at address 0x0
(gdb) n
334     if (ncandidates == 0)
(gdb) 
339     if (ncandidates == 1)
(gdb) 
349     candidates = func_select_candidate(nargs, input_typeids, candidates);
(gdb) p ncandidates
$12 = 2
(gdb) p *candidates
$13 = {next = 0x13db810, pathpos = 0, oid = 374, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db808}
(gdb) p *candidates->next
$14 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x13db838}
(gdb) p *candidates->next->next
Cannot access memory at address 0x0
(gdb)

DONE!

四、参考资料

PostgreSQL Type Conversion

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2650700/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
ITPUB数据库版块资深版主,对Oracle、PostgreSQL有深入研究。现就职于广州云图数据技术有限公司,系统架构师。

注册时间:2007-12-28

  • 博文量
    1339
  • 访问量
    3805187