这篇文章主要介绍“分析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函数”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。