91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PostgreSQL 源碼解讀(242)- plpgsql(CreateFunction-compute_function_attributes)

發布時間:2020-08-04 21:18:33 來源:ITPUB博客 閱讀:255 作者:husthxd 欄目:關系型數據庫

本節簡單介紹了PostgreSQL創建函數的過程,其實現函數是CreateFunction。

一、數據結構

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;

二、源碼解讀


/*
 * Dissect the list of options assembled in gram.y into function
 * attributes.
 * 解析集成在gram.y中的選項鏈表為函數屬性
 */
static void
compute_function_attributes(ParseState *pstate,//解析狀態結構體
              bool is_procedure,//是否過程?
              List *options,//選項鏈表(stmt->options)
              List **as,//as語句
              char **language,//語言
              Node **transform,//
              bool *windowfunc_p,//是否窗口函數
              char *volatility_p,//是否易變函數
              bool *strict_p,//是否嚴格
              bool *security_definer,//安全定義
              bool *leakproof_p,//是否leakproof
              ArrayType **proconfig,//過程配置信息
              float4 *procost,//過程成本
              float4 *prorows,//涉及的行數
              Oid *prosupport,//
              char *parallel_p)
{
  ListCell   *option;//臨時變量
  DefElem    *as_item = NULL;
  DefElem    *language_item = NULL;
  DefElem    *transform_item = NULL;
  DefElem    *windowfunc_item = NULL;
  DefElem    *volatility_item = NULL;
  DefElem    *strict_item = NULL;
  DefElem    *security_item = NULL;
  DefElem    *leakproof_item = NULL;
  List     *set_items = NIL;
  DefElem    *cost_item = NULL;
  DefElem    *rows_item = NULL;
  DefElem    *support_item = NULL;
  DefElem    *parallel_item = NULL;
  foreach(option, options)//循環處理
  {
    //獲取定義的元素信息
    DefElem    *defel = (DefElem *) lfirst(option);
    if (strcmp(defel->defname, "as") == 0)
    {
      //as
      if (as_item)
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("conflicting or redundant options"),
             parser_errposition(pstate, defel->location)));
      as_item = defel;
    }
    else if (strcmp(defel->defname, "language") == 0)
    {
      //language
      if (language_item)
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("conflicting or redundant options"),
             parser_errposition(pstate, defel->location)));
      language_item = defel;
    }
    else if (strcmp(defel->defname, "transform") == 0)
    {
      //transform
      if (transform_item)
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("conflicting or redundant options"),
             parser_errposition(pstate, defel->location)));
      transform_item = defel;
    }
    else if (strcmp(defel->defname, "window") == 0)
    {
      //窗口函數
      if (windowfunc_item)
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("conflicting or redundant options"),
             parser_errposition(pstate, defel->location)));
      if (is_procedure)
        ereport(ERROR,
            (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
             errmsg("invalid attribute in procedure definition"),
             parser_errposition(pstate, defel->location)));
      windowfunc_item = defel;
    }
    else if (compute_common_attribute(pstate,
                      is_procedure,
                      defel,
                      &volatility_item,
                      &strict_item,
                      &security_item,
                      &leakproof_item,
                      &set_items,
                      &cost_item,
                      &rows_item,
                      &support_item,
                      &parallel_item))//普通屬性
    {
      /* recognized common option */
      //識別可以同時傳遞給CREATE FUNCTION和ALTER FUNCTION的選項,并通過out參數返回
      continue;
    }
    else
      elog(ERROR, "option \"%s\" not recognized",
         defel->defname);
  }
  /* process required items */
  if (as_item)
    //必選項:函數體
    *as = (List *) as_item->arg;
  else
  {
    ereport(ERROR,
        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
         errmsg("no function body specified")));
    *as = NIL;        /* keep compiler quiet */
  }
  if (language_item)
    //必選項:語言
    *language = strVal(language_item->arg);
  else
  {
    ereport(ERROR,
        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
         errmsg("no language specified")));
    *language = NULL;   /* keep compiler quiet */
  }
  /* process optional items */
  //可選項
  if (transform_item)
    *transform = transform_item->arg;
  if (windowfunc_item)
    *windowfunc_p = intVal(windowfunc_item->arg);
  if (volatility_item)
    *volatility_p = interpret_func_volatility(volatility_item);
  if (strict_item)
    *strict_p = intVal(strict_item->arg);
  if (security_item)
    *security_definer = intVal(security_item->arg);
  if (leakproof_item)
    *leakproof_p = intVal(leakproof_item->arg);
  if (set_items)
    *proconfig = update_proconfig_value(NULL, set_items);
  if (cost_item)
  {
    *procost = defGetNumeric(cost_item);
    if (*procost <= 0)
      ereport(ERROR,
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
           errmsg("COST must be positive")));
  }
  if (rows_item)
  {
    *prorows = defGetNumeric(rows_item);
    if (*prorows <= 0)
      ereport(ERROR,
          (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
           errmsg("ROWS must be positive")));
  }
  if (support_item)
    *prosupport = interpret_func_support(support_item);
  if (parallel_item)
    *parallel_p = interpret_func_parallel(parallel_item);
}
/*
 * Recognize one of the options that can be passed to both CREATE
 * FUNCTION and ALTER FUNCTION and return it via one of the out
 * parameters. Returns true if the passed option was recognized. If
 * the out parameter we were going to assign to points to non-NULL,
 * raise a duplicate-clause error.  (We don't try to detect duplicate
 * SET parameters though --- if you're redundant, the last one wins.)
 * 識別可以同時傳遞給CREATE FUNCTION和ALTER FUNCTION的選項,并通過out參數返回
 */
static bool
compute_common_attribute(ParseState *pstate,
             bool is_procedure,
             DefElem *defel,
             DefElem **volatility_item,
             DefElem **strict_item,
             DefElem **security_item,
             DefElem **leakproof_item,
             List **set_items,
             DefElem **cost_item,
             DefElem **rows_item,
             DefElem **support_item,
             DefElem **parallel_item)
{
  //----------- 逐個判斷賦值
  if (strcmp(defel->defname, "volatility") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*volatility_item)
      goto duplicate_error;
    *volatility_item = defel;
  }
  else if (strcmp(defel->defname, "strict") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*strict_item)
      goto duplicate_error;
    *strict_item = defel;
  }
  else if (strcmp(defel->defname, "security") == 0)
  {
    if (*security_item)
      goto duplicate_error;
    *security_item = defel;
  }
  else if (strcmp(defel->defname, "leakproof") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*leakproof_item)
      goto duplicate_error;
    *leakproof_item = defel;
  }
  else if (strcmp(defel->defname, "set") == 0)
  {
    *set_items = lappend(*set_items, defel->arg);
  }
  else if (strcmp(defel->defname, "cost") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*cost_item)
      goto duplicate_error;
    *cost_item = defel;
  }
  else if (strcmp(defel->defname, "rows") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*rows_item)
      goto duplicate_error;
    *rows_item = defel;
  }
  else if (strcmp(defel->defname, "support") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*support_item)
      goto duplicate_error;
    *support_item = defel;
  }
  else if (strcmp(defel->defname, "parallel") == 0)
  {
    if (is_procedure)
      goto procedure_error;
    if (*parallel_item)
      goto duplicate_error;
    *parallel_item = defel;
  }
  else
    return false;
  /* Recognized an option */
  return true;
duplicate_error:
  ereport(ERROR,
      (errcode(ERRCODE_SYNTAX_ERROR),
       errmsg("conflicting or redundant options"),
       parser_errposition(pstate, defel->location)));
  return false;       /* keep compiler quiet */
procedure_error:
  ereport(ERROR,
      (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
       errmsg("invalid attribute in procedure definition"),
       parser_errposition(pstate, defel->location)));
  return false;
}

三、跟蹤分析

測試腳本


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 compute_function_attributes
Breakpoint 1 at 0x6702b7: file functioncmds.c, line 711.
(gdb) c
Continuing.
Breakpoint 1, compute_function_attributes (pstate=0x1dd4c88, is_procedure=false, 
    options=0x1daf7e8, as=0x7ffd231851d8, language=0x7ffd23185240, 
    transform=0x7ffd23185238, windowfunc_p=0x7ffd231851ff, volatility_p=0x7ffd231851fb "v", 
    strict_p=0x7ffd231851fe, security_definer=0x7ffd231851fd, leakproof_p=0x7ffd231851fc, 
    proconfig=0x7ffd231851f0, procost=0x7ffd231851ec, prorows=0x7ffd231851e8, 
    prosupport=0x7ffd231851e4, parallel_p=0x7ffd231851d7 "u") at functioncmds.c:711
711   DefElem    *as_item = NULL;

輸入參數

(gdb) p *pstate
$1 = {parentParseState = 0x0, 
  p_sourcetext = 0x1daded8 "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) p is_procedure
$2 = false

SQL語句的選項#1(as語句)

(gdb) p *options
$3 = {type = T_List, length = 2, head = 0x1daf7c0, tail = 0x1daf8a0}
(gdb) p *(Node *)options->head->data.ptr_value
$4 = {type = T_DefElem}
(gdb) p *(DefElem *)options->head->data.ptr_value
$5 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x1daf730, 
  defaction = DEFELEM_UNSPEC, location = 134}
(gdb) set $defelem=(DefElem *)options->head->data.ptr_value
(gdb) p $defelem->arg
$6 = (Node *) 0x1daf730
(gdb) p *(Node *)$defelem->arg
$7 = {type = T_List}
(gdb) p *(List *)$defelem->arg
$8 = {type = T_List, length = 1, head = 0x1daf708, tail = 0x1daf708}
(gdb) set $arg=(List *)$defelem->arg
(gdb) p *(Node *)$arg->head->data.ptr_value
$9 = {type = T_String}
(gdb) p *(Value *)$arg->head->data.ptr_value
$11 = {type = T_String, val = {ival = 31126984, 
    str = 0x1daf5c8 "\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"}}

SQL語句的選項#2(語言)

(gdb) set $defelem2=(DefElem *)options->head->next->data.ptr_value
(gdb) p *$defelem2
$13 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbfcbe "language", 
  arg = 0x1daf820, defaction = DEFELEM_UNSPEC, location = 298}
(gdb) p *$defelem2->arg
$14 = {type = T_String}
(gdb) p *(Value *)$defelem2->arg
$15 = {type = T_String, val = {ival = 31126952, str = 0x1daf5a8 "plpgsql"}}
(gdb)

提取as_item和language_item

(gdb) n
712   DefElem    *language_item = NULL;
(gdb) n
713   DefElem    *transform_item = NULL;
(gdb) 
714   DefElem    *windowfunc_item = NULL;
(gdb) 
715   DefElem    *volatility_item = NULL;
(gdb) 
716   DefElem    *strict_item = NULL;
(gdb) 
717   DefElem    *security_item = NULL;
(gdb) 
718   DefElem    *leakproof_item = NULL;
(gdb) 
719   List     *set_items = NIL;
(gdb) 
720   DefElem    *cost_item = NULL;
(gdb) 
721   DefElem    *rows_item = NULL;
(gdb) 
722   DefElem    *support_item = NULL;
(gdb) 
723   DefElem    *parallel_item = NULL;
(gdb) 
725   foreach(option, options)
(gdb) 
727     DefElem    *defel = (DefElem *) lfirst(option);
(gdb) 
729     if (strcmp(defel->defname, "as") == 0)
(gdb) 
731       if (as_item)
(gdb) 
736       as_item = defel;
(gdb) 
725   foreach(option, options)
(gdb) p *as_item
$16 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x1daf730, 
  defaction = DEFELEM_UNSPEC, location = 134}
(gdb) n
727     DefElem    *defel = (DefElem *) lfirst(option);
(gdb) 
729     if (strcmp(defel->defname, "as") == 0)
(gdb) 
738     else if (strcmp(defel->defname, "language") == 0)
(gdb) 
740       if (language_item)
(gdb) 
745       language_item = defel;
(gdb) 
725   foreach(option, options)
(gdb) p *language_item
$17 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbfcbe "language", 
  arg = 0x1daf820, defaction = DEFELEM_UNSPEC, location = 298}
(gdb) n
792   if (as_item)

提取item中的arg

(gdb) n
793     *as = (List *) as_item->arg;
(gdb) 
802   if (language_item)
(gdb) p *as
$18 = (List *) 0x1daf730
(gdb) n
803     *language = strVal(language_item->arg);
(gdb) 
813   if (transform_item)
(gdb) p *language
$19 = 0x1daf5a8 "plpgsql"
(gdb) n
815   if (windowfunc_item)
(gdb) 
817   if (volatility_item)
(gdb) 
819   if (strict_item)
(gdb) 
821   if (security_item)
(gdb) 
823   if (leakproof_item)
(gdb) 
825   if (set_items)
(gdb) 
827   if (cost_item)
(gdb) 
835   if (rows_item)
(gdb) 
843   if (support_item)
(gdb) 
845   if (parallel_item)
(gdb) 
847 }
(gdb) 
CreateFunction (pstate=0x1dd4c88, stmt=0x1daf8c8) at functioncmds.c:989
989   languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));

DONE!

四、參考資料

N/A

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

嘉峪关市| 长治县| 都江堰市| 双峰县| 大新县| 皋兰县| 醴陵市| 喀喇沁旗| 清水县| 神农架林区| 嵊州市| 鹿泉市| 夹江县| 偏关县| 凤凰县| 台东市| 衡阳市| 文山县| 莫力| 高阳县| 利津县| 武威市| 大埔区| 邯郸县| 二连浩特市| 麻城市| 光山县| 桐柏县| 临澧县| 法库县| 顺平县| 河西区| 临沧市| 登封市| 灵石县| 白沙| 镇雄县| 禹城市| 磴口县| 宁南县| 宝应县|