PostgreSQL 源码解读(203)- 查询#116(类型转换实现)

本节简单介绍了PostgreSQL中的类型转换的具体实现.

解析表达式,涉及不同数据类型时: 
1.如有相应类型的Operator定义(pg_operator),则尝试进行类型转换,否则报错; 
2.如有相应类型的转换规则,转换为目标类型后解析,否则报错.

一、数据结构

郑州不孕不育医院:http://jbk.39.net/yiyuanzaixian/zztjyy//

Form_pg_operator 
pg_operator中的定义,代码会其中的定义转换为FormData_pg_operator结构体

/* ---------------- *    pg_operator definition.  cpp turns this into *    typedef struct FormData_pg_operator * ---------------- */CATALOG(pg_operator,2617,OperatorRelationId){  Oid     oid;      /* oid */  /* name of operator */  NameData  oprname;  /* OID of namespace containing this oper */  Oid     oprnamespace BKI_DEFAULT(PGNSP);  /* operator owner */  Oid     oprowner BKI_DEFAULT(PGUID);  /* 'l', 'r', or 'b' */  char    oprkind BKI_DEFAULT(b);  /* can be used in merge join? */  bool    oprcanmerge BKI_DEFAULT(f);  /* can be used in hash join? */  bool    oprcanhash BKI_DEFAULT(f);  /* left arg type, or 0 if 'l' oprkind */  Oid     oprleft BKI_LOOKUP(pg_type);  /* right arg type, or 0 if 'r' oprkind */  Oid     oprright BKI_LOOKUP(pg_type);  /* result datatype */  Oid     oprresult BKI_LOOKUP(pg_type);  /* OID of commutator oper, or 0 if none */  Oid     oprcom BKI_DEFAULT(0) BKI_LOOKUP(pg_operator);  /* OID of negator oper, or 0 if none */  Oid     oprnegate BKI_DEFAULT(0) BKI_LOOKUP(pg_operator);  /* OID of underlying function */  regproc   oprcode BKI_LOOKUP(pg_proc);  /* OID of restriction estimator, or 0 */  regproc   oprrest BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);  /* OID of join estimator, or 0 */  regproc   oprjoin BKI_DEFAULT(-) BKI_LOOKUP(pg_proc);} FormData_pg_operator;/* ---------------- *    Form_pg_operator corresponds to a pointer to a tuple with *    the format of pg_operator relation. * ---------------- */typedef FormData_pg_operator *Form_pg_operator;

二、源码解读

coerce_type函数实现具体的类型转换.

/* * coerce_type() *    Convert an expression to a different type. * 类型转换 * * The caller should already have determined that the coercion is possible; * see can_coerce_type. * 调用者应确定转换是OK的. * * Normally, no coercion to a typmod (length) is performed here.  The caller * must call coerce_type_typmod as well, if a typmod constraint is wanted. * (But if the target type is a domain, it may internally contain a * typmod constraint, which will be applied ×××ide coerce_to_domain.) * In some cases pg_cast specifies a type coercion function that also * applies length conversion, and in those cases only, the result will * already be properly coerced to the specified typmod. * 通常来说,在这里不会执行转换为typmod(length)的操作. * * pstate is only used in the case that we are able to resolve the type of * a previously UNKNOWN Param.  It is okay to pass pstate = NULL if the * caller does not want type information updated for Params. * * Note: this function must not modify the given expression tree, only add * decoration on top of it.  See transformSetOperationTree, for example. */Node *coerce_type(ParseState *pstate, Node *node,      Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,      CoercionContext ccontext, CoercionForm cformat, int location){  Node     *result;//结果Node  CoercionPathType pathtype;  Oid     funcId;  if (targetTypeId == inputTypeId ||    node == NULL)  {    /* no conversion needed */    //不需要转换    return node;  }  if (targetTypeId == ANYOID ||    targetTypeId == ANYELEMENTOID ||    targetTypeId == ANYNONARRAYOID)  {    /*     * Assume can_coerce_type verified that implicit coercion is okay.     *     * Note: by returning the unmodified node here, we are saying that     * it's OK to treat an UNKNOWN constant as a valid input for a     * function accepting ANY, ANYELEMENT, or ANYNONARRAY.  This should be     * all right, since an UNKNOWN value is still a perfectly valid Datum.     *     * NB: we do NOT want a RelabelType here: the exposed type of the     * function argument must be its actual type, not the polymorphic     * pseudotype.     */    //目标类型可以为任意类型(ANYXXX)    return node;  }  if (targetTypeId == ANYARRAYOID ||    targetTypeId == ANYENUMOID ||    targetTypeId == ANYRANGEOID)  {    /*     * Assume can_coerce_type verified that implicit coercion is okay.     *     * These cases are unlike the ones above because the exposed type of     * the argument must be an actual array, enum, or range type.  In     * particular the argument must *not* be an UNKNOWN constant.  If it     * is, we just fall through; below, we'll call anyarray_in,     * anyenum_in, or anyrange_in, which will produce an error.  Also, if     * what we have is a domain over array, enum, or range, we have to     * relabel it to its base type.     *     * Note: currently, we can't actually see a domain-over-enum here,     * since the other functions in this file will not match such a     * parameter to ANYENUM.  But that should get changed eventually.     */    if (inputTypeId != UNKNOWNOID)    {      //获取基本类型      Oid     baseTypeId = getBaseType(inputTypeId);      if (baseTypeId != inputTypeId)      {        RelabelType *r = makeRelabelType((Expr *) node,                         baseTypeId, -1,                         InvalidOid,                         cformat);        r->location = location;        return (Node *) r;      }      /* Not a domain type, so return it as-is */      return node;    }  }  if (inputTypeId == UNKNOWNOID && IsA(node, Const))  {    //---------------- 输入类型为unknown并且是常量    /*     * Input is a string constant with previously undetermined type. Apply     * the target type's typinput function to it to produce a constant of     * the target type.     * 应用目标类型的typinput函数,生成目标类型常量     *     * NOTE: this case cannot be folded together with the other     * constant-input case, since the typinput function does not     * necessarily behave the same as a type conversion function. For     * example, int4's typinput function will reject "1.2", whereas     * float-to-int type conversion will round to integer.     *     * XXX if the typinput function is not immutable, we really ought to     * postpone evaluation of the function call until runtime. But there     * is no way to represent a typinput function call as an expression     * tree, because C-string values are not Datums. (XXX This *is*     * possible as of 7.3, do we want to do it?)     */    Const    *con = (Const *) node;//常量    Const    *newcon = makeNode(Const);//转换后逇常量    Oid     baseTypeId;//基本类型Oid    int32   baseTypeMod;//基本typmode    int32   inputTypeMod;//输入typmode    Type    baseType;//基本类型    ParseCallbackState pcbstate;//解析回调函数    /*     * If the target type is a domain, we want to call its base type's     * input routine, not domain_in().  This is to avoid premature failure     * when the domain applies a typmod: existing input routines follow     * implicit-coercion semantics for length checks, which is not always     * what we want here.  The needed check will be applied properly     * ×××ide coerce_to_domain().     */    baseTypeMod = targetTypeMod;    baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);    /*     * For most types we pass typmod -1 to the input routine, because     * existing input routines follow implicit-coercion semantics for     * length checks, which is not always what we want here.  Any length     * constraint will be applied later by our caller.  An exception     * however is the INTERVAL type, for which we *must* pass the typmod     * or it won't be able to obey the bizarre SQL-spec input rules. (Ugly     * as sin, but so is this part of the spec...)     */    if (baseTypeId == INTERVALOID)      inputTypeMod = baseTypeMod;    else      inputTypeMod = -1;    baseType = typeidType(baseTypeId);    //构造输出常量Const    newcon->consttype = baseTypeId;    newcon->consttypmod = inputTypeMod;    newcon->constcollid = typeTypeCollation(baseType);    newcon->constlen = typeLen(baseType);    newcon->constbyval = typeByVal(baseType);    newcon->constisnull = con->constisnull;    /*     * We use the original literal's location regardless of the position     * of the coercion.  This is a change from pre-9.2 behavior, meant to     * simplify life for pg_stat_statements.     */    //使用原始位置    newcon->location = con->location;    /*     * Set up to point at the constant's text if the input routine throws     * an error.     */    //如果报错,则指向该常量文本    setup_parser_errposition_callback(&pcbstate, pstate, con->location);    /*     * We assume here that UNKNOWN's internal representation is the same     * as CSTRING.     * 内部表示跟CSTRING一样     */    if (!con->constisnull)      newcon->constvalue = stringTypeDatum(baseType,                         DatumGetCString(con->constvalue),                         inputTypeMod);    else      newcon->constvalue = stringTypeDatum(baseType,                         NULL,                         inputTypeMod);    /*     * If it's a varlena value, force it to be in non-expanded     * (non-toasted) format; this avoids any possible dependency on     * external values and improves consistency of representation.     */    //如为可变长度值,则强制其为非扩展格式.    if (!con->constisnull && newcon->constlen == -1)      newcon->constvalue =        PointerGetDatum(PG_DETOAST_DATUM(newcon->constvalue));#ifdef RANDOMIZE_ALLOCATED_MEMORY    /*     * For pass-by-reference data types, repeat the conversion to see if     * the input function leaves any uninitialized bytes in the result. We     * can only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is     * enabled, so we don't bother testing otherwise.  The reason we don't     * want any ×××tability in the input function is that comparison of     * Const nodes relies on bytewise comparison of the datums, so if the     * input function leaves garbage then subexpressions that should be     * identical may not get recognized as such.  See pgsql-hackers     * discussion of 2008-04-04.     */    if (!con->constisnull && !newcon->constbyval)    {      Datum   val2;      val2 = stringTypeDatum(baseType,                   DatumGetCString(con->constvalue),                   inputTypeMod);      if (newcon->constlen == -1)        val2 = PointerGetDatum(PG_DETOAST_DATUM(val2));      if (!datumIsEqual(newcon->constvalue, val2, false, newcon->constlen))        elog(WARNING, "type %s has unstable input conversion for \"%s\"",           typeTypeName(baseType), DatumGetCString(con->constvalue));    }#endif    cancel_parser_errposition_callback(&pcbstate);    //结果Node    result = (Node *) newcon;    /* If target is a domain, apply constraints. */    if (baseTypeId != targetTypeId)      result = coerce_to_domain(result,                    baseTypeId, baseTypeMod,                    targetTypeId,                    ccontext, cformat, location,                    false);    ReleaseSysCache(baseType);    //返回    return result;  }  if (IsA(node, Param) &&    pstate != NULL && pstate->p_coerce_param_hook != NULL)  {    /*     * Allow the CoerceParamHook to decide what happens.  It can return a     * transformed node (very possibly the same Param node), or return     * NULL to indicate we should proceed with normal coercion.     */    result = pstate->p_coerce_param_hook(pstate,                       (Param *) node,                       targetTypeId,                       targetTypeMod,                       location);    if (result)      return result;  }  if (IsA(node, CollateExpr))  {    /*     * If we have a COLLATE clause, we have to push the coercion     * underneath the COLLATE.  This is really ugly, but there is little     * choice because the above hacks on Consts and Params wouldn't happen     * otherwise.  This kluge has consequences in coerce_to_target_type.     */    CollateExpr *coll = (CollateExpr *) node;    CollateExpr *newcoll = makeNode(CollateExpr);    newcoll->arg = (Expr *)      coerce_type(pstate, (Node *) coll->arg,            inputTypeId, targetTypeId, targetTypeMod,            ccontext, cformat, location);    newcoll->collOid = coll->collOid;    newcoll->location = coll->location;    return (Node *) newcoll;  }  pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,                   &funcId);  if (pathtype != COERCION_PATH_NONE)  {    if (pathtype != COERCION_PATH_RELABELTYPE)    {      /*       * Generate an expression tree representing run-time application       * of the conversion function.  If we are dealing with a domain       * target type, the conversion function will yield the base type,       * and we need to extract the correct typmod to use from the       * domain's typtypmod.       */      Oid     baseTypeId;      int32   baseTypeMod;      baseTypeMod = targetTypeMod;      baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);      result = build_coercion_expression(node, pathtype, funcId,                         baseTypeId, baseTypeMod,                         ccontext, cformat, location);      /*       * If domain, coerce to the domain type and relabel with domain       * type ID, hiding the previous coercion node.       */      if (targetTypeId != baseTypeId)        result = coerce_to_domain(result, baseTypeId, baseTypeMod,                      targetTypeId,                      ccontext, cformat, location,                      true);    }    else    {      /*       * We don't need to do a physical conversion, but we do need to       * attach a RelabelType node so that the expression will be seen       * to have the intended type when ×××pected by higher-level code.       *       * Also, doma××× may have value restrictions beyond the base type       * that must be accounted for.  If the destination is a domain       * then we won't need a RelabelType node.       */      result = coerce_to_domain(node, InvalidOid, -1, targetTypeId,                    ccontext, cformat, location,                    false);      if (result == node)      {        /*         * XXX could we label result with exprTypmod(node) ×××tead of         * default -1 typmod, to save a possible length-coercion         * later? Would work if both types have same interpretation of         * typmod, which is likely but not certain.         */        RelabelType *r = makeRelabelType((Expr *) result,                         targetTypeId, -1,                         InvalidOid,                         cformat);        r->location = location;        result = (Node *) r;      }    }    return result;  }  if (inputTypeId == RECORDOID &&    ISCOMPLEX(targetTypeId))  {    /* Coerce a RECORD to a specific complex type */    return coerce_record_to_complex(pstate, node, targetTypeId,                    ccontext, cformat, location);  }  if (targetTypeId == RECORDOID &&    ISCOMPLEX(inputTypeId))  {    /* Coerce a specific complex type to RECORD */    /* NB: we do NOT want a RelabelType here */    return node;  }#ifdef NOT_USED  if (inputTypeId == RECORDARRAYOID &&    is_complex_array(targetTypeId))  {    /* Coerce record[] to a specific complex array type */    /* not implemented yet ... */  }#endif  if (targetTypeId == RECORDARRAYOID &&    is_complex_array(inputTypeId))  {    /* Coerce a specific complex array type to record[] */    /* NB: we do NOT want a RelabelType here */    return node;  }  if (typeInheritsFrom(inputTypeId, targetTypeId)    || typeIsOfTypedTable(inputTypeId, targetTypeId))  {    /*     * Input class type is a subclass of target, so generate an     * appropriate runtime conversion (removing unneeded columns and     * possibly rearranging the ones that are wanted).     *     * We will also get here when the input is a domain over a subclass of     * the target type.  To keep life simple for the executor, we define     * ConvertRowtypeExpr as only working between regular composite types;     * therefore, in such cases ×××ert a RelabelType to smash the input     * expression down to its base type.     */    Oid     baseTypeId = getBaseType(inputTypeId);    ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);    if (baseTypeId != inputTypeId)    {      RelabelType *rt = makeRelabelType((Expr *) node,                        baseTypeId, -1,                        InvalidOid,                        COERCE_IMPLICIT_CAST);      rt->location = location;      node = (Node *) rt;    }    r->arg = (Expr *) node;    r->resulttype = targetTypeId;    r->convertformat = cformat;    r->location = location;    return (Node *) r;  }  /* If we get here, caller blew it */  elog(ERROR, "failed to find conversion function from %s to %s",     format_type_be(inputTypeId), format_type_be(targetTypeId));  return NULL;        /* keep compiler quiet */}/* * Given a type structure and a string, returns the internal representation * of that string.  The "string" can be NULL to perform conversion of a NULL * (which might result in failure, if the input function rejects NULLs). */DatumstringTypeDatum(Type tp, char *string, int32 atttypmod){  Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);  Oid     typinput = typform->typinput;  Oid     typioparam = getTypeIOParam(tp);  //调用函数进行转换  return OidInputFunctionCall(typinput, string, typioparam, atttypmod);}/* * As above, for I/O functions identified by OID.  These are only to be used * in seldom-executed code paths.  They are not only slow but leak memory. */DatumOidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod){  FmgrInfo  flinfo;  //构造函数调用参数  fmgr_info(functionId, &flinfo);  return InputFunctionCall(&flinfo, str, typioparam, typmod);}/* * Call a previously-looked-up datatype input function. * * "str" may be NULL to indicate we are reading a NULL.  In this case * the caller should assume the result is NULL, but we'll call the input * function anyway if it's not strict.  So this is almost but not quite * the same as FunctionCall3. */DatumInputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod){  LOCAL_FCINFO(fcinfo, 3);  Datum   result;  if (str == NULL && flinfo->fn_strict)    return (Datum) 0;   /* just return null result */  InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);  fcinfo->args[0].value = CStringGetDatum(str);  fcinfo->args[0].isnull = false;  fcinfo->args[1].value = ObjectIdGetDatum(typioparam);  fcinfo->args[1].isnull = false;  fcinfo->args[2].value = Int32GetDatum(typmod);  fcinfo->args[2].isnull = false;  //调用函数  result = FunctionCallInvoke(fcinfo);  /* Should get null result if and only if str is NULL */  if (str == NULL)  {    if (!fcinfo->isnull)      elog(ERROR, "input function %u returned non-NULL",         flinfo->fn_oid);  }  else  {    if (fcinfo->isnull)      elog(ERROR, "input function %u returned NULL",         flinfo->fn_oid);  }  return result;}/* *    int4in      - converts "num" to int4 */Datumint4in(PG_FUNCTION_ARGS){  char     *num = PG_GETARG_CSTRING(0);  PG_RETURN_INT32(pg_strtoint32(num));}/* * Convert input string to a signed 32 bit integer. * * Allows any number of leading or trailing whitespace characters. Will throw * ereport() upon bad input format or overflow. * * NB: Accumulate input as a negative number, to deal with two's complement * representation of the most negative number, which can't be represented as a * positive number. */int32pg_strtoint32(const char *s){  const char *ptr = s;  int32   tmp = 0;  bool    neg = false;  /* skip leading spaces */  while (likely(*ptr) && isspace((unsigned char) *ptr))    ptr++;  /* handle sign */  if (*ptr == '-')  {    ptr++;    neg = true;  }  else if (*ptr == '+')    ptr++;  /* require at least one digit */  if (unlikely(!isdigit((unsigned char) *ptr)))    goto invalid_syntax;  /* process digits */  while (*ptr && isdigit((unsigned char) *ptr))//如'123',-1->-12->-123  {    int8    digit = (*ptr++ - '0');//获取数字    if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||//tmp*10      unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))//tmp - digit      goto out_of_range;  }  /* allow trailing whitespace, but not other trailing chars */  while (*ptr != '\0' && isspace((unsigned char) *ptr))    ptr++;  if (unlikely(*ptr != '\0'))    goto invalid_syntax;  if (!neg)  {    /* could fail if input is most negative number */    if (unlikely(tmp == PG_INT32_MIN))      goto out_of_range;    tmp = -tmp;//符号取反,-123->123  }  return tmp;out_of_range:  ereport(ERROR,      (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),       errmsg("value \"%s\" is out of range for type %s",          s, "integer")));invalid_syntax:  ereport(ERROR,      (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),       errmsg("invalid input syntax for type %s: \"%s\"",          "integer", s)));  return 0;     /* keep compiler quiet */}

三、跟踪分析

郑州不孕不育医院:http://jbk.39.net/yiyuanzaixian/zztjyy//

SQL脚本

testdb=# select * from t_conv where id = '1';

跟踪分析

(gdb) b coerce_typeBreakpoint 1 at 0x6055f0: file parse_coerce.c, line 164.(gdb) cContinuing.Breakpoint 1, coerce_type (pstate=0x2c89e30, node=0x2c8a678, inputTypeId=705, targetTypeId=23, targetTypeMod=-1,     ccontext=COERCION_IMPLICIT, cformat=COERCE_IMPLICIT_CAST, location=-1) at parse_coerce.c:164164   if (targetTypeId == inputTypeId ||(gdb)

输入参数,输入类型ID为705(unknown),目标类型为23(int4)

(gdb) p *pstate$1 = {parentParseState = 0x0, p_sourcetext = 0x2c88e08 "select * from t_conv where id = '1';", p_rtable = 0x2c8a2a0,   p_joinexprs = 0x0, p_joinlist = 0x2c8a3a8, p_namespace = 0x2c8a328, 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_×××ert = false,   p_windowdefs = 0x0, p_expr_kind = EXPR_KIND_WHERE, p_next_resno = 2, 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 *node$2 = {type = T_Const}(gdb) p *(Const *)node$3 = {xpr = {type = T_Const}, consttype = 705, consttypmod = -1, constcollid = 0, constlen = -2, constvalue = 46701384,   constisnull = false, constbyval = false, location = 32}(gdb) x/1cb 467013840x2c89b48:  49 '1'(gdb)

进入常量转换分支

(gdb) n170   if (targetTypeId == ANYOID ||(gdb) 171     targetTypeId == ANYELEMENTOID ||(gdb) 188   if (targetTypeId == ANYARRAYOID ||(gdb) 189     targetTypeId == ANYENUMOID ||(gdb) 225   if (inputTypeId == UNKNOWNOID && IsA(node, Const))(gdb) 244     Const    *con = (Const *) node;(gdb) 245     Const    *newcon = makeNode(Const);(gdb) 260     baseTypeMod = targetTypeMod;(gdb) p *con$4 = {xpr = {type = T_Const}, consttype = 705, consttypmod = -1, constcollid = 0, constlen = -2, constvalue = 46701384,   constisnull = false, constbyval = false, location = 32}(gdb) n261     baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);(gdb) 272     if (baseTypeId == INTERVALOID)(gdb) 275       inputTypeMod = -1;(gdb) 277     baseType = typeidType(baseTypeId);(gdb) 279     newcon->consttype = baseTypeId;(gdb) 280     newcon->consttypmod = inputTypeMod;(gdb) 281     newcon->constcollid = typeTypeCollation(baseType);(gdb) 282     newcon->constlen = typeLen(baseType);(gdb) 283     newcon->constbyval = typeByVal(baseType);(gdb) 284     newcon->constisnull = con->constisnull;(gdb) 291     newcon->location = con->location;(gdb) 297     setup_parser_errposition_callback(&pcbstate, pstate, con->location);(gdb) p  *newcon$5 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 0,   constisnull = false, constbyval = true, location = 32}(gdb)

完成转换

(gdb) n303     if (!con->constisnull)(gdb) 305                          DatumGetCString(con->constvalue),(gdb) 304       newcon->constvalue = stringTypeDatum(baseType,(gdb) 317     if (!con->constisnull && newcon->constlen == -1)(gdb) 349     cancel_parser_errposition_callback(&pcbstate);(gdb) 351     result = (Node *) newcon;(gdb) p *newcon$6 = {xpr = {type = T_Const}, consttype = 23, consttypmod = -1, constcollid = 0, constlen = 4, constvalue = 1,   constisnull = false, constbyval = true, location = 32}(gdb) n354     if (baseTypeId != targetTypeId)(gdb) 361     ReleaseSysCache(baseType);(gdb) 363     return result;(gdb)

转换的实现 
跟踪InputFunctionCall

(gdb) b InputFunctionCallBreakpoint 2 at 0xa6fabe: file fmgr.c, line 1533.(gdb) cContinuing.Breakpoint 2, InputFunctionCall (flinfo=0x7ffd8b1da1f0, str=0x2c89b48 "1", typioparam=23, typmod=-1) at fmgr.c:15331533    LOCAL_FCINFO(fcinfo, 3);(gdb) n1536    if (str == NULL && flinfo->fn_strict)(gdb) 1539    InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);(gdb) 1541    fcinfo->args[0].value = CStringGetDatum(str);(gdb) 1542    fcinfo->args[0].isnull = false;(gdb) 1543    fcinfo->args[1].value = ObjectIdGetDatum(typioparam);(gdb) 1544    fcinfo->args[1].isnull = false;(gdb) 1545    fcinfo->args[2].value = Int32GetDatum(typmod);(gdb) 1546    fcinfo->args[2].isnull = false;(gdb) 1548    result = FunctionCallInvoke(fcinfo);(gdb) p *fcinfo$7 = {flinfo = 0x7ffd8b1da1f0, context = 0x0, resultinfo = 0x0, fncollation = 0, isnull = false, nargs = 3,   args = 0x7ffd8b1da180}(gdb) p *fcinfo->flinfo$8 = {fn_addr = 0x9694fc <int4in>, fn_oid = 42, fn_nargs = 1, fn_strict = true, fn_retset = false, fn_stats = 2 '\002',   fn_extra = 0x0, fn_mcxt = 0x2c88cf0, fn_expr = 0x0}(gdb)

实现函数是int4in->pg_strtoint32

(gdb) b pg_strtoint32Breakpoint 3 at 0x9b8b45: file numutils.c, line 201.(gdb) cContinuing.Breakpoint 3, pg_strtoint32 (s=0x2c89b48 "123") at numutils.c:201201   const char *ptr = s;(gdb) n202   int32   tmp = 0;(gdb) 203   bool    neg = false;(gdb) 206   while (likely(*ptr) && isspace((unsigned char) *ptr))(gdb) 210   if (*ptr == '-')(gdb) 215   else if (*ptr == '+')(gdb) 219   if (unlikely(!isdigit((unsigned char) *ptr)))(gdb) 223   while (*ptr && isdigit((unsigned char) *ptr))(gdb) 225     int8    digit = (*ptr++ - '0');(gdb) 227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p digit$9 = 1 '\001'(gdb) n228       unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))(gdb) p tmp$10 = 0(gdb) n227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p tmp$11 = -1(gdb) n223   while (*ptr && isdigit((unsigned char) *ptr))(gdb) p tmp$12 = -1(gdb) n225     int8    digit = (*ptr++ - '0');(gdb) 227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p digit$13 = 2 '\002'(gdb) n228       unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))(gdb) 227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p tmp$14 = -12(gdb) n223   while (*ptr && isdigit((unsigned char) *ptr))(gdb) 225     int8    digit = (*ptr++ - '0');(gdb) 227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p digit$15 = 3 '\003'(gdb) n228       unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))(gdb) 227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||(gdb) p tmp$16 = -123(gdb) n223   while (*ptr && isdigit((unsigned char) *ptr))(gdb) 233   while (*ptr != '\0' && isspace((unsigned char) *ptr))(gdb) 236   if (unlikely(*ptr != '\0'))(gdb) 239   if (!neg)(gdb) 242     if (unlikely(tmp == PG_INT32_MIN))(gdb) p tmp$17 = -123(gdb) n244     tmp = -tmp;(gdb) 247   return tmp;


猜你喜欢

转载自blog.51cto.com/14393777/2409355