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

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

一、数据结构

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 inside 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;//结果NodeCoercionPathType 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;//基本类型Oidint32   baseTypeMod;//基本typmodeint32   inputTypeMod;//输入typmodeType    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* inside 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;elseinputTypeMod = -1;baseType = typeidType(baseTypeId);//构造输出常量Constnewcon->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);elsenewcon->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 instability 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));}
#endifcancel_parser_errposition_callback(&pcbstate);//结果Noderesult = (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 inspected by higher-level code.** Also, domains 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) instead 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_USEDif (inputTypeId == RECORDARRAYOID &&is_complex_array(targetTypeId)){/* Coerce record[] to a specific complex array type *//* not implemented yet ... */}
#endifif (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 insert 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).*/
Datum
stringTypeDatum(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.*/
Datum
OidInputFunctionCall(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.*/
Datum
InputFunctionCall(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*/
Datum
int4in(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.*/
int32
pg_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*10unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))//tmp - digitgoto 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 */
}

三、跟踪分析

SQL脚本


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

跟踪分析


(gdb) b coerce_type
Breakpoint 1 at 0x6055f0: file parse_coerce.c, line 164.
(gdb) c
Continuing.
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:164
164   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_insert = 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 46701384
0x2c89b48:  49 '1'
(gdb)

进入常量转换分支


(gdb) n
170   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) n
261     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) n
303     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) n
354     if (baseTypeId != targetTypeId)
(gdb)
361     ReleaseSysCache(baseType);
(gdb)
363     return result;
(gdb)

转换的实现
跟踪InputFunctionCall


(gdb) b InputFunctionCall
Breakpoint 2 at 0xa6fabe: file fmgr.c, line 1533.
(gdb) c
Continuing.
Breakpoint 2, InputFunctionCall (flinfo=0x7ffd8b1da1f0, str=0x2c89b48 "1", typioparam=23, typmod=-1) at fmgr.c:1533
1533    LOCAL_FCINFO(fcinfo, 3);
(gdb) n
1536    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_strtoint32
Breakpoint 3 at 0x9b8b45: file numutils.c, line 201.
(gdb) c
Continuing.
Breakpoint 3, pg_strtoint32 (s=0x2c89b48 "123") at numutils.c:201
201   const char *ptr = s;
(gdb) n
202   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) n
228       unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))
(gdb) p tmp
$10 = 0
(gdb) n
227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||
(gdb) p tmp
$11 = -1
(gdb) n
223   while (*ptr && isdigit((unsigned char) *ptr))
(gdb) p tmp
$12 = -1
(gdb) n
225     int8    digit = (*ptr++ - '0');
(gdb)
227     if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||
(gdb) p digit
$13 = 2 '\002'
(gdb) n
228       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) n
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
$15 = 3 '\003'
(gdb) n
228       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) n
223   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) n
244     tmp = -tmp;
(gdb)
247   return tmp;

DONE!

四、参考资料

PostgreSQL Type Conversion
PostgreSQL数据类型转换规则#1
PostgreSQL数据类型转换规则#2
PostgreSQL数据类型转换规则#3

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2647659/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/6906/viewspace-2647659/

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

  1. PostgreSQL 源码解读(160)- 查询#80(如何实现表达式解析)

    本节介绍了PostgreSQL如何解析查询语句中的表达式列并计算得出该列的值.表达式列是指除关系定义中的系统列/定义列之外的其他投影列.比如: testdb=# create table t_expr ...

  2. PostgreSQL 源码解读(31)- 查询语句#16(查询优化-表达式预处理#1)

    本节简单介绍了PG查询优化对表达式预处理中连接Var(RTE中的Var,其中RTE_KIND=RTE_JOIN)溯源的过程.处理逻辑在主函数subquery_planner中通过调用flatten_j ...

  3. PostgreSQL 源码解读(35)- 查询语句#20(查询优化-简化Having和Grou...

    本节简单介绍了PG查询优化中对Having和Group By子句的简化处理. 一.基本概念 简化Having语句 把Having中的约束条件,如满足可以提升到Where条件中的,则移动到Where子句 ...

  4. PostgreSQL 源码解读(32)- 查询语句#17(查询优化-表达式预处理#2)

    本节简单介绍了PG查询优化表达式预处理中常量的简化过程.表达式预处理主要的函数主要有preprocess_expression和preprocess_qual_conditions(调用preproc ...

  5. PostgreSQL 源码解读(153)- 后台进程#5(walsender#1)

    本节简单介绍了PostgreSQL的后台进程walsender,该进程实质上是streaming replication环境中master节点上普通的backend进程,在standby节点启动时,s ...

  6. PostgreSQL 源码解读(147)- Storage Manager#3(fsm_search函数)

    本节简单介绍了PostgreSQL在执行插入过程中与存储相关的函数RecordAndGetPageWithFreeSpace->fsm_search,该函数搜索FSM,找到有足够空闲空间(min ...

  7. PostgreSQL 源码解读(156)- 后台进程#8(walsender#4)

    上节介绍了PostgreSQL的后台进程walsender中的函数WalSndLoop->WaitLatchOrSocket->WaitEventSetWait->WaitEvent ...

  8. PostgreSQL 源码解读(154)- 后台进程#6(walsender#2)

    本节继续介绍PostgreSQL的后台进程walsender,重点介绍的是调用栈中的exec_replication_command和StartReplication函数. 调用栈如下: (gdb) ...

  9. PostgreSQL 源码解读(155)- 后台进程#7(walsender#3)

    本节继续介绍PostgreSQL的后台进程walsender,重点介绍的是调用栈中的函数WalSndLoop->WaitLatchOrSocket->WaitEventSetWait-&g ...

最新文章

  1. 波士顿动力的机器狗上班了!巡逻、检测不在话下,挪威公司为其编发工号
  2. 编程第一个Apple Watch程序创建项目
  3. python资料免费-MicroPython最全资料免费获取
  4. 题解 UVA1555 【Garland】(二分)
  5. [vue-cli]vue-cli3插件有写过吗?怎么写一个代码生成插件?
  6. 消息中间件的技术选型心得-RabbitMQ ActiveMQ和ZeroMQ
  7. 海报设计素材|中国风的插画设计,国画浓抹中国色彩
  8. php本地文件包含漏洞,php文件包含漏洞利用小结
  9. contentType,charset和pageEncoding的区别
  10. Atitit 引流矩阵与矩阵引流 推广方法 attilax总结
  11. ESP8266热点配网-Arduino代码分享
  12. 用HTML 格式导出Excel 时,如何保留显示网格线 转载
  13. 关于 EOF EOF; 是什么意思?
  14. BZOJ3162: 独钓寒江雪
  15. 数据库-mysql MHA集群方案测试
  16. 俞渝手撕李国庆:他是同性恋,李回应:变态精神病患者!大量细节惊呆网友...
  17. 超实用!轻松几步修复灰蒙蒙的情侣合照!
  18. 局部搜索(爬山法+模拟退火+遗传算法)
  19. 汽车之家精选论坛图片下载
  20. JSP内置对象Session——setAttribute/getAttibute/removeAttribute

热门文章

  1. 惊魂,我的23个密码被泄露,快看看你的有没有泄露
  2. 七夕情人节~html+css+javascript实现满屏爱心特效(程序员表白)
  3. 160个CrackMe之108 mfc程序 寻找按钮事件,代码还原(上)
  4. attiny13a程序实例_关于ATtiny13A的程序
  5. ie9 error 拒绝访问
  6. 基于微信药店药品商城小程序系统设计与实现 开题报告
  7. UWB定位技术下的隧道定位监测系统真的如此受欢迎吗-新导智能
  8. java图片高保真缩放
  9. iOS---自动释放池
  10. python pymssql连接本地SQL SERVER