本篇内容主要讲解“分析PostgreSQL创建函数的过程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL创建函数的过程”吧!
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;
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);
typedef struct catcache
{
//cache ID
int id; /* cache identifier --- see syscache.h */
//cache的hash槽
int cc_nbuckets; /* # of hash buckets in this cache */
//元组描述符
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
//hash桶
dlist_head *cc_bucket; /* hash buckets */
//每个key的hash函数
CCHashFN cc_hashfunc[CATCACHE_MAXKEYS]; /* hash function for each key */
//每个key的快速等值函数
CCFastEqualFN cc_fastequal[CATCACHE_MAXKEYS]; /* fast equal function for
* each key */
//每个key的属性编号
int cc_keyno[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
//CatCList结构体链表
dlist_head cc_lists; /* list of CatCList structs */
//cache中元组数
int cc_ntup; /* # of tuples currently in this cache */
//keys数
int cc_nkeys; /* # of keys (1..CATCACHE_MAXKEYS) */
//cache元组相关的relation
const char *cc_relname; /* name of relation the tuples come from */
//relation OID
Oid cc_reloid; /* OID of relation the tuples come from */
//匹配缓存keys的索引OID
Oid cc_indexoid; /* OID of index matching cache keys */
//是否可跨库共享?
bool cc_relisshared; /* is relation shared across databases? */
//链表链接
slist_node cc_next; /* list link */
//用于heap扫描的预计算key信息
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
* 这些项放在最后面,以便使用CATCACHE_STATS选项编译catcache.c时不需要终止其他模块的ABI
*/
#ifdef CATCACHE_STATS
//检索次数
long cc_searches; /* total # searches against this cache */
//匹配次数
long cc_hits; /* # of matches against existing entry */
//未命中次数
long cc_neg_hits; /* # of matches against negative entry */
//未命中成功加载次数
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)是cache检索失败次数
*/
//验证失效次数
long cc_invals; /* # of entries invalidated from cache */
//链表检索次数
long cc_lsearches; /* total # list-searches */
//
long cc_lhits; /* # of matches against existing lists */
#endif
} CatCache;
HeapTuple
SearchSysCache3(int cacheId,
Datum key1, Datum key2, Datum key3)
{
//执行检查
Assert(cacheId >= 0 && cacheId < SysCacheSize &&
PointerIsValid(SysCache[cacheId]));
Assert(SysCache[cacheId]->cc_nkeys == 3);
//直接调用SearchCatCache3
return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
}
HeapTuple
SearchCatCache3(CatCache *cache,
Datum v1, Datum v2, Datum v3)
{
//直接调用SearchCatCacheInternal
return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
}
/*
* Work-horse for SearchCatCache/SearchCatCacheN.
* 通用函数:SearchCatCache/SearchCatCacheN调用
*/
static inline HeapTuple
SearchCatCacheInternal(CatCache *cache,
int nkeys,
Datum v1,
Datum v2,
Datum v3,
Datum v4)
{
//#define CATCACHE_MAXKEYS 4
Datum arguments[CATCACHE_MAXKEYS];
uint32 hashValue;
Index hashIndex;
dlist_iter iter;
dlist_head *bucket;
CatCTup *ct;
/* Make sure we're in an xact, even if this ends up being a cache hit */
//确保处于事务中
Assert(IsTransactionState());
Assert(cache->cc_nkeys == nkeys);
/*
* one-time startup overhead for each cache
*/
if (unlikely(cache->cc_tupdesc == NULL))
CatalogCacheInitializeCache(cache);
#ifdef CATCACHE_STATS
cache->cc_searches++;
#endif
/* Initialize local parameter array */
//初始化本地参数数组
arguments[0] = v1;
arguments[1] = v2;
arguments[2] = v3;
arguments[3] = v4;
/*
* find the hash bucket in which to look for the tuple
* 检索hash桶
*/
hashValue = CatalogCacheComputeHashValue(cache, nkeys, v1, v2, v3, v4);
hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets);
/*
* scan the hash bucket until we find a match or exhaust our tuples
* 扫描hash桶
*
* Note: it's okay to use dlist_foreach here, even though we modify the
* dlist within the loop, because we don't continue the loop afterwards.
* 就算在循环过程中更新了dlist也可以用dlist_foreach,因为不再往后循环了
*/
bucket = &cache->cc_bucket[hashIndex];
dlist_foreach(iter, bucket)
{
ct = dlist_container(CatCTup, cache_elem, iter.cur);
if (ct->dead)//忽略已废弃的条目
continue; /* ignore dead entries */
if (ct->hash_value != hashValue)//跳过hash不同的项
continue; /* quickly skip entry if wrong hash val */
//不同的元组,跳过
if (!CatalogCacheCompareTuple(cache, nkeys, ct->keys, arguments))
continue;
/*
* We found a match in the cache. Move it to the front of the list
* for its hashbucket, in order to speed subsequent searches. (The
* most frequently accessed elements in any hashbucket will tend to be
* near the front of the hashbucket's list.)
* 命中,放在链表的头部
*/
dlist_move_head(bucket, &ct->cache_elem);
/*
* If it's a positive entry, bump its refcount and return it. If it's
* negative, we can report failure to the caller.
* 正向项,增加refcount并返回
*/
if (!ct->negative)
{
ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);
ct->refcount++;
ResourceOwnerRememberCatCacheRef(CurrentResourceOwner, &ct->tuple);
CACHE_elog(DEBUG2, "SearchCatCache(%s): found in bucket %d",
cache->cc_relname, hashIndex);
#ifdef CATCACHE_STATS
cache->cc_hits++;
#endif
return &ct->tuple;
}
else
{
CACHE_elog(DEBUG2, "SearchCatCache(%s): found neg entry in bucket %d",
cache->cc_relname, hashIndex);
#ifdef CATCACHE_STATS
cache->cc_neg_hits++;
#endif
return NULL;
}
}
return SearchCatCacheMiss(cache, nkeys, hashValue, hashIndex, v1, v2, v3, v4);
}
/*
* Search the actual catalogs, rather than the cache.
*
* This is kept separate from SearchCatCacheInternal() to keep the fast-path
* as small as possible. To avoid that effort being undone by a helpful
* compiler, try to explicitly forbid inlining.
*/
static pg_noinline HeapTuple
SearchCatCacheMiss(CatCache *cache,
int nkeys,
uint32 hashValue,
Index hashIndex,
Datum v1,
Datum v2,
Datum v3,
Datum v4)
{
ScanKeyData cur_skey[CATCACHE_MAXKEYS];
Relation relation;
SysScanDesc scandesc;
HeapTuple ntp;
CatCTup *ct;
Datum arguments[CATCACHE_MAXKEYS];
/* Initialize local parameter array */
arguments[0] = v1;
arguments[1] = v2;
arguments[2] = v3;
arguments[3] = v4;
/*
* Ok, need to make a lookup in the relation, copy the scankey and fill
* out any per-call fields.
*/
memcpy(cur_skey, cache->cc_skey, sizeof(ScanKeyData) * nkeys);
cur_skey[0].sk_argument = v1;
cur_skey[1].sk_argument = v2;
cur_skey[2].sk_argument = v3;
cur_skey[3].sk_argument = v4;
/*
* Tuple was not found in cache, so we have to try to retrieve it directly
* from the relation. If found, we will add it to the cache; if not
* found, we will add a negative cache entry instead.
*
* NOTE: it is possible for recursive cache lookups to occur while reading
* the relation --- for example, due to shared-cache-inval messages being
* processed during table_open(). This is OK. It's even possible for one
* of those lookups to find and enter the very same tuple we are trying to
* fetch here. If that happens, we will enter a second copy of the tuple
* into the cache. The first copy will never be referenced again, and
* will eventually age out of the cache, so there's no functional problem.
* This case is rare enough that it's not worth expending extra cycles to
* detect.
*/
relation = table_open(cache->cc_reloid, AccessShareLock);
scandesc = systable_beginscan(relation,
cache->cc_indexoid,
IndexScanOK(cache, cur_skey),
NULL,
nkeys,
cur_skey);
ct = NULL;
while (HeapTupleIsValid(ntp = systable_getnext(scandesc)))
{
ct = CatalogCacheCreateEntry(cache, ntp, arguments,
hashValue, hashIndex,
false);
/* immediately set the refcount to 1 */
ResourceOwnerEnlargeCatCacheRefs(CurrentResourceOwner);
ct->refcount++;
ResourceOwnerRememberCatCacheRef(CurrentResourceOwner, &ct->tuple);
break; /* assume only one match */
}
systable_endscan(scandesc);
table_close(relation, AccessShareLock);
/*
* If tuple was not found, we need to build a negative cache entry
* containing a fake tuple. The fake tuple has the correct key columns,
* but nulls everywhere else.
*
* In bootstrap mode, we don't build negative entries, because the cache
* invalidation mechanism isn't alive and can't clear them if the tuple
* gets created later. (Bootstrap doesn't do UPDATEs, so it doesn't need
* cache inval for that.)
*/
if (ct == NULL)
{
if (IsBootstrapProcessingMode())
return NULL;
ct = CatalogCacheCreateEntry(cache, NULL, arguments,
hashValue, hashIndex,
true);
CACHE_elog(DEBUG2, "SearchCatCache(%s): Contains %d/%d tuples",
cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
CACHE_elog(DEBUG2, "SearchCatCache(%s): put neg entry in bucket %d",
cache->cc_relname, hashIndex);
/*
* We are not returning the negative entry to the caller, so leave its
* refcount zero.
*/
return NULL;
}
CACHE_elog(DEBUG2, "SearchCatCache(%s): Contains %d/%d tuples",
cache->cc_relname, cache->cc_ntup, CacheHdr->ch_ntup);
CACHE_elog(DEBUG2, "SearchCatCache(%s): put in bucket %d",
cache->cc_relname, hashIndex);
#ifdef CATCACHE_STATS
cache->cc_newloads++;
#endif
return &ct->tuple;
}
测试脚本
[local:/data/run/pg12]:5120 pg12@testdb=# select oid,proname,pronargs,proargtypes,proallargtypes from pg_proc where proname = 'func_test';
oid | proname | pronargs | proargtypes | proallargtypes
-------+-----------+----------+--------------+------------------------
16387 | func_test | 3 | 23 1043 1043 | {23,1043,1043,23,1043}
(1 row)
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) b pg_proc.c:367
Breakpoint 1 at 0x5be038: file pg_proc.c, line 367.
(gdb)
(gdb) c
Continuing.
Breakpoint 1, ProcedureCreate (procedureName=0x15e3ab0 "func_test", procNamespace=2200,
replace=true, returnsSet=false, returnType=2249, proowner=10, languageObjectId=13581,
languageValidator=13580,
prosrc=0x15e45c8 "\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;\n pio_v3 := 'pio_v3 i/o';\n po_v4 := 100;\n po_v5 := 'po_v5 out';\nend;\n",
probin=0x0, prokind=102 'f', security_definer=false, isLeakProof=false, isStrict=false,
volatility=118 'v', parallel=117 'u', parameterTypes=0x16ce398,
allParameterTypes=23913456, parameterModes=23913544, parameterNames=23913600,
parameterDefaults=0x0, trftypes=0, proconfig=0, prosupport=0, procost=100, prorows=0)
at pg_proc.c:367
367 tupDesc = RelationGetDescr(rel);
(gdb)
进入SearchSysCache3
(gdb) n
370 oldtup = SearchSysCache3(PROCNAMEARGSNSP,
(gdb) step
SearchSysCache3 (cacheId=42, key1=22952624, key2=23913368, key3=2200) at syscache.c:1149
1149 Assert(cacheId >= 0 && cacheId < SysCacheSize &&
(gdb)
输入参数:cacheId=42, key1=22952624, key2=23913368, key3=2200
其中key1->procedureName,key2->parameterTypes,key3->procNamespace
输入参数类型有3个,分别是23/1043/1043(inout参数)
(gdb) p (char *)22952624
$3 = 0x15e3ab0 "func_test"
(gdb) p ((oidvector *)23913368)[0]
$4 = {vl_len_ = 144, 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)
进入SearchCatCache3
(gdb) n
1151 Assert(SysCache[cacheId]->cc_nkeys == 3);
(gdb) n
1153 return SearchCatCache3(SysCache[cacheId], key1, key2, key3);
(gdb) step
SearchCatCache3 (cache=0x1639c80, v1=22952624, v2=23913368, v3=2200) at catcache.c:1183
1183 return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
(gdb)
进入SearchCatCacheInternal
(gdb) step
SearchCatCacheInternal (cache=0x1639c80, nkeys=3, v1=22952624, v2=23913368, v3=2200, v4=0)
at catcache.c:1213
1213 Assert(IsTransactionState());
(gdb)
cache信息
(gdb) n
1215 Assert(cache->cc_nkeys == nkeys);
(gdb) p *cache
$13 = {id = 42, cc_nbuckets = 128, cc_tupdesc = 0x7f8159216ef8, cc_bucket = 0x163a160,
cc_hashfunc = {0xa48129 <namehashfast>, 0xa48257 <oidvectorhashfast>,
0xa481b0 <int4hashfast>, 0x0}, cc_fastequal = {0xa480ea <nameeqfast>,
0xa48222 <oidvectoreqfast>, 0xa48193 <int4eqfast>, 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 <nameeq>, 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 <oidvectoreq>,
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 <oideq>, 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 <return> to continue, or q <return> to quit---
fn_strict = false, fn_retset = false, fn_stats = 0 '\000', fn_extra = 0x0,
fn_mcxt = 0x0, fn_expr = 0x0}, sk_argument = 0}}}
(gdb)
pg_proc tuple描述符
(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' <repeats 60 times>}, atttypid = 26,
attstattarget = -1, attlen = 4, attnum = 1, attndims = 0, attcacheoff = 0, atttypmod = -1,
attbyval = true, attstorage = 112 'p', attalign = 105 'i', attnotnull = true,
atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attgenerated = 0 '\000',
attisdropped = false, attislocal = true, attinhcount = 0, attcollation = 0}
(gdb) p cache->cc_tupdesc->attrs[1]
$17 = {attrelid = 1255, attname = {data = "proname", '\000' <repeats 56 times>},
atttypid = 19, attstattarget = -1, attlen = 64, attnum = 2, attndims = 0, attcacheoff = 4,
atttypmod = -1, attbyval = false, attstorage = 112 'p', attalign = 99 'c',
attnotnull = true, atthasdef = false, atthasmissing = false, attidentity = 0 '\000',
attgenerated = 0 '\000', attisdropped = false, attislocal = true, attinhcount = 0,
attcollation = 950}
(gdb)
获取hash桶
(gdb) n
1220 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) n
1246 dlist_foreach(iter, bucket)
(gdb) p *bucket
$20 = {head = {prev = 0x7f815919d688, next = 0x7f815919d688}}
(gdb)
沿着hash桶中的链表查找
(gdb) n
1248 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) step
SearchCatCacheMiss (cache=0x1639c80, nkeys=3, hashValue=3879045281, hashIndex=33,
v1=22952624, v2=23913368, v3=2200, v4=0) at catcache.c:1327
1327 arguments[0] = v1;
(gdb)
如没有找到,则调用SearchCatCacheMiss,构建扫描键
(gdb) n
1328 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 <nameeq>, 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 <oidvectoreq>, 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 <oideq>, 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 <SearchCatCacheInternal+572>, fn_mcxt = 0x898, fn_expr = 0x0},
sk_argument = 0}
(gdb)
开始扫描
(gdb) n
1361 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)
成功,返回tuple
1425 return &ct->tuple;
(gdb)
(gdb) p *ct
$25 = {ct_magic = 1462113538, hash_value = 3879045281, keys = {140193522567236,
140193522567344, 2200, 0}, cache_elem = {prev = 0x163a370, next = 0x7f815919d688},
refcount = 1, dead = false, negative = false, tuple = {t_len = 488, t_self = {ip_blkid = {
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)
到此,相信大家对“分析PostgreSQL创建函数的过程”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:http://blog.itpub.net/6906/viewspace-2677810/