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