pg 函数匹配规则
Posted 紫无之紫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pg 函数匹配规则相关的知识,希望对你有一定的参考价值。
pg 函数匹配规则
在pg 的官方文档中,在类型转换一节下有对函数的匹配规则进行介绍。下面是我对其的梳理记录。
查找规则
pg 是通过查找pg_proc来查找函数
func_get_detail
1. 根据函数名及参数个数筛选函数
首先看是否指定了schema, 如果指定了shcema,则在指定的schema 下查找对应函数名及参数个数的函数,如:oracle.substr(orafce 插件),则在oracle shcema 下查找;如果没指定,则在 search_path 指定的schema 下查找。
- 如果搜索路径(search_path)下发现多个参数类型相同的函数,那么只考虑最早在搜索路径中出现的那个。 不同参数类型的函数被平等对待,不受在搜索路径中位置的影响。通过\\df 可以发现,对于同名同参函数,在\\df 只会显示schema在search_path中最前下的函数。
- 如果使用了VARIADIC数组参数,并且调用时没有使用VARIADIC关键字,那么就变成了可变函数,参数可变(为指定元素类型的一次或多次)。这种情况下函数可能会变得和其他同名函数有相同参数,在这种情况下,在search_path中出现较早的被使用,如果在同一个schema下则优先使用不可变的函数。
- 对于那些参数有默认值的函数,可能匹配到省略了0个或多个默认值的调用。 如果有超出一个这种函数匹配到一个调用,则使用最早出现在搜索路径中的那个,如果是同个schema, 则报错。
FuncnameGetCandidates
2. 查找参数精确匹配的函数
经过上面的处理,获取了相同函数名及参数个数的函数列表,然后从剩余的函数中查找参数精确匹配的函数,若找到则使用。
在此步骤对于unknown 参数,没有匹配的类型。
3. 判断函数调用是否其实是类型转换
如果函数调用只有一个参数,并且函数名和数据类型的(内部)名称相同,同时该参数必须是unknown 类型,或者是一个可以强制转换到函数名类型的类型(二进制可强制转换),或者是可以通过此类型的I/O函数转换为函数名类型的类型。当满足上述条件时,则函数调用被当成是cast调用。
note
二进制可强制性(binary coercible)表示可以不调任何函数直接转换到对应类型,需要两种类型对应的相同值在内部的表示相同。
二进制可强制性不是一种对称关系,只是单方向的,如从xml到 text的造型可以被免费执行,但是反向则需要一个函数来 执行至少一次语法检查,双向都为二进制可强制性的类型也被称作二进制兼容。
4. 没有精确匹配,查找最佳的匹配
函数匹配规则:
- 去除那些参数类型不匹配且不能通过隐式转换转换为参数类型的函数,unknown 类型可以转换为任意类型。去除后,如果只有一个函数则使用,不然下一步。
- 在所有后续步骤中把域类型当成是其基本类型处理。
- 检测输入类型是否有准确匹配的,如果有则保留准确匹配个数最多的,没有准确匹配的则保留全部,如果只有一个函数了则使用,不然下一步。
- 检测所有函数,保留那些类型转换是首选类型(需要与输入在同一个分类)且首选类型的转换个数最多的, 如果没有首选类型,则都保留。如果只有一个函数了则使用,不然下一步。
- 对于unknown 类型的入参, 检查所有函数,如果这些函数中有函数在对应位置(unknown参数位置)为string 类型分类,则unknown 转为string, 不然,检查所有函数在此位置类型分类是否都相同,若都相同, 则unknown转为此类型分类,如果还没有,则认为失败,先不转换。转换后,筛掉那些不为转换后类型分类的函数。如果这些函数中存在首选类型的函数,则筛除那些不是首选类型的函数。
如果只有一个函数了则使用,不然下一步。 - 如果既有unknown参数也有已知类型的参数,并且所有已知类型参数具有相同的类型,则假定该unknown参数也是那种类型的,并且检查哪些候选函数可以在该unknown参数的位置上接受那个类型。如果正好有一个候选者通过了这个测试,则使用之;否则失败。
首选类型: 在可对同一分类的类型进行隐式转换时首选的类型。创建类型是可以指定。
隐式转换: 隐式转换只能在同一分类的类型间进行转换。
代码分析
func_get_detail
//1. 根据函数名及参数个数筛选函数
/* Get list of possible candidates from namespace search */
raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
expand_variadic, expand_defaults,
false);
//2. 查找参数精确匹配的函数
/*
* Quickly check if there is an exact match to the input datatypes (there
* can be only one)
*/
for (best_candidate = raw_candidates;
best_candidate != NULL;
best_candidate = best_candidate->next)
/* if nargs==0, argtypes can be null; don't pass that to memcmp */
if (nargs == 0 ||
memcmp(argtypes, best_candidate->args, nargs * sizeof(Oid)) == 0)
break;
if (best_candidate == NULL)
//3. 判断函数调用是否其实是类型转换
if (nargs == 1 && fargs != NIL && fargnames == NIL)
xxxx
xxxx
//4. 没有精确匹配,查找最佳的匹配
if (raw_candidates != NULL)
FuncCandidateList current_candidates;
int ncandidates;
bool have_multiple = false;
// 4.1
ncandidates = func_match_argtypes(nargs,
argtypes,
&raw_candidates,
¤t_candidates);
/* one match only? then run with it... */
if (ncandidates == 1)
best_candidate = current_candidates;
/*
* multiple candidates? then better decide or throw an error...
*/
else if (ncandidates > 1)
//4.2 4.3 4.4
best_candidate = func_select_candidate(nargs,
argtypes,
current_candidates);
/*
* If we were able to choose a best candidate, we're done.
* Otherwise, ambiguous function call.
*/
if (!best_candidate)
return FUNCDETAIL_MULTIPLE;
参考资料
第 10 章 类型转换 函数
Chapter 10. Type Conversion Functions
以上是关于pg 函数匹配规则的主要内容,如果未能解决你的问题,请参考以下文章