您好,登錄后才能下訂單哦!
這篇文章主要講解了“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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。