Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analyze the process of creating a function by PostgreSQL

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article focuses on "analyzing the process of creating functions in PostgreSQL". Interested friends may wish to have a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "analyzing the process of creating functions in PostgreSQL".

I. data structure

Form_pg_language

Plpgsql language definition structure

/ *-* 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 is a set of variable objects and must conform to the varlena convention, that is, the first int32 of an object contains the total size of the object in bytes. * however, be sure to use the VARSIZE and SET_VARSIZE functions to scope the structure * * CAUTION: if you change the header for ordinary arrays you will also * need to change the headers for oidvector and int2vector! * / typedef struct {/ / variable header int32 vl_len_; / * varlena header (do not touch directly!) * / / Dimension int ndim / * # of dimensions * / / points to the offset of the data. 0 means there is no bitmap int32 dataoffset; / * offset to data, or 0 if no bitmap * / / element type 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 = 'FunctionParameterMode, / * input only * / FUNC_PARAM_OUT =' oasis, / * output only * / FUNC_PARAM_INOUT = 'baked, / * both * / FUNC_PARAM_VARIADIC =' vested, / * 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

CatCache

/ * function computing a datum's hash * / typedef uint32 (* CCHashFN) (Datum datum); / * function computing equality of two datums * / typedef bool (* CCFastEqualFN) (Datum a, Datum b); hash slot int cc_nbuckets; / * # of hash buckets in this cache * / tuple descriptor TupleDesc cc_tupdesc of typedef struct catcache {/ / cache ID int id; / * cache identifier-- see syscache.h * / / cache / * tuple descriptor (copied from reldesc) * / / hash bucket dlist_head * cc_bucket; / * hash buckets * / / CCHashFN cc_ hash function of each key [CATCACHE _ MAXKEYS]; / * hash function for each key * / / the fast equivalent function CCFastEqualFN cc_ of each key [CATCACHE _ MAXKEYS] / * fast equal function for * each key * / / the attribute number of each key is int cc_ Keyno [CATCACHE _ MAXKEYS]; / * AttrNumber of each key * / CatCList structure body list dlist_head cc_lists; / * list of CatCList structs * / / cache int cc_ntup; / * # of tuples currently in this cache * / / keys number int cc_nkeys / * # of keys (1..CATCACHE_MAXKEYS) * / / cache tuple related relation const char * cc_relname; / * name of relation the tuples come from * / / relation OID Oid cc_reloid; / * OID of relation the tuples come from * / / can the index OID Oid cc_indexoid; / * OID of index matching cache keys * / / of matching cache keys be shared across libraries? Bool cc_relisshared; / * is relation shared across databases? * / / linked list link slist_node cc_next; / * list link * / / precomputed key information for heap scanning ScanKeyData cc_ skey [CATCACHE _ MAXKEYS] / * precomputed key info for heap * scans * / * Keep these at the end, so that compiling catcache.c with CATCACHE_STATS * doesn't break ABI for other modules * these items are placed at the end, so that when compiling catcache.c with the CATCACHE_STATS option, there is no need to terminate the ABI * / # ifdef CATCACHE_STATS / / retrieval times of other modules. / * total # searches against this cache * / / number of matches long cc_hits; / * # of matches against existing entry * / number of misses long cc_neg_hits; / * # of matches against negative entry * / number of misses loaded successfully long cc_newloads / * # of successful loads of new entry * / * * cc_searches-(cc_hits + cc_neg_hits + cc_newloads) is number of failed * searches, each of which will result in loading a negative entry\\ * cc_searches-(cc_hits + cc_neg_hits + cc_newloads) is the number of cache retrieval failures * / the number of verification failures long cc_invals / * # of entries invalidated from cache * / / number of linked list searches long cc_lsearches; / * total # list-searches * / / long cc_lhits; / * # of matches against existing lists * / # endif} CatCache; II. Source code interpretation HeapTupleSearchSysCache3 (int cacheId, Datum key1, Datum key2, Datum key3) {/ / check Assert (cacheId > = 0 & cacheId)

< SysCacheSize && PointerIsValid(SysCache[cacheId])); Assert(SysCache[cacheId]->

< SysCacheSize &&(gdb) 输入参数:cacheId=42, key1=22952624, key2=23913368, key3=2200 其中key1->

ProcedureName,key2- > parameterTypes,key3- > procNamespace

There are 3 input parameter types, which are respectively 23ax 1043 (inout parameter).

(gdb) p (char *) 22952624 $3 = 0x15e3ab0 "func_test" (gdb) p ((oidvector *) 23913368) [0] $4 = {vl_len_ = 22952624, ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 3, lbound1 = 0 Values = 0x16ce3b0} (gdb) p ((oidvector *) 23913368) [0]-> values$7 = 0x16ce3b0 (gdb) p * ((oidvector *) 23913368) [0]-> values$8 = 23 (gdb) p ((oidvector *) 23913368) [0]-> values [0] $9 = 23 (gdb) p ((oidvector *) 23913368) [0]-> values [1] $10 = 1043 (gdb) p (oidvector *) 23913368) [0]-> values [2] $11 = 1043 (gdb)

Enter SearchCatCache3

(gdb) n1151 Assert (SysCacheId]-> cc_nkeys = = 3); (gdb) n1153 return SearchCatCache3 (SysCache [cacheId], key1, key2, key3); (gdb) stepSearchCatCache3 (cache=0x1639c80, v1 / 22952624, v2 / 23913368, v3 / 2200) at catcache.c:11831183 return SearchCatCacheInternal (cache, 3, v1, v2, v3, 0); (gdb)

Enter SearchCatCacheInternal

(gdb) stepSearchCatCacheInternal (cache=0x1639c80, nkeys=3, v1 / 22952624, v2 / 2 / 23913368, v3 / 2 / 2200, v4 / 2) at catcache.c:12131213 Assert (IsTransactionState ()); (gdb)

Cache information

(gdb) n1215 Assert (cache- > cc_nkeys = = nkeys) (gdb) p * cache$13 = {id = 42, cc_nbuckets = 128, cc_tupdesc = 0x7f8159216ef8, cc_bucket = 0x163a160, cc_hashfunc = {0xa48129, 0xa48257, 0xa481b0, 0x0}, cc_fastequal = {0xa480ea, 0xa48222, 0xa48193, 0x0}, cc_keyno = {2,20,3,0}, cc_lists = {head = {prev = 0x7f81591cad60, next = 0x7f81591aab18}}, cc_ntup = 29, cc_nkeys = 3, cc_relname = 0x7f8159217f10 "pg_proc", cc_reloid = 1255, cc_indexoid = 2691 Cc_relisshared = false, cc_next = {next = 0x1639698}, cc_skey = {{sk_flags = 0, sk_attno = 2, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9a1cf3, fn_oid = 62, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0} Sk_argument = 0}, {sk_flags = 0, sk_attno = 20, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9be7e8, fn_oid = 679, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0}, sk_argument = 0}, {sk_flags = 0 Sk_attno = 3, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9be650, fn_oid = 184, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0}, sk_argument = 0}, {sk_flags = 0, sk_attno = 0, sk_strategy = 0 Sk_subtype = 0, sk_collation = 0, sk_func = {fn_addr = 0x0, fn_oid = 0, fn_nargs = 0,-- Type to continue, or q to quit--- fn_strict = false, fn_retset = false, fn_stats = 0'\ 000mm, fn_extra = 0x0, fn_mcxt = 0x0, fn_expr = 0x0}, sk_argument = 0}} (gdb)

Pg_proc tuple descriptor

(gdb) p * cache- > cc_tupdesc$14 = {natts = 29, tdtypeid = 81, tdtypmod =-1, tdrefcount =-1, constr = 0x7f8159216b90, attrs = 0x7f8159216f10} (gdb) p * cache- > cc_tupdesc- > constr$15 = {defval = 0x0, check = 0x0, missing = 0x0, num_defval = 0, num_check = 0, has_not_null = true, has_generated_stored = false} (gdb) p * cache- > cc_tupdesc- > attrs$16 = {attrelid = 1255, attname = {data = "oid",'\ 000'} Atttypid = 26, attstattarget =-1, attlen = 4, attnum = 1, attndims = 0, attcacheoff = 0, atttypmod =-1, attbyval = true, attstorage = 112 'packs, attalign = 105' iregions, attnotnull = true, atthasdef = false, atthasmissing = false, attidentity = 0'\ 000mm, attgenerated = 0'\ 000miles, attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 0} (gdb) p cache- > cc_tupdesc- > attrs [1] $17 = {attrelid = 1255, attname = {data = "proname" '\ 000'}, atttypid = 19, attstattarget =-1, attlen = 64, attnum = 2, attndims = 0, attcacheoff = 4, atttypmod =-1, attbyval = false, attstorage = 112' packs, attalign = 99 'cages, attnotnull = true, atthasdef = false, atthasmissing = false, attidentity = 0000, attgenerated = 0000, attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 950} (gdb)

Get hash bucket

(gdb) n1220 if (unlikely (cache- > cc_tupdesc = = NULL)) (gdb) 1228 arguments [0] = v1; (gdb) 1229 arguments [1] = v2; (gdb) 1230 arguments [2] = v3; (gdb) 1231 arguments [3] = v4; (gdb) 1236 hashValue = CatalogCacheComputeHashValue (cache, nkeys, v1, v2, v3, v4); (gdb) 1237 hashIndex = HASH_INDEX (hashValue, cache- > cc_nbuckets); (gdb) 1245 bucket = & cache- > cc_ bucket[ hashIndex] (gdb) p hashValue$18 = 3879045281 (gdb) p hashIndex$19 = 33 (gdb) (gdb) n1246 dlist_foreach (iter, bucket) (gdb) p * bucket$20 = {head = {prev = 0x7f815919d688, next = 0x7f815919d688}} (gdb)

Look up the linked list in the hash bucket

(gdb) n1248 ct = dlist_container (CatCTup, cache_elem, iter.cur); (gdb) 1250 if (ct- > dead) (gdb) 1253 if (ct- > hash_value! = hashValue) (gdb) 1254 continue; / * quickly skip entry if wrong hash val * / (gdb) 1246 dlist_foreach (iter, bucket) (gdb) 1299 return SearchCatCacheMiss (cache, nkeys, hashValue, hashIndex, v1, v2, v3, v4) (gdb) stepSearchCatCacheMiss (cache=0x1639c80, nkeys=3, hashValue=3879045281, hashIndex=33, v1: 22952624, v2: 23913368, v3: 2200, v4: 0) at catcache.c:13271327 arguments [0] = v1; (gdb)

If it is not found, call SearchCatCacheMiss to build the scan key

(gdb) n1328 arguments [1] = v2; (gdb) 1329 arguments [2] = v3; (gdb) 1330 arguments [3] = v4; (gdb) 1336 memcpy (cur_skey, cache- > cc_skey, sizeof (ScanKeyData) * nkeys); (gdb) 1337 cur_skey [0] .sk _ argument = v1; (gdb) 1338 cur_skey [1] .sk _ argument = v2; (gdb) 1339 cur_skey [2] .sk _ argument = v3 (gdb) 1340 cur_skey [3] .SK _ argument = v4; (gdb) 1357 relation = table_open (cache- > cc_reloid, AccessShareLock) (gdb) p * cur_skey$21 = {sk_flags = 0, sk_attno = 2, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9a1cf3, fn_oid = 62, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0} Sk_argument = 22952624} (gdb) p cur_skey [1] $22 = {sk_flags = 0, sk_attno = 20, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9be7e8, fn_oid = 679, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0} Sk_argument = 23913368} (gdb) p cur_skey [2] $23 = {sk_flags = 0, sk_attno = 3, sk_strategy = 3, sk_subtype = 0, sk_collation = 950, sk_func = {fn_addr = 0x9be650, fn_oid = 184, fn_nargs = 2, fn_strict = true, fn_retset = false, fn_stats = 2'\ 002, fn_extra = 0x0, fn_mcxt = 0x16280d0, fn_expr = 0x0} Sk_argument = 2200} (gdb) p cur_skey [4] $24 = {sk_flags = 0, sk_attno = 0, sk_strategy = 0, sk_subtype = 0, sk_collation = 2691234902, sk_func = {fn_addr = 0x1639c98, fn_oid = 16681376, fn_nargs =-30559, fn_strict = 53, fn_retset = 231, fn_stats = 96'`, fn_extra = 0xa4a825, fn_mcxt = 0x898, fn_expr = 0x0}, sk_argument = 0} (gdb)

Start scanning

(gdb) n1361 IndexScanOK (cache, cur_skey), (gdb) 1359 scandesc = systable_beginscan (relation, (gdb) 1366 ct = NULL; (gdb) 1368 while (HeapTupleIsValid (ntp = systable_getnext (scandesc) (gdb) 1370 ct = CatalogCacheCreateEntry (cache, ntp, arguments, (gdb) 1374 ResourceOwnerEnlargeCatCacheRefs (CurrentResourceOwner); (gdb) 1375 ct- > refcount++; (gdb) 1376 ResourceOwnerRememberCatCacheRef (CurrentResourceOwner, & ct- > tuple); (gdb) 1377 break / * assume only one match * / (gdb) 1380 systable_endscan (scandesc); (gdb) 1382 table_close (relation, AccessShareLock); (gdb) 1394 if (ct = = NULL) (gdb)

If successful, return tuple

1425 return & ct- > tuple (gdb) (gdb) p * ct$25 = {ct_magic = 1462113538, hash_value = 3879045281, keys = {1401935225672361401935225673442200,0}, cache_elem = {prev = 0x163a370, next = 0x7f815919d688}, refcount = 1, dead = false, negative = false, tuple = {t_len = 488, t_self = {bi_hi = 0, bi_lo = 42}, ip_posid = 20}, t_tableOid = 1255, t_data = 0x7f81591cc820}, c_list = 0x0 My_cache = 0x1639c80} (gdb) p ct- > tuple$26 = {t_len = 488,t_self = {ip_blkid = {bi_hi = 0, bi_lo = 42}, ip_posid = 20}, t_tableOid = 1255, t_data = 0x7f81591cc820} (gdb) so far I believe you have a deeper understanding of "analyzing the process of creating functions in PostgreSQL", so you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report