TThhee FFuunnccttiioonn MMaannaaggeerr 11.. GGeenneerraall The abstraction of functions is provided by the Func- tion Manager layer. A function in POSTGRES falls into one of the following categories: built-in functions, C functions or POSTQUEL functions. Each function is represented by its unique Object ID (also known as a Procedure ID). The built-in functions are a set of selected C proce- dures compiled into the backend. They are used by built-in operators, access methods, etc. User-defined functions yield either C functions (when declared with llaanngguuaaggee==""CC"") or POSTQUEL functions (when declared with llaann-- gguuaaggee==""ppoossttqquueell""). This layer is intended to provide uniform access to a function regardless of its type and bindings (ie. static or dynamic). Unfortunately, invoking POSTQUEL functions requires more sophistication. (Note that function and proce- dure is used interchangeably to mean the same thing in this document.) 22.. TThhee IInntteerrnnaallss 22..11.. TThhee SSyysstteemm CCaattaalloogg ppgg__pprroocc Each function has an entry in the system catalog, ppgg__pprroocc. The structure and declaration of an entry is as follows: CCAATTAALLOOGG((ppgg__pprroocc)) BBOOOOTTSSTTRRAAPP {{ cchhaarr1166 pprroonnaammee;; //** pprroocceedduurree nnaammee **// ooiidd pprroooowwnneerr;; //** pprroocceedduurree oowwnneerr **// ooiidd pprroollaanngg;; //** pprroocceedduurree llaanngguuaaggee **// bbooooll pprrooiissiinnhh;; //** iiss pprroocceedduurree iinnhheerriittaabbllee?? **// bbooooll pprrooiissttrruusstteedd;; //** iiss pprroocceedduurree ssppaawwnneedd oorr ccaalllleedd?? **// bbooooll pprrooiissccaacchhaabbllee;;//** iiss vvaalluuee pprreeccoommppuuttaabbllee?? **// iinntt22 pprroonnaarrggss;; //** nnuummbbeerr ooff aarrgguummeennttss **// bbooooll pprroorreettsseett;; //** ddooeess pprroocceedduurree rreettuurrnn sseett ooff ttuupplleess **// ooiidd pprroorreettttyyppee;; //** pprroocceedduurree rreettuurrnn ttyyppee **// ooiidd88 pprrooaarrggttyyppeess;; //** aarrgguummeenntt ttyyppeess **// iinntt44 pprroobbyyttee__ppcctt;; //** ppeerrcceennttaaggee ooff ssiizzee ooff iinnppuutt **// iinntt44 pprrooppeerrbbyyttee__ccppuu;; //** ccoosstt ppeerr bbyyttee ooff ooppeerraanndd **// iinntt44 pprrooppeerrccaallll__ccppuu;; //** CCPPUU ttiimmee ppeerr ccaallll **// iinntt44 pprroooouuttiinn__rraattiioo;; //** rraattiioo ooff oouuttppuutt ttoo iinnppuutt ssiizzeess **// tteexxtt pprroossrrcc;; //** qquueerryy ssttrriinngg ffoorr ppoossttqquueell ffuunnccttiioonnss **// bbyytteeaa pprroobbiinn;; //** oobbjjeecctt ffiillee nnaammee ffoorr CC pprroocceedduurreess **// }} FFoorrmmDDaattaa__ppgg__pprroocc;; ttyyppeeddeeff FFoorrmmDDaattaa__ppgg__pprroocc **FFoorrmm__ppgg__pprroocc;; 11 The pprroollaanngg field specifies the category of the func- tion. It contains the Object ID of the ``language'' the function is written in. Valid values are listed in the table below. +-------------------+---------------------+ | _L_a_n_g_u_a_g_e | _d_e_s_c_r_i_p_t_i_o_n | +-------------------+---------------------+ |IINNTTEERRNNAALLllaanngguuaaggeeIIdd | a built-in function | +-------------------+---------------------+ |CCllaanngguuaaggeeIIdd | a C function | +-------------------+---------------------+ |PPOOSSTTQQUUEELLllaanngguuaaggeeIIdd | a POSTQUEL function | +-------------------+---------------------+ The fields pprroobbyyttee__ppcctt,, pprrooppeerrbbyyttee__ccppuu,, pprrooppeerrccaallll__ccppuu,, and pprroooouuttiinn__rraattiioo are used by the optimizer for estimating the cost of a procedure invocation. They are described in greater detail in the POSTGRES reference manual. The field pprrooiissttrruusstteedd indicates if the procedure is trusted or not. If the procedure is trusted it is invoked in the same address space as the POSTGRES backend, otherwise, it is run as a seperate process. 22..22.. TThhee FFuunnccttiioonn CCaacchhee For faster access, information about the functions is cached in a function cache. lliibb//ffccaacchhee..cc contains code which handles the function cache. 22..33.. BBuuiilltt--iinn FFuunnccttiioonnss Built-in functions are collected at compile time from the source code to produce a table of entry points. The table is generated by the shell script uuttiillss//GGeenn__ffmmggrrttaabb..sshh. It generates ffmmggrrttaabb..cc and ffmmggrr..hh from ccaattaalloogg//ppgg__pprroocc..hh. Each entry in the table contains the following struc- ture (defined in uuttiillss//ffmmggrrttaabb..hh). ttyyppeeddeeff ssttrruucctt {{ OObbjjeeccttIIdd pprrooiidd;; //** pprroocceedduurree IIdd **// uuiinntt1166 nnaarrggss;; //** nnuummbbeerr ooff aarrgguummeennttss **// ffuunncc__ppttrr ffuunncc;; //** eennttrryy ppooiinntt **// }} FFmmggrrCCaallll;; The table is sorted by proid. The following is an excerpt of the table. For instance, the two entries specify the Pro- cedure Id's and number of arguments for the tteexxttiinn and tteexxttoouutt procedures. ssttaattiicc FFmmggrrCCaallll ffmmggrr__bbuuiillttiinnss[[]] == {{ ...... 22 {{ 4466,, 11,, tteexxttiinn }},, {{ 4477,, 11,, tteexxttoouutt }},, ...... }} The directory uuttiillss//aaddttcontains 22..44.. FFuunnccttiioonnss wwiitthh DDyynnaammiicc BBiinnddiinnggss User-defined functions are dynamically loaded into the backend on demand. The POSTQUEL ddeeffiinnee ffuunnccttiioonn command reg- isters the procedure in the system catalog, ppgg__pprroocc. The function is loaded into the running backend when either the POSTQUEL llooaadd command is encountered or the first time the function is invoked. The code which handles dynamic loading is in uuttiill//ffmmggrr//ddffmmggrr..cc. Details of dynamic loading is beyond the scope of this section. 33.. IInntteerrffaaccee RRoouuttiinneess Routines for invoking C functions are defined in uuttiillss//ffmmggrr//ffmmggrr..cc.. The following interface routines can be used: cchhaarr ** ffmmggrr((pprroocceedduurreeIIdd [[,, ...... ]] )) OObbjjeeccttIIdd pprroocceedduurreeIIdd;; ffmmggrr(()) takes the object ID of a procedure and its argu- ments. Note that you can only have eight arguments for user-defined C functions while at most nine for internal functions. ffmmggrr(()) invokes the function and returns the result if successful and 0 if unsuccessful. For example, the following code segment taken from ccaattaalloogg//iinnddeexx..cc illus- trates how the text-in procedure, tteexxttiinn(()), is invoked through ffmmggrr(()). iiff ((pprreeddiiccaattee !!== LLiissppNNiill)) {{ pprreeddSSttrriinngg == lliissppOOuutt((pprreeddiiccaattee));; pprreeddTTeexxtt == ((tteexxtt **))ffmmggrr((FF__TTEEXXTTIINN,, pprreeddSSttrriinngg));; ppffrreeee((pprreeddSSttrriinngg));; }} eellssee {{ pprreeddTTeexxtt == ((tteexxtt **))ffmmggrr((FF__TTEEXXTTIINN,, """"));; }} cchhaarr ** ffmmggrr__cc((uusseerr__ffnn,, ffuunncc__iidd,, nn__aarrgguummeennttss,, vvaalluueess,, iissNNuullll)) ffuunncc__ppttrr uusseerr__ffnn;; //** ffuunnccttiioonn eennttrryy ppooiinntt **// 33 OObbjjeeccttIIdd ffuunncc__iidd;; //** OOIIDD ooff ffuunnccttiioonn **// iinntt nn__aarrgguummeennttss;; //** nnuummbbeerr ooff aarrgguummeennttss ttoo tthhee ffuunnccttiioonn **// FFmmggrrVVaalluueess **vvaalluueess;; //** aarrrraayy ooff ffuunnccttiioonn aarrgguummeennttss **// BBoooolleeaann **iissNNuullll;; This routine is called by ffmmggrr(()) for invoking a C function. It is also called directly by the executor for invoking C functions. For untrusted C functions the function pointer uusseerr__ffnn is set to null. Functions defined in the same address space (builtin functions and trusted user-defined functions) are called directly from this routine whereas functions in a different address space (untrusted functions) are handled by the routine ffmmggrr__uuffpp(()) defined in uuttiillss//ffmmggrr//uuffpp..cc.. If the function needs to be dynamically loaded into the backend, it will be done automatically. POSTQUEL functions are invoked with ppoossttqquueell__ffuunnccttiioonn (defined in eexxeeccuuttoorr//ffuunnccttiioonnss..cc). DDaattuumm ppoossttqquueell__ffuunnccttiioonn((ffuunnccNNooddee,, aarrggss,, iissNNuullll,, iissDDoonnee)) FFuunncc ffuunnccNNooddee;; cchhaarr **aarrggss[[]];; bbooooll **iissNNuullll;; bbooooll **iissDDoonnee;; This routine is used only by the executor. To appreciate how the function manager works, one might look at the executor. In the executor ((eexxeeccuuttoorr//eexx__qquuaall..cc)),, EExxeeccEEvvaallEExxpprr evaluates operators and function clauses with EExxeeccEEvvaallOOppeerr and EExxeeccEEvvaallFFuunnccttiioonn.. Both of them invokes EExxeeccMMaakkeeFFuunnccttiioonnRReessuulltt which in turn invokes ffmmggrr__cc(()) and ppoossttqquueell__ffuunnccttiioonn(()) accordingly to evaluate the results. Another useful interface routine is ffmmggrr__iinnffoo(()) (defined in ffmmggrr//ffmmggrr..cc)).. It can be used to obtain informa- tion about any built-in or user-defined function and is declared as follows: vvooiidd ffmmggrr__iinnffoo((pprroocceedduurreeIIdd,, ffuunnccttiioonn,, nnaarrggss)) OObbjjeeccttIIdd pprroocceedduurreeIIdd;; ffuunncc__ppttrr **ffuunnccttiioonn;; iinntt **nnaarrggss;; It takes the procedure ID of a function and returns its entry point in ffuunnccttiioonn and the number of arguments it takes in nnaarrggss.. For example, the following code segment also taken from ccaattaalloogg//iinnddeexx..cc illustrates how to obtain the entry point (ie. the function pointer) of the procedure testing equality 44 of ObjectId's, ooiiddeeqq(()),, through ffmmggrr__iinnffoo(()). It stores the entry point in the index key for later use. ffmmggrr__iinnffoo((OObbjjeeccttIIddEEqquuaallRReeggPPrroocceedduurree,, &&iinnddeexxKKeeyy[[00]]..ffuunncc,, &&iinnddeexxKKeeyy[[00]]..nnaarrggss));; To use the above interfaces, you may need the following include file: ##iinncclluuddee ""ffmmggrr..hh"" 55