怎么实现PostgreSQL中的类型转换
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容主要讲解"怎么实现PostgreSQL中的类型转换",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么实现PostgreSQL中的类型转换"吧!解析
千家信息网最后更新 2025年01月20日怎么实现PostgreSQL中的类型转换
本篇内容主要讲解"怎么实现PostgreSQL中的类型转换",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么实现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;//结果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 * 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; 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 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)); }#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 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_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 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). */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 */}
三、跟踪分析
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_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 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, 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;
到此,相信大家对"怎么实现PostgreSQL中的类型转换"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
类型
函数
常量
目标
输入
跟踪
内容
参数
数据
结构
结果
分析
学习
不同
原始
实用
更深
代码
位置
兴趣
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
软件开发哪家好用
方舟火影服务器号
越秀软件开发定制
无锡企业app软件开发
公司软件开发证书
审计部门网络安全责任制度
国内数据库公司 cap
xpftp服务器搭建
一个电商网站服务器需要多少带宽
惠州市和创软件开发中心
运维服务器系统是什么
网络安全学点什么好
资软件开发
废墟数据库
ftp服务器工具
共享服务器管理员密码
托管服务器 远程管理
背景资料对网络安全吗
redis数据库结构
软件开发安卓机构
什么叫外部服务器
甘肃铭创数据库信息技术有限公司
大数据SDB数据库
我的世界国际服pvp服务器大全
应聘java软件开发工程师
网络安全系统等级怎么定级
和田软件开发联系方式
5g网络安全白皮书豆丁
中铁e通app服务器
广东新华科技互联网学校