这篇文章主要讲解了“PostgreSQL隐式类型转换中选择操作符的实现函数是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL隐式类型转换中选择操作符的实现函数是什么”吧!
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, ¤t_category, ¤t_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, ¤t_category, ¤t_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)
感谢各位的阅读,以上就是“PostgreSQL隐式类型转换中选择操作符的实现函数是什么”的内容了,经过本文的学习后,相信大家对PostgreSQL隐式类型转换中选择操作符的实现函数是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。