Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analyze the CreateFunction function of PostgreSQL

2025-01-20 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

< 0) { /* SQL and PL-language functions are assumed more expensive */ //SQL和PL-XXX函数假定成本更高 if (languageOid == INTERNALlanguageId || languageOid == ClanguageId) procost = 1; else procost = 100; } if (prorows < 0) { if (returnsSet) prorows = 1000; else prorows = 0; /* dummy value if not returnsSet */ } else if (!returnsSet) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("ROWS is not applicable when function does not return a set"))); /* * And now that we have all the parameters, and know we're permitted to do * so, go ahead and create the function. * 这时候已准备好所有的参数,并且已验证具备相应的权限,创建函数 */ return ProcedureCreate(funcname, namespaceId, stmt->

Replace, returnsSet, prorettype, GetUserId (), languageOid, languageValidator, prosrc_str, / * converted to text later * / probin_str, / * converted to text later * / stmt- > is_procedure? PROKIND_PROCEDURE: (isWindowFunc? PROKIND_WINDOW: PROKIND_FUNCTION), security, isLeakProof, isStrict, volatility, parallel, parameterTypes, PointerGetDatum (allParameterTypes), PointerGetDatum (parameterModes), PointerGetDatum (parameterNames), parameterDefaults, PointerGetDatum (trftypes), PointerGetDatum (proconfig) Prosupport, procost, prorows) Third, follow-up and analysis

Test script

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$$declarebegin raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: =%', pi_v1,pi_v2,pio_v3; pio_v3: = 'pio_v3 iMaple'; po_v4: = 100; po_v5: = 'po_v5 out';end;$$ LANGUAGE plpgsql

Start GDB trace

(gdb) b CreateFunction Breakpoint 1 at 0x670b94: file functioncmds.c, line 929. (gdb) cContinuing.Breakpoint 1, CreateFunction (pstate=0x2b02cb8, stmt=0x2add8f8) at functioncmds.c:929929 Node * transformDefElem = NULL (gdb) bt#0 CreateFunction (pstate=0x2b02cb8, stmt=0x2add8f8) at functioncmds.c:929#1 0x00000000008f61a6 in ProcessUtilitySlow (pstate=0x2b02cb8, pstmt=0x2addc78, queryString=0x2adbf08 "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\ nTibet $\ ndeclare\ nbegin\ n raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: ="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x2addd70 CompletionTag=0x7fffef099ca0 "") at utility.c:1478#2 0x00000000008f5069 in standard_ProcessUtility (pstmt=0x2addc78, queryString=0x2adbf08 "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\ ncustomers $\ ndeclare\ nbegin\ n raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: ="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x2addd70 CompletionTag=0x7fffef099ca0 "") at utility.c:927#3 0x00000000008f418f in ProcessUtility (pstmt=0x2addc78, queryString=0x2adbf08 "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\ ncustomers $\ ndeclare\ nbegin\ n raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: ="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x2addd70 CompletionTag=0x7fffef099ca0 "") at utility.c:360#4 0x00000000008f3188 in PortalRunUtility (portal=0x2b43278, pstmt=0x2addc78,-- Type to continue, or q to quit--- isTopLevel=true, setHoldSnapshot=false, dest=0x2addd70, completionTag=0x7fffef099ca0 "") at pquery.c:1175#5 0x00000000008f339e in PortalRunMulti (portal=0x2b43278, isTopLevel=true, setHoldSnapshot=false, dest=0x2addd70, altdest=0x2addd70, completionTag=0x7fffef099ca0 ") at pquery.c:1321#6 0x00000000008f28d3 in PortalRun (portal=0x2b43278, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x2addd70, altdest=0x2addd70 CompletionTag=0x7fffef099ca0 "") at pquery.c:796#7 0x00000000008ec882 in exec_simple_query (query_string=0x2adbf08 "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\ ncustomers $\ ndeclare\ nbegin\ n raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: ="...) At postgres.c:1215#8 0x00000000008f0b04 in PostgresMain (argc=1, argv=0x2b09318, dbname=0x2b09160 "testdb", username=0x2ad8b28 "pg12") at postgres.c:4247#9 0x0000000000846fa8 in BackendRun (port=0x2afdb10) at postmaster.c:4437#10 0x0000000000846786 in BackendStartup (port=0x2afdb10) at postmaster.c:4128#11 0x00000000008429b4 in ServerLoop () at postmaster.c:1704#12 0x000000000084226a in PostmasterMain (argc=1, argv=0x2ad6ae0) at postmaster.c:1377#13 0x0000000000762364 in main (argc=1, argv=0x2ad6ae0) at main.c:228 (gdb)

Input parameters, pstate is ParseState structure, stmt type is CreateFunctionStmt structure

(gdb) p * pstate$1 = {parentParseState = 0x0, p_sourcetext = 0x2adbf08 "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\ ncustomers $\ 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 * stmt$2 = {type = T_CreateFunctionStmt, is_procedure = false, replace = true, funcname = 0x2adcb58, parameters = 0x2adcd60, returnType = 0x2add580, options = 0x2add818}

Get namespace

(gdb) n939 List * trftypes_list = NIL; (gdb) 957 namespaceId = QualifiedNameGetCreationNamespace (stmt- > funcname, (gdb) 961 aclresult = pg_namespace_aclcheck (namespaceId, GetUserId (), ACL_CREATE); (gdb) p namespaceId$3 = 2200 (gdb)

Namespace is public.

[local:/data/run/pg12]: 5120 pg12@testdb=# select * from pg_namespace Oid | nspname | nspowner | nspacl-+-99 | pg_toast | 10 | 12314 | pg_temp_1 | 10 | 12315 | pg_toast_temp_1 | 10 | 11 | pg_catalog | 10 | {pg12=UC/pg12 = U/pg12} 2200 | public | 10 | {pg12=UC/pg12,=UC/pg12} 13291 | information_schema | 10 | {pg12=UC/pg12,=U/pg12} (6 rows)

Perform a permission check to initialize property defaults

(gdb) n962 if (aclresult! = ACLCHECK_OK) (gdb) p aclresult$4 = ACLCHECK_OK (gdb) n967 isWindowFunc = false; (gdb) 968 isStrict = false; (gdb) 969 security = false; (gdb) 970 isLeakProof = false; (gdb) 971 volatility = PROVOLATILE_VOLATILE; (gdb) 972 proconfig = NULL; (gdb) 973 procost =-1; / * indicates not set * / (gdb) 974 prorows =-1 / * indicates not set * / (gdb) 975 prosupport = InvalidOid; (gdb) 976 parallel = PROPARALLEL_UNSAFE; (gdb) 979 compute_function_attributes (pstate)

Call compute_function_attributes to extract non-default attributes from the stmt- > options linked list

(gdb) 989 languageTuple = SearchSysCache1 (LANGNAME, PointerGetDatum (language)) (gdb) p * language$33 = 112p' (gdb) p * transformDefElemCannot access memory at address 0x0 (gdb) p isWindowFunc$34 = false (gdb) p volatility$35 = 118v' (gdb) p isStrict$36 = false (gdb) p security$37 = false (gdb) p isLeakProof$38 = false (gdb) p proconfig$39 = (ArrayType *) 0x0 (gdb) p procost$40 =-1 (gdb) p prorows$41 =-1 (gdb) p prosupport$42 = 0 (gdb) p parallel$43 = 117u' (gdb) p stmt- > options$44 = (List *) 0x2add818 (gdb) P * stmt- > options$45 = {type = T_List Length = 2, head = 0x2add7f0, tail = 0x2add8d0} (gdb) p * (Node *) stmt- > options- > head- > data.ptr_value$46 = {type = T_DefElem} (gdb) p * (DefElem *) stmt- > options- > head- > data.ptr_value$47 = {type = T_DefElem, defnamespace = 0x0, defname = 0xbbf727 "as", arg = 0x2add760, defaction = DEFELEM_UNSPEC Location = 134} (gdb) p * ((DefElem *) stmt- > options- > head- > data.ptr_value)-> arg$48 = {type = T_List} (gdb) p * pstate$5 = {parentParseState = 0x0, p_sourcetext = 0x2adbf08 "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\ ncustomers $\ 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) xamp 1024c pstate- > p_sourcetext0x2adbf08: 99'c '114' r '101' e'97'a '116' t '101' e'32''111' o'0x2adbf10: 114'r'32''114' r '101' e '112' p '108' l'97'a'99 'c'0x2adbf18: 101' e'32 '102' f '117' u110 'n99' 'c' 116't '105' i'0x2adbf20: 111'o '110' n'32 '102' f '117' u'n'99'c'95'_ '0x2adbf28: 116' t '101' e '115' s' 116't'40'('112' p '105' i95'_ 0x2adbf30: 118'v'49'1'32 '105' i110'n'32 '105' i110 'n32' 105 'i110' n32' 'n'0x2adbf38: 116t' 44' '112 'p105' i' 95'_ 118'v'50'2' 32 '0x2adbf40: 118' v'97'a '114' r'99'c '104' h'97'a '114' r'44' 0x2adbf48: 112 'p105' i' 111'o' 95'_ 118'v'51 '332' 105 'i'0x2adbf50: 110' n '111' o '117' u '116' t'32 '118' v'97'a '114' r'0x2adbf58: 99'c '104' h'97'a '114' r'44' '112'p '111' o'95'_ '0x2adbf60: 118' v'52'4' 32 '111' o '117' u '116' t'32 '105' i'0x2adbf68: 110'n '116' t'44' 5'0x2adbf70: 32 '111' o' 117'u '116' t'32 '118' v'97'a '114' r'0x2adbf78: 99'c '104' h'97'a '114' r'41')'10'\ n '114' r '101 'e'0x2adbf80: 116' t '117' u'r '110' n '115 's' 32', '114' r '101' e'0x2adbf88: 99'c '111' o '114' r '100' d'32'10'\ n'97'a '115' s'0x2adbf90: 10'\ n'36'$36'$'10'\ n '100' d '101' e'99'c '108' l'0x2adbf98: 97'a '114' r '101' e'10'\ n'98'b' 101'e '103' g '105' i'0x2adbfa0: 110'n'10'\ n'32'32 '114' r'97'a '105' I '115' s'---Type to continue Or q to quit---0x2adbfa8: 101'e'32 '110' n '111' o '116't '105' I'99'c '101' e'0x2adbfb0: 32'39'\ '112' p '105' i' 95'_ 118'v'49'1' 32 '0x2adbfb8: 58':'61'='32'37'%'44' '112 'p105' i' 95'_ '0x2adbfc0: 118v' 50'2' 32'58':'61'='32'37'%'44', '0x2adbfc8: 112' p' 105 'i105' 95'_ 118'v'51'3' 32'58':'61'= '0x2adbfd0: 32' 37'% 39'\'44' '112 'p105' i' 95'_ 118 'v'0x2adbfd8: 49' 1' 44', '112' p105'i' 95'_ 118'v'50'2' 44', '0x2adbfe0: 112' p' 105'i' 111 'o95' _ 118'v'51'3' 59' '10'\ n'0x2adbfe8: 32'32 'p105' i111'95'_ 118'v'51 '3'0x2adbff0: 32' 58':'61'='32'39'\ '112' p' 105'i' 111 'o'0x2adbff8: 95' _ 118'v'51 '332' 105'i' 47'/ 111'o' 39'\ '0x2adc000: 59' V'0x2adc008: 52'4' 32': 61'='32'49'48 '048' 0'0x2adc010: 59' V'0x2adc018: 53 '532' 58': 61'='32'39'\ '112' p111111o'0x2adc020: 95 '118v' 53 '532' 111 '111o117' u'116't'39'\ '0x2adc028: 59' 10'n '101' e '110' n '100' d'59'; 10'\ n'36'$'0x2adc030: 36' 32'76'L'65'A'78'N'71'G'85'U'65 'A'0x2adc038: 71' G'69'E'32 '112' p '108' l112 'p103' g '115' s'0x2adc040: 113 'q108' 159' '0'\ 0000'\ 000127'\ 177' 127'\ 1---Type to continue, or q to quit--- ^ CQuit (gdb) (gdb) n

Get language

990 if (! HeapTupleIsValid (languageTuple)) (gdb) p languageTuple$7 = (HeapTuple) 0x7fcc407e0bf8 (gdb) p * languageTuple$8 = {t_len = 120, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 4}, t_tableOid = 2612, t_data = 0x7fcc407e0c20} (gdb) n997 languageStruct = (Form_pg_language) GETSTRUCT (languageTuple); (gdb) 998 languageOid = languageStruct- > oid (gdb) p * languageStruct$9 = {oid = 13581, lanname = {data = "plpgsql",'\ 000'}, lanowner = 10, lanispl = true, lanpltrusted = true, lanplcallfoid = 13578, laninline = 13579, lanvalidator = 13580} (gdb) n1000 if (languageStruct- > lanpltrusted) (gdb) 1005 aclresult = pg_language_aclcheck (languageOid, GetUserId (), ACL_USAGE); (gdb) 1006 if (aclresult! = ACLCHECK_OK) (gdb) 1018 languageValidator = languageStruct- > lanvalidator (gdb) 1020 ReleaseSysCache (languageTuple); (gdb) 1027 if (isLeakProof &! superuser ()) (gdb) 1032 if (transformDefElem) (gdb) 1056 stmt- > is_procedure? OBJECT_PROCEDURE: OBJECT_FUNCTION, (gdb)

Convert the remaining parameters in CREATE for use in ProcedureCreate calls

1053 interpret_function_parameter_list (pstate, (gdb) 1065 if (stmt- > is_procedure) (gdb) p * pstate$10 = {parentParseState = 0x0, p_sourcetext = 0x2adbf08 "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\ nTibet $\ 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 * stmt$11 = {type = T_CreateFunctionStmt, is_procedure = false, replace = true Funcname = 0x2adcb58, parameters = 0x2adcd60, returnType = 0x2add580, options = 0x2add818} (gdb) p * stmt- > parameters$12 = {type = T_List, length = 5, head = 0x2adcd38, tail = 0x2add4b0} (gdb) p parameterTypes$13 = (oidvector *) 0x2bed1a8 (gdb) p * parameterTypes$14 = {vl_len_ = 144,ndim = 1, dataoffset = 0, elemtype = 26, dim1 = 3, lbound1 = 0 Values = 0x2bed1c0} (gdb) xbank 144h 0x2bed1c00x2bed1c0: 23'\ 027' 0'\ 000' 19'\ 023' 0'\ 000' 19'\ 023' 0'\ 000' 126'~ '127'\ 177'0x2bed1d0: 127'\ 177' 127'\ 177' 127'\ 177' 127'\ 177' 127'\ 177' 127'\ 177' 127'\ 177'0x2bed1e0: 127'\ 177 '127'\ 177' 127'\ 177' 64'@ 0'\ 00000'\ 000000'\ 000'0x2bed1f0: 44' '0'\ 000' 0'\ 000'0'-96'\ 240'-80'\ 2600'\ 0000'\ 000'0x2bed200:-80'\ 2600'\ 0001'\ 001'\ 000000'\ 0000' 26'\ 0320'\ 000'0x2bed210: 5'\ 0050'\ 000' 1 '001' 0'\ 000' 23'\ 0270' 19'\ 0230'\ 0230'\ 000'0x2bed220: 19'\ 0230'\ 00023'\ 0270' 19'\ 0230'\ 000' 126'~ '127'\ 177'0x2bed230: 127'\ 177' 127'\ 177' 127'\ 177' 127'\ 177' 127' \ 177' 127'\ 177' 127'\ 177' 127'\ 177'0x2bed240: 32'0'\ 000'0'\ 000 '29'\ 035' 0'\ 000' 0'\ 000'0'\ 000'0x2bed250:-96'\ 240'-80'\ 260' 0'\ 000'0' 116't'0'\ 000' 1 '\ 0010'\ 000'---Type to continue Or q to quit--- ^ CQuit (gdb) n1071 else if (stmt- > returnType) (gdb) p * stmt- > returnType$15 = {type = T_TypeName, names = 0x2add548, typeOid = 0, setof = false, pct_type = false, typmods = 0x0, typemod =-1, arrayBounds = 0x0, location = 126} (gdb) p * stmt- > returnType- > names$16 = {type = T_List, length = 1, head = 0x2add520, tail = 0x2add520} (gdb) n1074 gdb (compute_return_type > compute_return_type, compute_return_type) (gdb) 1076 if (OidIsValid (requiredResultType) & & prorettype! = requiredResultType) (gdb) p * prorettypeCannot access memory at address 0x8c9 (gdb) p prorettype$17 = 2249 (gdb) p returnsSet$18 = false (gdb) p $19 = false (gdb) p * allParameterTypes$20 = {vl_len_ = 176, ndim = 1, dataoffset = 0, elemtype = 26} (gdb) p parameterModes$21 = (ArrayType *) 0x2bed258 (gdb) p * parameterModes$22 = {vl_len_ = 116,ndim = 1, dataoffset = 0 Elemtype = 18} (gdb) p * parameterNames$23 = {vl_len_ = 336, ndim = 1, dataoffset = 0, elemtype = 25} (gdb) p * parameterDefaultsCannot access memory at address 0x0 (gdb) p * variadicArgTypeCannot access memory at address 0x0 (gdb) p * requiredResultTypeCannot access memory at address 0x8c9 (gdb) p requiredResultType$24 = 2249 (gdb) n1098 if (list_length (trftypes_list) > 0) (gdb) p trftypes_list$25 = (List *) 0x0 (gdb) n1114 trftypes = NULL (gdb) 1117 interpret_AS_clause (languageOid, language, funcname, as_clause, (gdb) 1125 if (procost)

< 0)(gdb) p *prosrc_str$26 = 10 '\n'(gdb) p *probin_strCannot access memory at address 0x0(gdb) p as_clause$27 = (List *) 0x2add760(gdb) p *as_clause$28 = {type = T_List, length = 1, head = 0x2add738, tail = 0x2add738}(gdb) p *as_clause->

Head$29 = {data = {ptr_value = 0x2add710, int_value = 44947216, oid_value = 44947216} Next = 0x0} (gdb) p (Node *) as_clause- > head- > data.ptr_value$30 = (Node *) 0x2add710 (gdb) p (Node * *) as_clause- > head- > data.ptr_value$31 = (Node * *) 0x2add710 (gdb) p * as_clause- > head- > data.ptr_valueAttempt to dereference a generic pointer. (gdb) p (Node *) as_clause- > head- > data.ptr_value$32 = (Node *) 0x2add710 (gdb) n1128 if (languageOid = INTERNALlanguageId | (gdb) ) 1132 procost = 100 (gdb) 1134 if (prorows

< 0)(gdb) 1136 if (returnsSet)(gdb) 1139 prorows = 0; /* dummy value if not returnsSet */(gdb) 1150 return ProcedureCreate(funcname,(gdb) 1160 stmt->

Is_procedure? PROKIND_PROCEDURE: (isWindowFunc? PROKIND_WINDOW: PROKIND_FUNCTION), (gdb) 1150 return ProcedureCreate (funcname, (gdb) 1152 stmt- > replace, (gdb) 1150 return ProcedureCreate (funcname, (gdb) 1176} (gdb) ProcessUtilitySlow (pstate=0x2b02cb8, pstmt=0x2addc78, queryString=0x2adbf08 "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\ ncustomers $\ ndeclare\ nbegin\ n raise notice 'pi_v1: =%, pi_v2: =%, pi_v3: = ", context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x2addd70, completionTag=0x7fffef099ca0") at utility.c:14791479 break (gdb) at this point, I believe you have a deeper understanding of "analyzing the CreateFunction function of PostgreSQL". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report