这篇文章主要介绍“分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”,在日常操作中,相信很多人在分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
Form_pg_language
plpgsql语言定义结构体
/* ----------------
* pg_language definition. cpp turns this into
* typedef struct FormData_pg_language
* ----------------
*/
CATALOG(pg_language,2612,LanguageRelationId)
{
Oid oid; /* oid */
/* Language name */
NameData lanname;
/* Language's owner */
Oid lanowner BKI_DEFAULT(PGUID);
/* Is a procedural language */
bool lanispl BKI_DEFAULT(f);
/* PL is trusted */
bool lanpltrusted BKI_DEFAULT(f);
/* Call handler, if it's a PL */
Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
/* Optional anonymous-block handler function */
Oid laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
/* Optional validation function */
Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* Access privileges */
aclitem lanacl[1] BKI_DEFAULT(_null_);
#endif
} FormData_pg_language;
/* ----------------
* Form_pg_language corresponds to a pointer to a tuple with
* the format of pg_language relation.
* ----------------
*/
typedef FormData_pg_language *Form_pg_language;
ArrayType
/*
* Arrays are varlena objects, so must meet the varlena convention that
* the first int32 of the object contains the total object size in bytes.
* Be sure to use VARSIZE() and SET_VARSIZE() to access it, though!
* Arrays是可变对象集,必须符合varlena约定,即对象的第一个int32包含对象的总大小(以字节为单位)。
* 但是,一定要确保使用VARSIZE和SET_VARSIZE函数范围该结构体
*
* CAUTION: if you change the header for ordinary arrays you will also
* need to change the headers for oidvector and int2vector!
*/
typedef struct
{
//可变的header
int32 vl_len_; /* varlena header (do not touch directly!) */
//维度
int ndim; /* # of dimensions */
//指向数据的偏移量,如为0则表示没有位图
int32 dataoffset; /* offset to data, or 0 if no bitmap */
//元素类型的OID
Oid elemtype; /* element type OID */
} ArrayType;
DefElem
typedef struct DefElem
{
NodeTag type;
char *defnamespace; /* NULL if unqualified name */
char *defname;
Node *arg; /* a (Value *) or a (TypeName *) */
DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */
int location; /* token location, or -1 if unknown */
} DefElem;
FunctionParameter
typedef enum FunctionParameterMode
{
/* the assigned enum values appear in pg_proc, don't change 'em! */
FUNC_PARAM_IN = 'i', /* input only */
FUNC_PARAM_OUT = 'o', /* output only */
FUNC_PARAM_INOUT = 'b', /* both */
FUNC_PARAM_VARIADIC = 'v', /* variadic (always input) */
FUNC_PARAM_TABLE = 't' /* table function output column */
} FunctionParameterMode;
typedef struct FunctionParameter
{
NodeTag type;
char *name; /* parameter name, or NULL if not given */
TypeName *argType; /* TypeName for parameter type */
FunctionParameterMode mode; /* IN/OUT/etc */
Node *defexpr; /* raw default expr, or NULL if not given */
} FunctionParameter;
/*
* Interpret the function parameter list of a CREATE FUNCTION or
* CREATE AGGREGATE statement.
* 解析CREATE FUNCTON/CREATE AGGREGATE语句中的参数链表
*
* Input parameters:
* parameters: list of FunctionParameter structs
* languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE)
* objtype: needed only to determine error handling and required result type
* 输入参数:
* parameters:FunctionParameter结构体链表
* languageOid:语言ID
* objtype:确定错误处理时需要,并且需要结果类型
*
* Results are stored into output parameters. parameterTypes must always
* be created, but the other arrays are set to NULL if not needed.
* variadicArgType is set to the variadic array type if there's a VARIADIC
* parameter (there can be only one); or to InvalidOid if not.
* requiredResultType is set to InvalidOid if there are no OUT parameters,
* else it is set to the OID of the implied result type.
* 结果存储在输出参数中.必须创建parameterTypes,如不需要其他数组将设置为NULL.
* 如存在VARIADIC参数(有且仅有一个),variadicArgType将设置为variadic数组类型.
* 如无OUT参数,则requiredResultType设置为InvalidOid,否则设置为结果类型.
*/
void
interpret_function_parameter_list(ParseState *pstate,//解析状态
List *parameters,//参数链表
Oid languageOid,//语言OID
ObjectType objtype,//对象类型
oidvector **parameterTypes,//参数类型oid vector
ArrayType **allParameterTypes,//所有的参数类型
ArrayType **parameterModes,//参数模式,i/o/b/v/t
ArrayType **parameterNames,//参数名称
List **parameterDefaults,//参数默认值链表
Oid *variadicArgType,//variadic参数类型OID
Oid *requiredResultType)//结果类型
{
int parameterCount = list_length(parameters);//参数个数
Oid *inTypes;
int inCount = 0;
Datum *allTypes;
Datum *paramModes;
Datum *paramNames;
int outCount = 0;
int varCount = 0;
bool have_names = false;
bool have_defaults = false;
ListCell *x;
int i;
*variadicArgType = InvalidOid; /* default result */
*requiredResultType = InvalidOid; /* default result */
//输入参数类型
inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
//所有参数的类型
allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
//
paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
//参数名称
paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
*parameterDefaults = NIL;
/* Scan the list and extract data into work arrays */
//扫描链表,提前数据到结果数组中
i = 0;
foreach(x, parameters)
{
//函数参数
FunctionParameter *fp = (FunctionParameter *) lfirst(x);
//类型名称
TypeName *t = fp->argType;
//是否输入参数
bool isinput = false;
Oid toid;
//pg_proc元组
Type typtup;
//权限检查结果
AclResult aclresult;
//检索type tuple
typtup = LookupTypeName(NULL, t, NULL, false);
if (typtup)
{
//
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
{
/* As above, hard error if language is SQL */
if (languageOid == SQLlanguageId)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SQL function cannot accept shell type %s",
TypeNameToString(t))));
/* We don't allow creating aggregates on shell types either */
else if (objtype == OBJECT_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate cannot accept shell type %s",
TypeNameToString(t))));
else
ereport(NOTICE,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("argument type %s is only a shell",
TypeNameToString(t))));
}
//type的OID
toid = typeTypeId(typtup);
//释放缓存
ReleaseSysCache(typtup);
}
else
{
//该类型不存在
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s does not exist",
TypeNameToString(t))));
toid = InvalidOid; /* keep compiler quiet */
}
//权限检查
aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, toid);
if (t->setof)
{
//存在setof
if (objtype == OBJECT_AGGREGATE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregates cannot accept set arguments")));
else if (objtype == OBJECT_PROCEDURE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("procedures cannot accept set arguments")));
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("functions cannot accept set arguments")));
}
if (objtype == OBJECT_PROCEDURE)
{
//过程对象,不需要OUT参数,只允许inout参数
if (fp->mode == FUNC_PARAM_OUT)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
(errmsg("procedures cannot have OUT arguments"),
errhint("INOUT arguments are permitted."))));
}
/* handle input parameters */
//处理输入参数
if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
{
//非OUT参数并且不是TABLE参数
/* other input parameters can't follow a VARIADIC parameter */
if (varCount > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be the last input parameter")));
//写入到输入类型数组中
inTypes[inCount++] = toid;
isinput = true;
}
/* handle output parameters */
//处理输出参数
if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
{
if (objtype == OBJECT_PROCEDURE)
//存储过程:要求输出结果类型为RECORD
*requiredResultType = RECORDOID;
else if (outCount == 0) /* save first output param's type */
//第一个OID
*requiredResultType = toid;
outCount++;
}
if (fp->mode == FUNC_PARAM_VARIADIC)
{
//variadic参数
*variadicArgType = toid;
varCount++;
/* validate variadic parameter type */
//验证variadic参数类型
switch (toid)
{
case ANYARRAYOID:
case ANYOID:
/* okay */
break;
default:
if (!OidIsValid(get_element_type(toid)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("VARIADIC parameter must be an array")));
break;
}
}
//转换为Datum
allTypes[i] = ObjectIdGetDatum(toid);
//参数类型
paramModes[i] = CharGetDatum(fp->mode);
if (fp->name && fp->name[0])
{
//检查参数名称,参数名称不能重复
ListCell *px;
/*
* As of Postgres 9.0 we disallow using the same name for two
* input or two output function parameters. Depending on the
* function's language, conflicting input and output names might
* be bad too, but we leave it to the PL to complain if so.
*/
foreach(px, parameters)
{
//循环判断参数是否重复
FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
if (prevfp == fp)
break;
/* pure in doesn't conflict with pure out */
//输入和输出不冲突
if ((fp->mode == FUNC_PARAM_IN ||
fp->mode == FUNC_PARAM_VARIADIC) &&
(prevfp->mode == FUNC_PARAM_OUT ||
prevfp->mode == FUNC_PARAM_TABLE))
continue;
if ((prevfp->mode == FUNC_PARAM_IN ||
prevfp->mode == FUNC_PARAM_VARIADIC) &&
(fp->mode == FUNC_PARAM_OUT ||
fp->mode == FUNC_PARAM_TABLE))
continue;
if (prevfp->name && prevfp->name[0] &&
strcmp(prevfp->name, fp->name) == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("parameter name \"%s\" used more than once",
fp->name)));
}
//获取Datum
paramNames[i] = CStringGetTextDatum(fp->name);
have_names = true;
}
if (fp->defexpr)
{
Node *def;
if (!isinput)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only input parameters can have default values")));
def = transformExpr(pstate, fp->defexpr,
EXPR_KIND_FUNCTION_DEFAULT);
def = coerce_to_specific_type(pstate, def, toid, "DEFAULT");
assign_expr_collations(pstate, def);
/*
* Make sure no variables are referred to (this is probably dead
* code now that add_missing_from is history).
*/
if (list_length(pstate->p_rtable) != 0 ||
contain_var_clause(def))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use table references in parameter default value")));
/*
* transformExpr() should have already rejected subqueries,
* aggregates, and window functions, based on the EXPR_KIND_ for a
* default expression.
*
* It can't return a set either --- but coerce_to_specific_type
* already checked that for us.
*
* Note: the point of these restrictions is to ensure that an
* expression that, on its face, hasn't got subplans, aggregates,
* etc cannot suddenly have them after function default arguments
* are inserted.
*/
*parameterDefaults = lappend(*parameterDefaults, def);
have_defaults = true;
}
else
{
if (isinput && have_defaults)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("input parameters after one with a default value must also have defaults")));
}
i++;
}
/* Now construct the proper outputs as needed */
//如需要,构建合适的输出
*parameterTypes = buildoidvector(inTypes, inCount);
if (outCount > 0 || varCount > 0)
{
//输出参数
*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
sizeof(Oid), true, 'i');
*parameterModes = construct_array(paramModes, parameterCount, CHAROID,
1, true, 'c');
if (outCount > 1)
*requiredResultType = RECORDOID;
/* otherwise we set requiredResultType correctly above */
}
else
{
*allParameterTypes = NULL;
*parameterModes = NULL;
}
if (have_names)
{
//指定了参数名称
for (i = 0; i < parameterCount; i++)
{
if (paramNames[i] == PointerGetDatum(NULL))
paramNames[i] = CStringGetTextDatum("");
}
*parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
-1, false, 'i');
}
else
*parameterNames = NULL;
}
测试脚本
create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)
returns record
as
$$
declare
begin
raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;
pio_v3 := 'pio_v3 i/o';
po_v4 := 100;
po_v5 := 'po_v5 out';
end;
$$ LANGUAGE plpgsql;
启动GDB跟踪
(gdb) c
Continuing.
Breakpoint 1, interpret_function_parameter_list (pstate=0x10edc88, parameters=0x10c7d30,
languageOid=13581, objtype=OBJECT_FUNCTION, parameterTypes=0x7ffec5c6ea88,
allParameterTypes=0x7ffec5c6ea80, parameterModes=0x7ffec5c6ea78,
parameterNames=0x7ffec5c6ea70, parameterDefaults=0x7ffec5c6ea68,
variadicArgType=0x7ffec5c6ea64, requiredResultType=0x7ffec5c6ea60) at functioncmds.c:195
195 int parameterCount = list_length(parameters);
(gdb)
输入参数,语言为pl/pgsql,对象类型是function,存在有5个参数
(gdb) p *pstate
$1 = {parentParseState = 0x0,
p_sourcetext = 0x10c6ed8 "create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)\nreturns record \nas\n$$\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 :="..., p_rtable = 0x0, p_joinexprs = 0x0,
p_joinlist = 0x0, p_namespace = 0x0, p_lateral_active = false, p_ctenamespace = 0x0,
p_future_ctes = 0x0, p_parent_cte = 0x0, p_target_relation = 0x0,
p_target_rangetblentry = 0x0, p_is_insert = false, p_windowdefs = 0x0,
p_expr_kind = EXPR_KIND_NONE, p_next_resno = 1, p_multiassign_exprs = 0x0,
p_locking_clause = 0x0, p_locked_from_parent = false, p_resolve_unknowns = true,
p_queryEnv = 0x0, p_hasAggs = false, p_hasWindowFuncs = false, p_hasTargetSRFs = false,
p_hasSubLinks = false, p_hasModifyingCTE = false, p_last_srf = 0x0,
p_pre_columnref_hook = 0x0, p_post_columnref_hook = 0x0, p_paramref_hook = 0x0,
p_coerce_param_hook = 0x0, p_ref_hook_state = 0x0}
(gdb)
(gdb) p *parameters
$2 = {type = T_List, length = 5, head = 0x10c7d08, tail = 0x10c8480}
(gdb)
初始化相关变量
(gdb) n
197 int inCount = 0;
(gdb)
201 int outCount = 0;
(gdb)
202 int varCount = 0;
(gdb)
203 bool have_names = false;
(gdb)
204 bool have_defaults = false;
(gdb)
208 *variadicArgType = InvalidOid; /* default result */
(gdb)
209 *requiredResultType = InvalidOid; /* default result */
(gdb)
211 inTypes = (Oid *) palloc(parameterCount * sizeof(Oid));
(gdb)
212 allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
(gdb)
213 paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
(gdb)
214 paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
(gdb)
215 *parameterDefaults = NIL;
(gdb)
218 i = 0;
(gdb)
219 foreach(x, parameters)
(gdb)
开始循环,第一个参数,名称为pi_v1,参数类型为pg_catalog.int4
(gdb)
221 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb)
222 TypeName *t = fp->argType;
(gdb)
223 bool isinput = false;
(gdb) p *fp
$4 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp->argType
$5 = {type = T_TypeName, names = 0x10c7bd0, typeOid = 0, setof = false, pct_type = false,
typmods = 0x0, typemod = -1, arrayBounds = 0x0, location = 46}
(gdb) p *fp->argType->names
$6 = {type = T_List, length = 2, head = 0x10c7c30, tail = 0x10c7ba8}
(gdb) p *(Node *)fp->argType->names->head->data.ptr_value
$7 = {type = T_String}
(gdb) p *(Value *)fp->argType->names->head->data.ptr_value
$8 = {type = T_String, val = {ival = 12340746, str = 0xbc4e0a "pg_catalog"}}
(gdb) p *(Value *)fp->argType->names->head->next->data.ptr_value
$9 = {type = T_String, val = {ival = 12320664, str = 0xbbff98 "int4"}}
(gdb) p *t
$10 = {type = T_TypeName, names = 0x10c7bd0, typeOid = 0, setof = false, pct_type = false,
typmods = 0x0, typemod = -1, arrayBounds = 0x0, location = 46}
(gdb)
获取pg_type中对应type的tuple
(gdb) n
228 typtup = LookupTypeName(NULL, t, NULL, false);
(gdb)
229 if (typtup)
(gdb) p *typtup
$11 = {t_len = 176, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 8},
t_tableOid = 1247, t_data = 0x7ff12a2c3c40}
(gdb) p *typtup->t_data
$12 = {t_choice = {t_heap = {t_xmin = 1, t_xmax = 0, t_field3 = {t_cid = 0, t_xvac = 0}},
t_datum = {datum_len_ = 1, datum_typmod = 0, datum_typeid = 0}}, t_ctid = {ip_blkid = {
bi_hi = 0, bi_lo = 0}, ip_posid = 8}, t_infomask2 = 31, t_infomask = 2305,
t_hoff = 32 ' ', t_bits = 0x7ff12a2c3c57 "\377\377\377\017"}
(gdb) x/16c typtup->t_data->t_bits
0x7ff12a2c3c57: -1 '\377' -1 '\377' -1 '\377' 15 '\017' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c5f: 0 '\000' 23 '\027' 0 '\000' 0 '\000' 0 '\000' 105 'i' 110 'n' 116 't'
(gdb) x/64c typtup->t_data->t_bits
0x7ff12a2c3c57: -1 '\377' -1 '\377' -1 '\377' 15 '\017' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c5f: 0 '\000' 23 '\027' 0 '\000' 0 '\000' 0 '\000' 105 'i' 110 'n' 116 't'
0x7ff12a2c3c67: 52 '4' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c6f: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c77: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c7f: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c87: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7ff12a2c3c8f: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
(gdb)
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$14 = {oid = 23, typname = {data = "int4", '\000' <repeats 59 times>}, typnamespace = 11,
typowner = 10, typlen = 4, typbyval = true, typtype = 98 'b', typcategory = 78 'N',
typispreferred = false, typisdefined = true, typdelim = 44 ',', typrelid = 0,
typelem = 0, typarray = 1007, typinput = 42, typoutput = 43, typreceive = 2406,
typsend = 2407, typmodin = 0, typmodout = 0, typanalyze = 0, typalign = 105 'i',
typstorage = 112 'p', typnotnull = false, typbasetype = 0, typtypmod = -1, typndims = 0,
typcollation = 0}
(gdb)
获取type的oid
(gdb) n
251 toid = typeTypeId(typtup);
(gdb)
252 ReleaseSysCache(typtup);
(gdb)
263 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) p toid
$15 = 23
(gdb)
检查权限
263 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb) p toid
$15 = 23
(gdb) n
264 if (aclresult != ACLCHECK_OK)
(gdb)
267 if (t->setof)
(gdb)
处理输入参数
(gdb) p t->setof
$16 = false
(gdb) n
283 if (objtype == OBJECT_PROCEDURE)
(gdb)
293 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb)
296 if (varCount > 0)
(gdb)
300 inTypes[inCount++] = toid;
(gdb)
301 isinput = true;
(gdb)
305 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb)
314 if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb)
(gdb) n
334 allTypes[i] = ObjectIdGetDatum(toid);
(gdb)
336 paramModes[i] = CharGetDatum(fp->mode);
(gdb)
338 if (fp->name && fp->name[0])
(gdb) p fp->mode
$17 = FUNC_PARAM_IN
(gdb) n
348 foreach(px, parameters)
(gdb)
判断是否重名
(gdb) n
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
353 break;
(gdb)
如无重名,设置相关变量,把fp->name的地址写入paramNames指针数组中
373 paramNames[i] = CStringGetTextDatum(fp->name);
(gdb)
374 have_names = true;
(gdb)
377 if (fp->defexpr)
(gdb) p paramNames[0]
$18 = 17751776
下一个参数
(gdb) n
420 if (isinput && have_defaults)
(gdb)
426 i++;
(gdb) p *fp->defexpr
Cannot access memory at address 0x0
(gdb) n
219 foreach(x, parameters)
(gdb)
221 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb)
222 TypeName *t = fp->argType;
(gdb)
223 bool isinput = false;
(gdb)
228 typtup = LookupTypeName(NULL, t, NULL, false);
(gdb)
(gdb) n
229 if (typtup)
(gdb)
231 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb)
251 toid = typeTypeId(typtup);
(gdb)
252 ReleaseSysCache(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$22 = {oid = 1043, typname = {data = "varchar", '\000' <repeats 56 times>},
typnamespace = 11, typowner = 10, typlen = -1, typbyval = false, typtype = 98 'b',
typcategory = 83 'S', typispreferred = false, typisdefined = true, typdelim = 44 ',',
typrelid = 0, typelem = 0, typarray = 1015, typinput = 1046, typoutput = 1047,
typreceive = 2432, typsend = 2433, typmodin = 2915, typmodout = 2916, typanalyze = 0,
typalign = 105 'i', typstorage = 120 'x', typnotnull = false, typbasetype = 0,
typtypmod = -1, typndims = 0, typcollation = 100}
(gdb) n
263 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb)
264 if (aclresult != ACLCHECK_OK)
(gdb)
267 if (t->setof)
(gdb)
283 if (objtype == OBJECT_PROCEDURE)
(gdb)
293 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb)
296 if (varCount > 0)
(gdb)
300 inTypes[inCount++] = toid;
(gdb)
301 isinput = true;
(gdb)
305 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb)
314 if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb)
334 allTypes[i] = ObjectIdGetDatum(toid);
(gdb)
336 paramModes[i] = CharGetDatum(fp->mode);
(gdb)
判断参数是否重复
338 if (fp->name && fp->name[0])
(gdb)
348 foreach(px, parameters)
(gdb) p fp->name
$23 = 0x10c7d68 "pi_v2"
(gdb) p fp->name[0]
$24 = 112 'p'
(gdb) n
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb) p *prevfp
$25 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
357 (prevfp->mode == FUNC_PARAM_OUT ||
(gdb)
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
358 prevfp->mode == FUNC_PARAM_TABLE))
(gdb)
357 (prevfp->mode == FUNC_PARAM_OUT ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
363 fp->mode == FUNC_PARAM_TABLE))
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
366 strcmp(prevfp->name, fp->name) == 0)
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb) p *prevfp
$26 = {type = T_FunctionParameter, name = 0x10c7d68 "pi_v2", argType = 0x10c7e60,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp
$27 = {type = T_FunctionParameter, name = 0x10c7d68 "pi_v2", argType = 0x10c7e60,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
353 break;
(gdb)
373 paramNames[i] = CStringGetTextDatum(fp->name);
(gdb)
374 have_names = true;
(gdb)
377 if (fp->defexpr)
(gdb)
420 if (isinput && have_defaults)
(gdb)
426 i++;
(gdb)
219 foreach(x, parameters)
下一参数,这时候是一个INOUT参数(在IN和OUT数组中均记录)
(gdb) n
221 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb)
222 TypeName *t = fp->argType;
(gdb)
223 bool isinput = false;
(gdb)
228 typtup = LookupTypeName(NULL, t, NULL, false);
(gdb)
229 if (typtup)
(gdb)
231 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb)
251 toid = typeTypeId(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$28 = {oid = 1043, typname = {data = "varchar", '\000' <repeats 56 times>},
typnamespace = 11, typowner = 10, typlen = -1, typbyval = false, typtype = 98 'b',
typcategory = 83 'S', typispreferred = false, typisdefined = true, typdelim = 44 ',',
typrelid = 0, typelem = 0, typarray = 1015, typinput = 1046, typoutput = 1047,
typreceive = 2432, typsend = 2433, typmodin = 2915, typmodout = 2916, typanalyze = 0,
typalign = 105 'i', typstorage = 120 'x', typnotnull = false, typbasetype = 0,
typtypmod = -1, typndims = 0, typcollation = 100}
(gdb) n
252 ReleaseSysCache(typtup);
(gdb)
263 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb)
264 if (aclresult != ACLCHECK_OK)
(gdb)
267 if (t->setof)
(gdb)
283 if (objtype == OBJECT_PROCEDURE)
(gdb)
293 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb)
296 if (varCount > 0)
(gdb)
300 inTypes[inCount++] = toid;
(gdb)
301 isinput = true;
(gdb)
305 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb)
307 if (objtype == OBJECT_PROCEDURE)
(gdb)
309 else if (outCount == 0) /* save first output param's type */
(gdb)
310 *requiredResultType = toid;
(gdb)
311 outCount++;
(gdb)
314 if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb)
334 allTypes[i] = ObjectIdGetDatum(toid);
(gdb)
336 paramModes[i] = CharGetDatum(fp->mode);
(gdb)
338 if (fp->name && fp->name[0])
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb) p *prevfp
$29 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) n
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb) p *fp
$30 = {type = T_FunctionParameter, name = 0x10c7f38 "pio_v3", argType = 0x10c8030,
mode = FUNC_PARAM_INOUT, defexpr = 0x0}
(gdb) n
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
363 fp->mode == FUNC_PARAM_TABLE))
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
366 strcmp(prevfp->name, fp->name) == 0)
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
363 fp->mode == FUNC_PARAM_TABLE))
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
366 strcmp(prevfp->name, fp->name) == 0)
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
353 break;
(gdb)
373 paramNames[i] = CStringGetTextDatum(fp->name);
(gdb)
374 have_names = true;
(gdb)
377 if (fp->defexpr)
(gdb)
420 if (isinput && have_defaults)
(gdb)
426 i++;
(gdb)
219 foreach(x, parameters)
下一个参数,OUT参数
(gdb) n
221 FunctionParameter *fp = (FunctionParameter *) lfirst(x);
(gdb) n
222 TypeName *t = fp->argType;
(gdb)
223 bool isinput = false;
(gdb)
228 typtup = LookupTypeName(NULL, t, NULL, false);
(gdb)
229 if (typtup)
(gdb)
231 if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
(gdb)
251 toid = typeTypeId(typtup);
(gdb) p *((Form_pg_type) GETSTRUCT(typtup))
$31 = {oid = 23, typname = {data = "int4", '\000' <repeats 59 times>}, typnamespace = 11,
typowner = 10, typlen = 4, typbyval = true, typtype = 98 'b', typcategory = 78 'N',
typispreferred = false, typisdefined = true, typdelim = 44 ',', typrelid = 0,
typelem = 0, typarray = 1007, typinput = 42, typoutput = 43, typreceive = 2406,
typsend = 2407, typmodin = 0, typmodout = 0, typanalyze = 0, typalign = 105 'i',
typstorage = 112 'p', typnotnull = false, typbasetype = 0, typtypmod = -1, typndims = 0,
typcollation = 0}
(gdb) n
252 ReleaseSysCache(typtup);
(gdb)
263 aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE);
(gdb)
264 if (aclresult != ACLCHECK_OK)
(gdb)
267 if (t->setof)
(gdb)
283 if (objtype == OBJECT_PROCEDURE)
(gdb)
293 if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
(gdb)
305 if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
(gdb)
307 if (objtype == OBJECT_PROCEDURE)
(gdb)
309 else if (outCount == 0) /* save first output param's type */
(gdb)
311 outCount++;
(gdb)
314 if (fp->mode == FUNC_PARAM_VARIADIC)
(gdb)
334 allTypes[i] = ObjectIdGetDatum(toid);
(gdb)
336 paramModes[i] = CharGetDatum(fp->mode);
(gdb)
338 if (fp->name && fp->name[0])
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb) p *prevfp
$32 = {type = T_FunctionParameter, name = 0x10c7b60 "pi_v1", argType = 0x10c7c58,
mode = FUNC_PARAM_IN, defexpr = 0x0}
(gdb) p *fp
$33 = {type = T_FunctionParameter, name = 0x10c8108 "po_v4", argType = 0x10c8200,
mode = FUNC_PARAM_OUT, defexpr = 0x0}
(gdb) n
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
364 continue;
(gdb) n
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
362 (fp->mode == FUNC_PARAM_OUT ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
364 continue;
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
356 fp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
355 if ((fp->mode == FUNC_PARAM_IN ||
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
361 prevfp->mode == FUNC_PARAM_VARIADIC) &&
(gdb)
360 if ((prevfp->mode == FUNC_PARAM_IN ||
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
366 strcmp(prevfp->name, fp->name) == 0)
(gdb)
365 if (prevfp->name && prevfp->name[0] &&
(gdb)
348 foreach(px, parameters)
(gdb)
350 FunctionParameter *prevfp = (FunctionParameter *) lfirst(px);
(gdb)
352 if (prevfp == fp)
(gdb)
353 break;
(gdb)
373 paramNames[i] = CStringGetTextDatum(fp->name);
(gdb)
374 have_names = true;
(gdb)
377 if (fp->defexpr)
(gdb)
420 if (isinput && have_defaults)
(gdb)
426 i++;
(gdb)
219 foreach(x, parameters)
下一个参数
......
完成所有参数的解析
219 foreach(x, parameters)
(gdb)
430 *parameterTypes = buildoidvector(inTypes, inCount);
(gdb)
432 if (outCount > 0 || varCount > 0)
(gdb)
434 *allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,
(gdb) n
436 *parameterModes = construct_array(paramModes, parameterCount, CHAROID,
(gdb)
438 if (outCount > 1)
(gdb)
439 *requiredResultType = RECORDOID;
(gdb) p *allTypes
$34 = 23
(gdb) p allTypes[4]
$35 = 1043
(gdb) n
438 if (outCount > 1)
(gdb)
448 if (have_names)
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
452 if (paramNames[i] == PointerGetDatum(NULL))
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
452 if (paramNames[i] == PointerGetDatum(NULL))
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
452 if (paramNames[i] == PointerGetDatum(NULL))
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
452 if (paramNames[i] == PointerGetDatum(NULL))
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
452 if (paramNames[i] == PointerGetDatum(NULL))
(gdb)
450 for (i = 0; i < parameterCount; i++)
(gdb)
455 *parameterNames = construct_array(paramNames, parameterCount, TEXTOID,
(gdb)
460 }
(gdb)
CreateFunction (pstate=0x10edc88, stmt=0x10c88c8) at functioncmds.c:1065
1065 if (stmt->is_procedure)
(gdb)
到此,关于“分析PostgreSQL CreateFunction中的interpret_function_parameter_list函数”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:http://blog.itpub.net/6906/viewspace-2676678/