分析PostgreSQL创建函数的过程

技术分析PostgreSQL创建函数的过程本篇内容主要讲解“分析PostgreSQL创建函数的过程”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析PostgreSQL创建函

本篇内容主要讲解"分析一种数据库系统创建函数的过程",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"分析一种数据库系统创建函数的过程"吧!

一、数据结构

Form_pg_language

plpgsql语言定义结构体

/* -

* pg _语言定义。cpptunthistinto

* typedefstructFormData _ pg _ language

* -

*/

目录(pg_language,2612,LanguageRelationId)

{

Oidoid/*oid*/

/*语言名称*/

名称数据名称;

/*语言所有者*/

oitlanownerbki _ DEFAULT(PGUID);

/*是程序语言*/

boollanilsbki _ DEFAULT(f);

/*PListrusted*/

boollanluplustrustedbki _ DEFAULT(f);

/*Callhandler,ifit'saPL*/

OidlanplcallfoidBKI _ DEFAULT(0)BKI _ LOOKUP(pg _ proc);

/* Optionalanonymous-块处理函数*/

BKI查找(pg _ proc);

/*Optionalvalidationfunction*/

BKI _查找(pg _ proc);

# ifdefCATALOG _ VARLEN/*可变长度字段状态re */

/*访问权限

ges */
    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创建函数的过程”有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/71159.html

(0)

相关推荐

  • 周记可以写什么,《周记》有哪些题材可写

    技术周记可以写什么,《周记》有哪些题材可写可以写关于一笔电影的观后感,不要太过重去描绘故事情节,要重写自己的感觉和看方法,很多道理都可从电影中发掘出来的周记可以写什么。可以写跟你家人的情感问题,如果吵架的话可以从另一个角

    生活 2021年10月25日
  • 利用socket实现一个简单的web聊天(websocket服务器开源)

    技术如何分析基于WebSocket的聊天开源项目如何分析基于WebSocket的聊天开源项目,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。如果你是站长,是否

    攻略 2021年12月24日
  • python虚拟环境怎么用

    技术python虚拟环境怎么用小编给大家分享一下python虚拟环境怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!virtualenvv

    攻略 2021年11月24日
  • 轻量云服务器有什么优势

    技术轻量云服务器有什么优势随着现在对于云服务器的使用门槛不断降低,不少机房服务商都推出了自己的轻量云服务器,而相比云服务器,轻量云服务器的优势主要是入门简单,使用便捷,单击鼠标即可快速搭建云端环境或构建应用,开箱即用,那

    礼包 2021年12月10日
  • 黑色上衣配什么颜色的裤子好看,黑色上衣配什么颜色裤子好看

    技术黑色上衣配什么颜色的裤子好看,黑色上衣配什么颜色裤子好看虽然已经是夏天,天气炎热,但是还是有很多人喜欢穿黑色,如果说黑色的裤子倒还是百搭的如果是上衣应该怎么搭配呢黑色上衣配什么颜色的裤子好看?男装黑色上衣大多会搭配牛

    生活 2021年10月21日
  • 怎么解决Java中的Type definition error问题

    技术怎么解决Java中的Type definition error问题本篇内容主要讲解“怎么解决Java中的Type definition error问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。

    攻略 2021年11月16日