ITPub博客

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

PostgreSQL 源码解读(209)- 隐式类型转换(func_select_candidate)

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

本节简单介绍了PostgreSQL隐式类型转换中选择操作符(pg_operator)的实现函数func_select_candidate.

一、数据结构

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_select_candidate
处理逻辑与PG文档中的类型转换规则一样,其规则详见参考资料中的Operator部分.


/*
create table t_tmp(c1 int,c2 int);
insert into t_tmp values(1,1);
create cast(integer as text) with inout as implicit;
testdb=# select c1||'-'||c2 from t_tmp;
psql: ERROR:  operator is not unique: integer || unknown
LINE 1: select c1||'-'||c2 from t_tmp;
                 ^
HINT:  Could not choose a best candidate operator. You might need to add explicit type casts.
*/
/* func_select_candidate()
 *      Given the input argtype array and more than one candidate
 *      for the function, attempt to resolve the conflict.
 *      给定参数类型和多于1个的候选函数,尝试解决冲突选中合适的函数.
 *
 * Returns the selected candidate if the conflict can be resolved,
 * otherwise returns NULL.
 * 如冲突解决,则返回选中的函数,否则返回NULL.
 *
 * Note that the caller has already determined that there is no candidate
 * exactly matching the input argtypes, and has pruned away any "candidates"
 * that aren't actually coercion-compatible with the input types.
 * 注意 : 调用者已确定没有那个函数完全满足输入的参数类型,
 *        已清除了所有与输入参数类型不兼容的函数.
 *
 * This is also used for resolving ambiguous operator references.  Formerly
 * parse_oper.c had its own, essentially duplicate code for the purpose.
 * The following comments (formerly in parse_oper.c) are kept to record some
 * of the history of these heuristics.
 * 本例程同时用于解决模糊操作符引用.以前parse_oper.c有自己的代码,本质上是重复的代码.
 * 接下来的注释(先前在parse_oper.c中)保留用于记录这些启发式的历史.
 *
 * OLD COMMENTS:
 *
 * This routine is new code, replacing binary_oper_select_candidate()
 * which dates from v4.2/v1.0.x days. It tries very hard to match up
 * operators with types, including allowing type coercions if necessary.
 * The important thing is that the code do as much as possible,
 * while _never_ doing the wrong thing, where "the wrong thing" would
 * be returning an operator when other better choices are available,
 * or returning an operator which is a non-intuitive possibility.
 * - thomas 1998-05-21
 * 本例程努力的通过类型与operators进行匹配,包括在需要时允许类型强制转换.
 *
 * The comments below came from binary_oper_select_candidate(), and
 * illustrate the issues and choices which are possible:
 * - thomas 1998-05-20
 *
 * current wisdom holds that the default operator should be one in which
 * both operands have the same type (there will only be one such
 * operator)
 * 当前我们认为 : 默认操作符应该是两个操作数具有相同类型的操作符(只有一个这样的操作符).
 *
 * 7.27.93 - I have decided not to do this; it's too hard to justify, and
 * it's easy enough to typecast explicitly - avi
 * [the rest of this routine was commented out since then - ay]
 *
 * 6/23/95 - I don't complete agree with avi. In particular, casting
 * floats is a pain for users. Whatever the rationale behind not doing
 * this is, I need the following special case to work.
 *
 * In the WHERE clause of a query, if a float is specified without
 * quotes, we treat it as float8. I added the float48* operators so
 * that we can operate on float4 and float8. But now we have more than
 * one matching operator if the right arg is unknown (eg. float
 * specified with quotes). This break some stuff in the regression
 * test where there are floats in quotes not properly casted. Below is
 * the solution. In addition to requiring the operator operates on the
 * same type for both operands [as in the code Avi originally
 * commented out], we also require that the operators be equivalent in
 * some sense. (see equivalentOpersAfterPromotion for details.)
 * - ay 6/95
 * 在WHERE语句中,如果float不带引号,PG会把该值视为float8类型.
 * 添加了float48*操作符的目的是可以处理float4和float8两种类型.
 * 但如果右操作数的类型是unknown(如带有引号的浮点数)的话,会有超过一个匹配的operator存在.
 * 这会导致回归测试中出现浮点数使用引号引住而没有被正确转换的情况而失败.
 * 除了要求操作符在同样类型的操作数外,还要求操作符在某些场景是等价的.
 */
FuncCandidateList
func_select_candidate(int nargs,
                      Oid *input_typeids,
                      FuncCandidateList candidates)
{
    FuncCandidateList current_candidate,
                first_candidate,
                last_candidate;
    Oid        *current_typeids;
    Oid         current_type;
    int         i;
    int         ncandidates;
    int         nbestMatch,
                nmatch,
                nunknowns;
    Oid         input_base_typeids[FUNC_MAX_ARGS];
    TYPCATEGORY slot_category[FUNC_MAX_ARGS],
                current_category;
    bool        current_is_preferred;
    bool        slot_has_preferred_type[FUNC_MAX_ARGS];
    bool        resolved_unknowns;
    /* protect local fixed-size arrays */
    //校验
    if (nargs > FUNC_MAX_ARGS)
        ereport(ERROR,
                (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
                 errmsg_plural("cannot pass more than %d argument to a function",
                               "cannot pass more than %d arguments to a function",
                               FUNC_MAX_ARGS,
                               FUNC_MAX_ARGS)));
    /*
     * If any input types are domains, reduce them to their base types. This
     * ensures that we will consider functions on the base type to be "exact
     * matches" in the exact-match heuristic; it also makes it possible to do
     * something useful with the type-category heuristics. Note that this
     * makes it difficult, but not impossible, to use functions declared to
     * take a domain as an input datatype.  Such a function will be selected
     * over the base-type function only if it is an exact match at all
     * argument positions, and so was already chosen by our caller.
     *
     * While we're at it, count the number of unknown-type arguments for use
     * later.
     * 计算unknown类型的参数个数
     */
    /*
    If any input argument is of a domain type, treat it as being of the domain's 
    base type for all subsequent steps. This ensures that domains act like their 
    base types for purposes of ambiguous-operator resolution.
    */
    nunknowns = 0;
    for (i = 0; i < nargs; i++)
    {
        if (input_typeids[i] != UNKNOWNOID)
            input_base_typeids[i] = getBaseType(input_typeids[i]);//基本类型
        else
        {
            //unknown 类型
            /* no need to call getBaseType on UNKNOWNOID */
            input_base_typeids[i] = UNKNOWNOID;
            nunknowns++;
        }
    }
    /*
     * Run through all candidates and keep those with the most matches on
     * exact types. Keep all candidates if none match.
     * 遍历所有候选,保留那些类型一致的那些.如无匹配的,保留所有候选.
     */
    /*
    Run through all candidates and keep those with the most exact matches on input types.
    Keep all candidates if none have exact matches. If only one candidate remains, use it; 
    else continue to the next step.
    */
    ncandidates = 0;//候选数
    nbestMatch = 0;//最佳匹配数
    last_candidate = NULL;//最后一个候选
    for (current_candidate = candidates;
         current_candidate != NULL;
         current_candidate = current_candidate->next)//遍历
    {
        //获取候选函数的参数
        current_typeids = current_candidate->args;
        nmatch = 0;
        for (i = 0; i < nargs; i++)
        {
            //计算参数匹配个数
            if (input_base_typeids[i] != UNKNOWNOID &&
                current_typeids[i] == input_base_typeids[i])
                nmatch++;
        }
        /* take this one as the best choice so far? */
        //就拿这个作为最好的选择?
        if ((nmatch > nbestMatch) || (last_candidate == NULL))
        {
            //1.比最佳参数匹配个数要大,调整最佳匹配数(参数个数)
            //2.last_candidate == NULL,第一次循环
            nbestMatch = nmatch;
            candidates = current_candidate;
            last_candidate = current_candidate;
            ncandidates = 1;
        }
        /* no worse than the last choice, so keep this one too? */
        //不会比最后一个选项更糟,所以也保留这个选项
        else if (nmatch == nbestMatch)
        {
            //放到链表中
            last_candidate->next = current_candidate;
            last_candidate = current_candidate;
            ncandidates++;
        }
        /* otherwise, don't bother keeping this one... */
        //否则,无需保留
    }
    if (last_candidate)         /* terminate rebuilt list */
        last_candidate->next = NULL;
    if (ncandidates == 1)//只有一个候选,返回
        return candidates;
    /*
     * Still too many candidates? Now look for candidates which have either
     * exact matches or preferred types at the args that will require
     * coercion. (Restriction added in 7.4: preferred type must be of same
     * category as input type; give no preference to cross-category
     * conversions to preferred types.)  Keep all candidates if none match.
     * 仍有太多的候选?
     * 检索args精确匹配或强制类型转换后有首选类型的候选项.
     * (首选类型必须与输入类型是相同的目录).
     * 如无匹配,保留所有候选.
     */
    /*
    Run through all candidates and keep those that accept preferred types 
    (of the input data type's type category) at the most positions where type 
    conversion will be required. Keep all candidates if none accept preferred types. 
    If only one candidate remains, use it; else continue to the next step.
    */
    for (i = 0; i < nargs; i++) /* avoid multiple lookups */
        slot_category[i] = TypeCategory(input_base_typeids[i]);//获取类型目录
    ncandidates = 0;
    nbestMatch = 0;
    last_candidate = NULL;
    for (current_candidate = candidates;
         current_candidate != NULL;
         current_candidate = current_candidate->next)//遍历
    {
        current_typeids = current_candidate->args;//参数
        nmatch = 0;
        for (i = 0; i < nargs; i++)
        {
            if (input_base_typeids[i] != UNKNOWNOID)
            {
                if (current_typeids[i] == input_base_typeids[i] ||
                    IsPreferredType(slot_category[i], current_typeids[i]))
                    nmatch++;//不要求精确匹配,存在首选项一样的参数也可以了
            }
        }
        if ((nmatch > nbestMatch) || (last_candidate == NULL))
        {
            //1.比最佳参数匹配个数要大,调整最佳匹配数(参数个数)
            //2.last_candidate == NULL,第一次循环
            nbestMatch = nmatch;
            candidates = current_candidate;
            last_candidate = current_candidate;
            ncandidates = 1;
        }
        else if (nmatch == nbestMatch)
        {
            //保留跟最佳匹配一样的候选
            last_candidate->next = current_candidate;
            last_candidate = current_candidate;
            ncandidates++;
        }
    }
    if (last_candidate)         /* terminate rebuilt list */
        last_candidate->next = NULL;
    if (ncandidates == 1)
        return candidates;//
    /*
     * Still too many candidates?  Try assigning types for the unknown inputs.
     * 仍有过多的候选?尝试为unknown类型赋值
     *
     * If there are no unknown inputs, we have no more heuristics that apply,
     * and must fail.
     * 如无unknown类型,没有更多的启发式可用,就此失败
     */
    if (nunknowns == 0)//失败
        return NULL;            /* failed to select a best candidate */
    /*
     * The next step examines each unknown argument position to see if we can
     * determine a "type category" for it.  If any candidate has an input
     * datatype of STRING category, use STRING category (this bias towards
     * STRING is appropriate since unknown-type literals look like strings).
     * Otherwise, if all the candidates agree on the type category of this
     * argument position, use that category.  Otherwise, fail because we
     * cannot determine a category.
     * 下一步,检查每一个unknown类型的参数位置来确定是否可以找到该参数的类型目录.
     * 如果候选存在STRING目录的输入数据类型,使用STRING目录(因为unknown literals看起来像是string)
     * 否则,如果所有候选认同该参数位置上的类型目录,则使用此目录.
     * 不能确定目录,则失败.
     *
     * If we are able to determine a type category, also notice whether any of
     * the candidates takes a preferred datatype within the category.
     * 如果可以确定类型目录,还要注意候选项中是否有一个在目录中采用首选数据类型.
     *
     * Having completed this examination, remove candidates that accept the
     * wrong category at any unknown position.  Also, if at least one
     * candidate accepted a preferred type at a position, remove candidates
     * that accept non-preferred types.  If just one candidate remains, return
     * that one.  However, if this rule turns out to reject all candidates,
     * keep them all instead.
     * 完成该检查后,去掉在unknown位置上接受错误目录的候选.
     * 同时,如果至少有一个候选接受该位置上的首选类型,去掉无首选类型的候选.
     * 如果只有一个候选保留,则返回该候选.
     * 否则,拒绝所有的候选,保留所有.
     */
    /*
    If any input arguments are unknown, check the type categories accepted at 
    those argument positions by the remaining candidates. At each position, 
    select the string category if any candidate accepts that category. 
    (This bias towards string is appropriate since an unknown-type literal looks like a string.) 
    Otherwise, if all the remaining candidates accept the same type category, 
    select that category; otherwise fail because the correct choice cannot be 
    deduced without more clues. Now discard candidates that do not accept the 
    selected type category. Furthermore, if any candidate accepts a preferred 
    type in that category, discard candidates that accept non-preferred types 
    for that argument. Keep all candidates if none survive these tests. 
    If only one candidate remains, use it; else continue to the next step.
    */
    resolved_unknowns = false;//是否已解决unknown类型标记
    for (i = 0; i < nargs; i++)//遍历参数
    {
        bool        have_conflict;//是否存在冲突标记
        if (input_base_typeids[i] != UNKNOWNOID)
            continue;//非unknown类型
        resolved_unknowns = true;   /* 假定可以搞掂 assume we can do it */
        slot_category[i] = TYPCATEGORY_INVALID;
        slot_has_preferred_type[i] = false;
        have_conflict = false;
        for (current_candidate = candidates;
             current_candidate != NULL;
             current_candidate = current_candidate->next)//遍历所有候选
        {
            current_typeids = current_candidate->args;
            current_type = current_typeids[i];
            get_type_category_preferred(current_type,
                                        &current_category,
                                        &current_is_preferred);
            if (slot_category[i] == TYPCATEGORY_INVALID)
            {
                /* first candidate */
                //第一个候选
                slot_category[i] = current_category;
                slot_has_preferred_type[i] = current_is_preferred;
            }
            else if (current_category == slot_category[i])
            {
                /* more candidates in same category */
                //同样的目录有更多的候选
                slot_has_preferred_type[i] |= current_is_preferred;
            }
            else
            {
                /* category conflict! */
                //目录冲突
                if (current_category == TYPCATEGORY_STRING)
                {
                    /* STRING always wins if available */
                    //如可能,首选STRING
                    slot_category[i] = current_category;
                    slot_has_preferred_type[i] = current_is_preferred;
                }
                else
                {
                    /*
                     * Remember conflict, but keep going (might find STRING)
                     * 存在冲突,但继续处理
                     */
                    have_conflict = true;
                }
            }
        }
        if (have_conflict && slot_category[i] != TYPCATEGORY_STRING)
        {
            //存在冲突,并且目录不是STRING
            /* Failed to resolve category conflict at this position */
            //无法解决冲突
            resolved_unknowns = false;
            break;
        }
    }
    if (resolved_unknowns)
    {
        //已解决了冲突
        /* Strip non-matching candidates */
        ncandidates = 0;
        first_candidate = candidates;
        last_candidate = NULL;
        for (current_candidate = candidates;
             current_candidate != NULL;
             current_candidate = current_candidate->next)//再次遍历
        {
            bool        keepit = true;
            //如果至少有一个候选接受该位置上的首选类型,去掉无首选类型的候选.
            current_typeids = current_candidate->args;
            for (i = 0; i < nargs; i++)//遍历参数
            {
                if (input_base_typeids[i] != UNKNOWNOID)
                    continue;//非unknown参数,跳过
                current_type = current_typeids[i];//当前类型
                get_type_category_preferred(current_type,
                                            &current_category,
                                            &current_is_preferred);//首选类型
                if (current_category != slot_category[i])
                {
                    //当前目录不等于slot中的目录,退出参数循环
                    keepit = false;
                    break;
                }
                if (slot_has_preferred_type[i] && !current_is_preferred)
                {
                    //存在首选类型但当前首选类型为NULL,退出参数循环
                    keepit = false;
                    break;
                }
            }
            if (keepit)
            {
                /* keep this candidate */
                //保留该候选
                last_candidate = current_candidate;
                ncandidates++;
            }
            else
            {
                /* forget this candidate */
                //
                if (last_candidate)
                    last_candidate->next = current_candidate->next;
                else
                    first_candidate = current_candidate->next;
            }
        }
        /* if we found any matches, restrict our attention to those */
        if (last_candidate)
        {
            candidates = first_candidate;
            /* terminate rebuilt list */
            last_candidate->next = NULL;
        }
        if (ncandidates == 1)
            return candidates;
    }
    /*
     * Last gasp: if there are both known- and unknown-type inputs, and all
     * the known types are the same, assume the unknown inputs are also that
     * type, and see if that gives us a unique match.  If so, use that match.
     * 最后 : 如果存在known和unknown类型同时存在,
     *        并且已知类型是一样的,那么假定unknown输入也是该类型,然后看看是否有唯一匹配,如有则使用该候选.
     *
     * NOTE: for a binary operator with one unknown and one non-unknown input,
     * we already tried this heuristic in binary_oper_exact().  However, that
     * code only finds exact matches, whereas here we will handle matches that
     * involve coercion, polymorphic type resolution, etc.
     * 注意 : 对于带有一个unknown和一个已知类型参数的二元操作符,
     * 已在binary_oper_exact()函数中使用该启发式.
     * 但是,那些代码只能发现准确的匹配,而这里我们将处理涉及强制、多态类型解析等的匹配。
     */
    /*
    If there are both unknown and known-type arguments, and all the known-type arguments 
    have the same type, assume that the unknown arguments are also of that type, and check 
    which candidates can accept that type at the unknown-argument positions. 
    If exactly one candidate passes this test, use it. Otherwise, fail.
    */
    if (nunknowns < nargs)
    {
        Oid         known_type = UNKNOWNOID;
        for (i = 0; i < nargs; i++)//找到基本类型,找不到则失败
        {
            if (input_base_typeids[i] == UNKNOWNOID)
                continue;
            if (known_type == UNKNOWNOID)   /* first known arg? */
                known_type = input_base_typeids[i];
            else if (known_type != input_base_typeids[i])
            {
                /* oops, not all match */
                known_type = UNKNOWNOID;
                break;
            }
        }
        if (known_type != UNKNOWNOID)//找到了基本类型
        {
            /* okay, just one known type, apply the heuristic */
            for (i = 0; i < nargs; i++)
                input_base_typeids[i] = known_type;//使用该基本类型
            ncandidates = 0;
            last_candidate = NULL;
            for (current_candidate = candidates;
                 current_candidate != NULL;
                 current_candidate = current_candidate->next)//遍历
            {
                current_typeids = current_candidate->args;
                if (can_coerce_type(nargs, input_base_typeids, current_typeids,
                                    COERCION_IMPLICIT))
                {
                    if (++ncandidates > 1)
                        break;  /* not unique, give up */
                    last_candidate = current_candidate;
                }
            }
            if (ncandidates == 1)
            {
                /* successfully identified a unique match */
                //成功!
                last_candidate->next = NULL;
                return last_candidate;
            }
        }
    }
    //返回NULL
    return NULL;                /* failed to select a best candidate */
}                               /* func_select_candidate() */

三、跟踪分析

测试脚本


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

跟踪分析


Breakpoint 1, func_select_candidate (nargs=2, input_typeids=0x7fff5f3ac6c0, candidates=0x2daa6f0) at parse_func.c:1021
1021        if (nargs > FUNC_MAX_ARGS)
(gdb) p *input_typeids
$6 = 23
(gdb) p *candidates
$7 = {next = 0x2daa720, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb)  p *candidates->next
$8 = {next = 0x2daa7e0, pathpos = 0, oid = 2779, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa748}
(gdb) p *candidates->next->next
$9 = {next = 0x2daa810, pathpos = 0, oid = 374, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa808}
(gdb) p *candidates->next->next->next
$10 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa838}
(gdb) p *candidates->next->next->next->next
Cannot access memory at address 0x0
(gdb) n
1042        nunknowns = 0;
(gdb) 
1043        for (i = 0; i < nargs; i++)
(gdb) 
1045            if (input_typeids[i] != UNKNOWNOID)
(gdb) 
1046                input_base_typeids[i] = getBaseType(input_typeids[i]);
(gdb) 
1043        for (i = 0; i < nargs; i++)
(gdb) p input_base_typeids[0]
$12 = 23
(gdb) n
1045            if (input_typeids[i] != UNKNOWNOID)
(gdb) 
1050                input_base_typeids[i] = UNKNOWNOID;
(gdb) p input_typeids[i]
$13 = 705
(gdb) p UNKNOWNOID
$14 = 705
(gdb) n
1051                nunknowns++;
(gdb) 
1043        for (i = 0; i < nargs; i++)
(gdb) 
1059        ncandidates = 0;
(gdb) 
1060        nbestMatch = 0;
(gdb) 
1061        last_candidate = NULL;
(gdb) 
1062        for (current_candidate = candidates;
(gdb) 
1066            current_typeids = current_candidate->args;
(gdb) 
1067            nmatch = 0;
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1071                    current_typeids[i] == input_base_typeids[i])
(gdb) p current_typeids[i]
$15 = 25
(gdb) p input_base_typeids[i]
$16 = 23
(gdb) n
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1076            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1078                nbestMatch = nmatch;
(gdb) 
1079                candidates = current_candidate;
(gdb) 
1080                last_candidate = current_candidate;
(gdb) 
1081                ncandidates = 1;
(gdb) 
1064             current_candidate = current_candidate->next)
(gdb) 
1062        for (current_candidate = candidates;
(gdb) 
1066            current_typeids = current_candidate->args;
(gdb) 
1067            nmatch = 0;
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1071                    current_typeids[i] == input_base_typeids[i])
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1076            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1084            else if (nmatch == nbestMatch)
(gdb) 
1086                last_candidate->next = current_candidate;
(gdb) p *last_candidate
$17 = {next = 0x2daa720, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) p *current_candidate
$18 = {next = 0x2daa7e0, pathpos = 0, oid = 2779, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa748}
(gdb) n
1087                last_candidate = current_candidate;
(gdb) 
1088                ncandidates++;
(gdb) 
1064             current_candidate = current_candidate->next)
(gdb) 
1062        for (current_candidate = candidates;
(gdb) 
1066            current_typeids = current_candidate->args;
(gdb) 
1067            nmatch = 0;
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1071                    current_typeids[i] == input_base_typeids[i])
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1076            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) p *candidates
$19 = {next = 0x2daa720, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) n
1084            else if (nmatch == nbestMatch)
(gdb) 
1086                last_candidate->next = current_candidate;
(gdb) 
1087                last_candidate = current_candidate;
(gdb) 
1088                ncandidates++;
(gdb) n
1064             current_candidate = current_candidate->next)
(gdb) 
1062        for (current_candidate = candidates;
(gdb) 
1066            current_typeids = current_candidate->args;
(gdb) 
1067            nmatch = 0;
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1071                    current_typeids[i] == input_base_typeids[i])
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1070                if (input_base_typeids[i] != UNKNOWNOID &&
(gdb) 
1068            for (i = 0; i < nargs; i++)
(gdb) 
1076            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1084            else if (nmatch == nbestMatch)
(gdb) 
1086                last_candidate->next = current_candidate;
(gdb) 
1087                last_candidate = current_candidate;
(gdb) 
1088                ncandidates++;
(gdb) 
1064             current_candidate = current_candidate->next)
(gdb) 
1062        for (current_candidate = candidates;
(gdb) 
1093        if (last_candidate)         /* terminate rebuilt list */
(gdb) 
1094            last_candidate->next = NULL;
(gdb) 
1096        if (ncandidates == 1)
(gdb) p *last_candidate
$20 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa838}
(gdb) n
1106        for (i = 0; i < nargs; i++) /* avoid multiple lookups */
(gdb) 
1107            slot_category[i] = TypeCategory(input_base_typeids[i]);
(gdb) 
1106        for (i = 0; i < nargs; i++) /* avoid multiple lookups */
(gdb) p slot_category[i] 
$21 = 78 'N'
(gdb) n
1107            slot_category[i] = TypeCategory(input_base_typeids[i]);
(gdb) 
1106        for (i = 0; i < nargs; i++) /* avoid multiple lookups */
(gdb) p slot_category[i] 
$22 = 88 'X'
(gdb) n
1108        ncandidates = 0;
(gdb) 
1109        nbestMatch = 0;
(gdb) 
1110        last_candidate = NULL;
(gdb) 
1111        for (current_candidate = candidates;
(gdb) 
1115            current_typeids = current_candidate->args;
(gdb) 
1116            nmatch = 0;
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) p current_typeids[i]
$23 = 25
(gdb) n
1122                        IsPreferredType(slot_category[i], current_typeids[i]))
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1127            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1129                nbestMatch = nmatch;
(gdb) 
1130                candidates = current_candidate;
(gdb) 
1131                last_candidate = current_candidate;
(gdb) 
1132                ncandidates = 1;
(gdb) 
1113             current_candidate = current_candidate->next)
(gdb) 
1111        for (current_candidate = candidates;
(gdb) 
1115            current_typeids = current_candidate->args;
(gdb) 
1116            nmatch = 0;
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1122                        IsPreferredType(slot_category[i], current_typeids[i]))
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1127            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1134            else if (nmatch == nbestMatch)
(gdb) 
1136                last_candidate->next = current_candidate;
(gdb) 
1137                last_candidate = current_candidate;
(gdb) 
1138                ncandidates++;
(gdb) 
1113             current_candidate = current_candidate->next)
(gdb) 
1111        for (current_candidate = candidates;
(gdb) 
1115            current_typeids = current_candidate->args;
(gdb) 
1116            nmatch = 0;
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1122                        IsPreferredType(slot_category[i], current_typeids[i]))
(gdb) p *last_candidate
$24 = {next = 0x2daa7e0, pathpos = 0, oid = 2779, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa748}
(gdb) n
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1127            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1134            else if (nmatch == nbestMatch)
(gdb) 
1136                last_candidate->next = current_candidate;
(gdb) 
1137                last_candidate = current_candidate;
(gdb) 
1138                ncandidates++;
(gdb) 
1113             current_candidate = current_candidate->next)
(gdb) 
1111        for (current_candidate = candidates;
(gdb) 
1115            current_typeids = current_candidate->args;
(gdb) 
1116            nmatch = 0;
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1122                        IsPreferredType(slot_category[i], current_typeids[i]))
(gdb) 
1121                    if (current_typeids[i] == input_base_typeids[i] ||
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1119                if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1117            for (i = 0; i < nargs; i++)
(gdb) 
1127            if ((nmatch > nbestMatch) || (last_candidate == NULL))
(gdb) 
1134            else if (nmatch == nbestMatch)
(gdb) 
1136                last_candidate->next = current_candidate;
(gdb) 
1137                last_candidate = current_candidate;
(gdb) 
1138                ncandidates++;
(gdb) 
1113             current_candidate = current_candidate->next)
(gdb) 
1111        for (current_candidate = candidates;
(gdb) 
1142        if (last_candidate)         /* terminate rebuilt list */
(gdb) 
1143            last_candidate->next = NULL;
(gdb) 
1145        if (ncandidates == 1)
(gdb) 
1154        if (nunknowns == 0)
(gdb) 
1176        resolved_unknowns = false;
(gdb) 
1177        for (i = 0; i < nargs; i++)
(gdb) 
1181            if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1182                continue;
(gdb) 
1177        for (i = 0; i < nargs; i++)
(gdb) 
1181            if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1183            resolved_unknowns = true;   /* assume we can do it */
(gdb) 
1184            slot_category[i] = TYPCATEGORY_INVALID;
(gdb) 
1185            slot_has_preferred_type[i] = false;
(gdb) 
1186            have_conflict = false;
(gdb) 
1187            for (current_candidate = candidates;
(gdb) 
1191                current_typeids = current_candidate->args;
(gdb) 
1192                current_type = current_typeids[i];
(gdb) 
1193                get_type_category_preferred(current_type,
(gdb) 
1196                if (slot_category[i] == TYPCATEGORY_INVALID)
(gdb) p current_type
$25 = 25
(gdb) p current_category
$26 = 83 'S'
(gdb) p current_is_preferred
$27 = true
(gdb) p slot_category[i]
$28 = 0 '\000'
(gdb) n
1199                    slot_category[i] = current_category;
(gdb) 
1200                    slot_has_preferred_type[i] = current_is_preferred;
(gdb) 
1189                 current_candidate = current_candidate->next)
(gdb) p current_category
$29 = 83 'S'
(gdb) p current_is_preferred
$30 = true
(gdb) n
1187            for (current_candidate = candidates;
(gdb) 
1191                current_typeids = current_candidate->args;
(gdb) 
1192                current_type = current_typeids[i];
(gdb) 
1193                get_type_category_preferred(current_type,
(gdb) 
1196                if (slot_category[i] == TYPCATEGORY_INVALID)
(gdb) p current_category
$31 = 80 'P'
(gdb) p current_is_preferred
$32 = false
(gdb) n
1202                else if (current_category == slot_category[i])
(gdb) 
1210                    if (current_category == TYPCATEGORY_STRING)
(gdb) 
1221                        have_conflict = true;
(gdb) 
1189                 current_candidate = current_candidate->next)
(gdb) 
1187            for (current_candidate = candidates;
(gdb) 
1191                current_typeids = current_candidate->args;
(gdb) 
1192                current_type = current_typeids[i];
(gdb) 
1193                get_type_category_preferred(current_type,
(gdb) 
1196                if (slot_category[i] == TYPCATEGORY_INVALID)
(gdb) p current_type
$33 = 2277
(gdb) p current_is_preferred
$34 = false
(gdb) p current_category
$35 = 80 'P'
(gdb) n
1202                else if (current_category == slot_category[i])
(gdb) 
1210                    if (current_category == TYPCATEGORY_STRING)
(gdb) 
1221                        have_conflict = true;
(gdb) 
1189                 current_candidate = current_candidate->next)
(gdb) 
1187            for (current_candidate = candidates;
(gdb) 
1191                current_typeids = current_candidate->args;
(gdb) 
1192                current_type = current_typeids[i];
(gdb) 
1193                get_type_category_preferred(current_type,
(gdb) 
1196                if (slot_category[i] == TYPCATEGORY_INVALID)
(gdb) 
1202                else if (current_category == slot_category[i])
(gdb) 
1205                    slot_has_preferred_type[i] |= current_is_preferred;
(gdb) p current_category
$36 = 83 'S'
(gdb) n
1189                 current_candidate = current_candidate->next)
(gdb) 
1187            for (current_candidate = candidates;
(gdb) 
1225            if (have_conflict && slot_category[i] != TYPCATEGORY_STRING)
(gdb) 
1177        for (i = 0; i < nargs; i++)
(gdb) p resolved_unknowns
$37 = true
(gdb) n
1233        if (resolved_unknowns)
(gdb) 
1236            ncandidates = 0;
(gdb) 
1237            first_candidate = candidates;
(gdb) 
1238            last_candidate = NULL;
(gdb) 
1239            for (current_candidate = candidates;
(gdb) 
1243                bool        keepit = true;
(gdb) 
1245                current_typeids = current_candidate->args;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1249                        continue;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1250                    current_type = current_typeids[i];
(gdb) 
1251                    get_type_category_preferred(current_type,
(gdb) p current_type
$38 = 25
(gdb) n
1254                    if (current_category != slot_category[i])
(gdb) p current_category
$39 = 83 'S'
(gdb) p slot_category[i]
$40 = 83 'S'
(gdb) n
1259                    if (slot_has_preferred_type[i] && !current_is_preferred)
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1265                if (keepit)
(gdb) 
1268                    last_candidate = current_candidate;
(gdb) p *current_candidate
$41 = {next = 0x2daa720, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) n
1269                    ncandidates++;
(gdb) 
1241                 current_candidate = current_candidate->next)
(gdb) n
1239            for (current_candidate = candidates;
(gdb) 
1243                bool        keepit = true;
(gdb) 
1245                current_typeids = current_candidate->args;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1249                        continue;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1250                    current_type = current_typeids[i];
(gdb) 
1251                    get_type_category_preferred(current_type,
(gdb) 
1254                    if (current_category != slot_category[i])
(gdb) p current_type
$42 = 2776
(gdb) p current_category
$43 = 80 'P'
(gdb) n
1256                        keepit = false;
(gdb) 
1257                        break;
(gdb) 
1265                if (keepit)
(gdb) 
1274                    if (last_candidate)
(gdb) 
1275                        last_candidate->next = current_candidate->next;
(gdb) 
1241                 current_candidate = current_candidate->next)
(gdb) p *last_candidate
$44 = {next = 0x2daa7e0, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) n
1239            for (current_candidate = candidates;
(gdb) 
1243                bool        keepit = true;
(gdb) 
1245                current_typeids = current_candidate->args;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1249                        continue;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1250                    current_type = current_typeids[i];
(gdb) 
1251                    get_type_category_preferred(current_type,
(gdb) p current_type
$45 = 2277
(gdb) p current_category
$46 = 80 'P'
(gdb) n
1254                    if (current_category != slot_category[i])
(gdb) 
1256                        keepit = false;
(gdb) 
1257                        break;
(gdb) 
1265                if (keepit)
(gdb) 
1274                    if (last_candidate)
(gdb) 
1275                        last_candidate->next = current_candidate->next;
(gdb) 
1241                 current_candidate = current_candidate->next)
(gdb) 
1239            for (current_candidate = candidates;
(gdb) 
1243                bool        keepit = true;
(gdb) 
1245                current_typeids = current_candidate->args;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1249                        continue;
(gdb) 
1246                for (i = 0; i < nargs; i++)
(gdb) 
1248                    if (input_base_typeids[i] != UNKNOWNOID)
(gdb) 
1250                    current_type = current_typeids[i];
(gdb) 
1251                    get_type_category_preferred(current_type,
(gdb) 
1254                    if (current_category != slot_category[i])
(gdb) 
1259                    if (slot_has_preferred_type[i] && !current_is_preferred)
(gdb) p current_category
$47 = 83 'S'
(gdb) p *current_candidate
$48 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa838}
(gdb) n
1246                for (i = 0; i < nargs; i++)
(gdb) 
1265                if (keepit)
(gdb) 
1268                    last_candidate = current_candidate;
(gdb) 
1269                    ncandidates++;
(gdb) 
1241                 current_candidate = current_candidate->next)
(gdb) 
1239            for (current_candidate = candidates;
(gdb) 
1282            if (last_candidate)
(gdb) 
1284                candidates = first_candidate;
(gdb) p *first_candidate
$49 = {next = 0x2daa810, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) p *last_candidate
$50 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa838}
(gdb) n
1286                last_candidate->next = NULL;
(gdb) n
1289            if (ncandidates == 1)
(gdb) 
1303        if (nunknowns < nargs)
(gdb) p *candidates
$51 = {next = 0x2daa810, pathpos = 0, oid = 654, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa718}
(gdb) p *candidates->next
$52 = {next = 0x0, pathpos = 0, oid = 2780, nargs = 2, nvargs = 0, ndargs = 0, argnumbers = 0x0, args = 0x2daa838}
(gdb) n
1305            Oid         known_type = UNKNOWNOID;
(gdb) 
1307            for (i = 0; i < nargs; i++)
(gdb) 
1309                if (input_base_typeids[i] == UNKNOWNOID)
(gdb) 
1311                if (known_type == UNKNOWNOID)   /* first known arg? */
(gdb) 
1312                    known_type = input_base_typeids[i];
(gdb) 
1307            for (i = 0; i < nargs; i++)
(gdb) p known_type
$53 = 23
(gdb) n
1309                if (input_base_typeids[i] == UNKNOWNOID)
(gdb) 
1310                    continue;
(gdb) 
1307            for (i = 0; i < nargs; i++)
(gdb) 
1321            if (known_type != UNKNOWNOID)
(gdb) 
1324                for (i = 0; i < nargs; i++)
(gdb) 
1325                    input_base_typeids[i] = known_type;
(gdb) 
1324                for (i = 0; i < nargs; i++)
(gdb) p known_type
$54 = 23
(gdb) n
1325                    input_base_typeids[i] = known_type;
(gdb) 
1324                for (i = 0; i < nargs; i++)
(gdb) 
1326                ncandidates = 0;
(gdb) 
1327                last_candidate = NULL;
(gdb) 
1328                for (current_candidate = candidates;
(gdb) 
1332                    current_typeids = current_candidate->args;
(gdb) 
1333                    if (can_coerce_type(nargs, input_base_typeids, current_typeids,
(gdb) 
1336                        if (++ncandidates > 1)
(gdb) n
1338                        last_candidate = current_candidate;
(gdb) 
1330                     current_candidate = current_candidate->next)
(gdb) 
1328                for (current_candidate = candidates;
(gdb) 
1332                    current_typeids = current_candidate->args;
(gdb) 
1333                    if (can_coerce_type(nargs, input_base_typeids, current_typeids,
(gdb) 
1336                        if (++ncandidates > 1)
(gdb) 
1337                            break;  /* not unique, give up */
(gdb) 
1341                if (ncandidates == 1)
(gdb) 
1350        return NULL;                /* failed to select a best candidate */
(gdb)

DONE!

四、参考资料

PostgreSQL Type Conversion

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

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

注册时间:2007-12-28

  • 博文量
    1338
  • 访问量
    3804758