本节简单介绍了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的.如无匹配,则链表保持不变. */intfunc_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) cContinuing.Breakpoint 2, oper_select_candidate (nargs=2, input_typeids=0x7ffeb9cca190, candidates=0x13db8a0, operOid=0x7ffeb9cca22c) at parse_oper.c:330330 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->nextCannot access memory at address 0x0(gdb) n334 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->nextCannot access memory at address 0x0(gdb)
DONE! 郑州×××医院×××:http://myyk.familydoctor.com.cn/yiyuanzaixian/zztjyy//