Ðлава 57. ÐапиÑание обÑабоÑÑика пÑоÑедÑÑного ÑзÑка
ÐÑе ÑÑнкÑии, напиÑаннÑе на ÑзÑке, вÑзÑваемом не ÑеÑез ÑекÑÑий инÑеÑÑÐµÐ¹Ñ Â«Ð²ÐµÑÑии 1» Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»Ð¸ÑÑемÑÑ ÑзÑков (а именно, ÑÑо ÑÑнкÑии на пÑоÑедÑÑнÑÑ ÑзÑÐºÐ°Ñ Ð¸ ÑÑнкÑии, напиÑаннÑе на SQL) вÑполнÑÑÑÑÑ ÑеÑез обÑабоÑÑик вÑзова Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ÑзÑка. ÐадаÑа Ñакого обÑабоÑÑика вÑзова â вÑполниÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñм обÑазом, напÑимеÑ, инÑеÑпÑеÑиÑÑÑ Ð´Ð»Ñ ÑÑого ÐµÑ Ð¸ÑÑ Ð¾Ð´Ð½Ñй ÑекÑÑ. Ð ÑÑой главе в обÑÐ¸Ñ ÑеÑÑÐ°Ñ ÑаÑÑказÑваеÑÑÑ, как можно напиÑаÑÑ Ð¾Ð±ÑабоÑÑик нового пÑоÑедÑÑного ÑзÑка.
ÐбÑабоÑÑик вÑзова пÑоÑедÑÑного ÑзÑка â ÑÑо «обÑÑнаÑ» ÑÑнкÑиÑ, коÑоÑÐ°Ñ ÑазÑабаÑÑваеÑÑÑ Ð½Ð° компилиÑÑемом ÑзÑке, Ñаком как C, вÑзÑваеÑÑÑ ÑеÑез инÑеÑÑÐµÐ¹Ñ Ð²ÐµÑÑии 1, и ÑегиÑÑÑиÑÑеÑÑÑ Ð² PostgreSQL как не пÑинимаÑÑÐ°Ñ Ð°ÑгÑменÑÑ Ð¸ возвÑаÑаÑÑÐ°Ñ Ñип language_handler. ÐÑÐ¾Ñ ÑпеÑиалÑнÑй пÑевдоÑип помеÑÐ°ÐµÑ ÑÑнкÑÐ¸Ñ ÐºÐ°Ðº обÑабоÑÑик вÑзова и пÑепÑÑÑÑвÑÐµÑ ÐµÑ Ð²ÑÐ·Ð¾Ð²Ñ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно из команд SQL. Ðолее подÑобно ÑоглаÑение о вÑзоваÑ
и динамиÑеÑÐºÐ°Ñ Ð·Ð°Ð³ÑÑзка кода на C опиÑÑваеÑÑÑ Ð² Разделе 36.10.
ÐбÑабоÑÑик вÑзова вÑзÑваеÑÑÑ Ñак же, как и лÑÐ±Ð°Ñ Ð´ÑÑÐ³Ð°Ñ ÑÑнкÑиÑ: он полÑÑÐ°ÐµÑ ÑказаÑÐµÐ»Ñ Ð½Ð° пеÑеменнÑÑ struct FunctionCallInfoBaseData, ÑодеÑжаÑÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð°ÑгÑменÑов и инÑоÑмаÑÐ¸Ñ Ð¾ вÑзÑваемой ÑÑнкÑии, и должен веÑнÑÑÑ ÑезÑлÑÑÐ°Ñ Ñипа Datum (и, возможно, ÑÑÑановиÑÑ Ð¿Ñизнак isnull в ÑÑÑÑкÑÑÑе FunctionCallInfoBaseData, еÑли нÑжно веÑнÑÑÑ ÑезÑлÑÑÐ°Ñ SQL NULL). ÐÑлиÑие обÑабоÑÑика вÑзова Ð¾Ñ Ð¾Ð±ÑÑной вÑзÑваемой ÑÑнкÑии ÑоÑÑÐ¾Ð¸Ñ Ð² Ñом, ÑÑо поле flinfo->fn_oid ÑÑÑÑкÑÑÑÑ FunctionCallInfoBaseData Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ бÑÐ´ÐµÑ ÑодеÑжаÑÑ OID вÑзÑваемой ÑÑнкÑии, а не Ñамого обÑабоÑÑика. Ðо ÑÑÐ¾Ð¼Ñ OID обÑабоÑÑик вÑзова должен понÑÑÑ, какÑÑ ÑÑнкÑÐ¸Ñ Ð²ÑзÑваÑÑ. ÐÑоме Ñого, ÑпиÑок пеÑедаваемÑÑ
аÑгÑменÑов Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ ÑоÑмиÑÑеÑÑÑ Ð² ÑооÑвеÑÑÑвии Ñ Ð¾Ð±ÑÑвлением Ñелевой ÑÑнкÑии, а не обÑабоÑÑика вÑзова.
ÐбÑабоÑÑик вÑзова Ñам должен вÑбÑаÑÑ Ð·Ð°Ð¿Ð¸ÑÑ ÑÑнкÑии из ÑиÑÑемного каÑалога pg_proc и пÑоанализиÑоваÑÑ ÑÐ¸Ð¿Ñ Ð°ÑгÑменÑов и ÑезÑлÑÑаÑа вÑзÑваемой ÑÑнкÑии. СодеÑжимое пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ AS ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE FUNCTION Ð´Ð»Ñ ÑÑой ÑÑнкÑии бÑÐ´ÐµÑ Ð½Ð°Ñ
одиÑÑÑÑ Ð² ÑÑолбÑе prosrc ÑÑÑоки в pg_proc. ÐбÑÑно ÑÑо иÑÑ
однÑй ÑекÑÑ Ð½Ð° пÑоÑедÑÑном ÑзÑке, но в пÑинÑипе ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ ÑÑо-Ñо дÑÑгое, напÑимеÑ, пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ инÑе даннÑе, говоÑÑÑие обÑабоÑÑÐ¸ÐºÑ Ð²Ñзова, ÑÑо именно делаÑÑ.
ЧаÑÑо ÑÑнкÑÐ¸Ñ Ð¼Ð½Ð¾Ð³Ð¾ÐºÑаÑно вÑзÑваеÑÑÑ Ð² одном SQL-опеÑаÑоÑе. ЧÑÐ¾Ð±Ñ Ð² ÑакиÑ
ÑлÑÑаÑÑ
избежаÑÑ Ð¿Ð¾Ð²ÑоÑнÑÑ
обÑаÑений за инÑоÑмаÑией о вÑзÑваемой ÑÑнкÑии, обÑабоÑÑик вÑзова Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾ÑполÑзоваÑÑÑÑ Ð¿Ð¾Ð»ÐµÐ¼ flinfo->fn_extra. ÐзнаÑалÑно оно ÑодеÑÐ¶Ð¸Ñ NULL, но обÑабоÑÑик вÑзова Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð¼ÐµÑÑиÑÑ Ð² него ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑебÑемÑÑ Ð¸Ð½ÑоÑмаÑиÑ. ÐÑи поÑледÑÑÑиÑ
вÑзоваÑ
, еÑли поле flinfo->fn_extra бÑÐ´ÐµÑ Ð¾ÑлиÑно Ð¾Ñ NULL, им можно воÑполÑзоваÑÑÑÑ Ð¸ пÑопÑÑÑиÑÑ Ñаг полÑÑÐµÐ½Ð¸Ñ ÑÑой инÑоÑмаÑии. ÐбÑабоÑÑик вÑзова должен позабоÑиÑÑÑÑ Ð¾ Ñом, ÑÑÐ¾Ð±Ñ ÑказаÑÐµÐ»Ñ Ð² flinfo->fn_extra ÑказÑвал на блок памÑÑи, коÑоÑÑй не бÑÐ´ÐµÑ Ð¾ÑвобождÑн ÑанÑÑе, Ñем завеÑÑиÑÑÑ Ð·Ð°Ð¿ÑÐ¾Ñ (именно ÑÑолÑко Ð¼Ð¾Ð¶ÐµÑ ÑÑÑеÑÑвоваÑÑ ÑÑÑÑкÑÑÑа FmgrInfo). РкаÑеÑÑве одного из ваÑианÑов, ÑÑого можно добиÑÑÑÑ, ÑазмеÑÑив дополниÑелÑнÑе даннÑе в конÑекÑÑе памÑÑи, заданном в flinfo->fn_mcxt; ÑÑок жизни ÑакиÑ
даннÑÑ
обÑÑно ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñо ÑÑоком жизни Ñамой ÑÑÑÑкÑÑÑÑ FmgrInfo. С дÑÑгой ÑÑоÑонÑ, обÑабоÑÑик Ð¼Ð¾Ð¶ÐµÑ Ð²ÑбÑаÑÑ Ð¸ более долгоживÑÑий конÑекÑÑ Ð¿Ð°Ð¼ÑÑи Ñ Ñем, ÑÑÐ¾Ð±Ñ ÐºÐµÑиÑоваÑÑ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑнкÑий и Ð¼ÐµÐ¶Ð´Ñ Ð·Ð°Ð¿ÑоÑами.
Ðогда ÑÑнкÑÐ¸Ñ Ð½Ð° пÑоÑедÑÑном ÑзÑке вÑзÑваеÑÑÑ ÐºÐ°Ðº ÑÑиггеÑ, ей не пеÑедаÑÑÑÑ Ð°ÑгÑменÑÑ Ð¾Ð±ÑÑнÑм ÑпоÑобом; вмеÑÑо ÑÑого поле context в FunctionCallInfoBaseData ÑказÑÐ²Ð°ÐµÑ Ð½Ð° ÑÑÑÑкÑÑÑÑ TriggerData, Ñогда как пÑи обÑÑном вÑзове ÑÑнкÑии оно ÑодеÑÐ¶Ð¸Ñ NULL. ÐбÑабоÑÑик ÑзÑка, в ÑÐ²Ð¾Ñ Ð¾ÑеÑедÑ, должен каким-либо обÑазом пÑедоÑÑавиÑÑ ÑÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ ÑÑнкÑиÑм на ÑÑом пÑоÑедÑÑном ÑзÑке.
Шаблон обÑабоÑÑика пÑоÑедÑÑного ÑзÑка, напиÑаннÑй как ÑаÑÑиÑение на C, пÑедÑÑавлен в src/test/modules/plsample. ÐÑо ÑабоÑий пÑимеÑ, показÑваÑÑий, как можно ÑоздаÑÑ Ð¾Ð±ÑабоÑÑик пÑоÑедÑÑного ÑзÑка, коÑоÑÑй бÑÐ´ÐµÑ Ð¿ÑинимаÑÑ Ð¿Ð°ÑамеÑÑÑ Ð¸ возвÑаÑаÑÑ ÑезÑлÑÑаÑ.
ХоÑÑ Ð¾Ð±ÑабоÑÑика вÑзова доÑÑаÑоÑно Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿ÑоÑÑейÑего пÑоÑедÑÑного ÑзÑка, еÑÑÑ ÐµÑÑ Ð´Ð²Ðµ ÑÑнкÑии, коÑоÑÑе можно ÑеализоваÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑно, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑзоваÑÑÑÑ ÑзÑком бÑло Ñдобнее: ÑÑнкÑÐ¸Ñ Ð¿ÑовеÑки и обÑабоÑÑик внедÑÑнного кода. ФÑнкÑÐ¸Ñ Ð¿ÑовеÑки можно ÑеализоваÑÑ, ÑÑÐ¾Ð±Ñ Ð¿ÑоизводиÑÑ Ð¿ÑовеÑÐºÑ ÑинÑакÑиÑа ÑзÑка во вÑÐµÐ¼Ñ CREATE FUNCTION. ÐÑли же Ñеализован обÑабоÑÑик внедÑÑнного кода, ÑÑÐ¾Ñ ÑзÑк бÑÐ´ÐµÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ Ð²Ñполнение анонимнÑÑ Ð±Ð»Ð¾ÐºÐ¾Ð² кода командой DO.
ÐÑли Ð´Ð»Ñ Ð¿ÑоÑедÑÑного ÑзÑка пÑедоÑÑавлÑеÑÑÑ ÑÑнкÑÐ¸Ñ Ð¿ÑовеÑки, она должна бÑÑÑ Ð¾Ð±ÑÑвлена как ÑÑнкÑиÑ, пÑинимаÑÑÐ°Ñ Ð¾Ð´Ð¸Ð½ паÑамеÑÑ Ñипа oid. РезÑлÑÑÐ°Ñ ÑÑнкÑии пÑовеÑки игноÑиÑÑеÑÑÑ, Ñак ÑÑо она обÑÑно обÑÑвлÑеÑÑÑ ÐºÐ°Ðº возвÑаÑаÑÑÐ°Ñ Ñип void. ÐÑа ÑÑнкÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð²ÑзÑваÑÑÑÑ Ð² конÑе вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE FUNCTION, ÑоздаÑÑей или изменÑÑÑей ÑÑнкÑиÑ, напиÑаннÑÑ Ð½Ð° пÑоÑедÑÑном ÑзÑке. ÐеÑеданнÑй ей OID ÑказÑÐ²Ð°ÐµÑ Ð½Ð° ÑÑÑÐ¾ÐºÑ Ð² pg_proc Ð´Ð»Ñ ÑÑой ÑÑнкÑии. ФÑнкÑÐ¸Ñ Ð¿ÑовеÑки должна вÑбÑаÑÑ ÑÑÑ ÑÑÑÐ¾ÐºÑ Ð¾Ð±ÑÑнÑм обÑазом и пÑоизвеÑÑи вÑе необÑ
одимÑе пÑовеÑки. ÐÑежде вÑего нÑжно вÑзваÑÑ CheckFunctionValidatorAccess(), ÑÑÐ¾Ð±Ñ Ð¾ÑлиÑиÑÑ ÑвнÑе вÑÐ·Ð¾Ð²Ñ ÑÑой ÑÑнкÑии Ð¾Ñ Ð¿ÑоиÑÑ
одÑÑиÑ
пÑи вÑполнении ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE FUNCTION. ÐаÑем обÑÑно пÑовеÑÑеÑÑÑ, напÑимеÑ, ÑÑо ÑÐ¸Ð¿Ñ Ð°ÑгÑменÑов и ÑезÑлÑÑаÑа ÑÑнкÑии поддеÑживаÑÑÑÑ ÑзÑком и ÑÑо Ñело ÑÑнкÑии ÑинÑакÑиÑеÑки пÑавилÑно Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ÑзÑка. ÐÑли ÑÑнкÑÐ¸Ñ Ð¿ÑовеÑки заклÑÑаеÑ, ÑÑо вÑÑ Ð² поÑÑдке, она должна пÑоÑÑо завеÑÑиÑÑÑÑ. ÐÑли же она обнаÑÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð¾ÑибкÑ, она должна ÑообÑиÑÑ Ð¾ ней ÑеÑез обÑÑнÑй меÑ
анизм ereport(). ÐÑÐ´Ð°Ð½Ð½Ð°Ñ Ñаким обÑазом оÑибка пÑиведÑÑ Ðº оÑкаÑÑ ÑÑанзакÑии, Ñак ÑÑо опÑеделение некоÑÑекÑной ÑÑнкÑии заÑикÑиÑовано не бÑдеÑ.
ФÑнкÑии пÑовеÑки обÑÑно Ð´Ð¾Ð»Ð¶Ð½Ñ ÑÑиÑÑваÑÑ Ð¿Ð°ÑамеÑÑ check_function_bodies: еÑли он оÑклÑÑÑн, Ñо доÑогоÑÑоÑÑие или завиÑÑÑие Ð¾Ñ ÐºÐ¾Ð½ÑекÑÑа пÑовеÑки ÑодеÑжимого ÑÑнкÑии вÑполнÑÑÑ Ð½Ðµ ÑледÑеÑ. ÐÑли ÑзÑк подÑазÑÐ¼ÐµÐ²Ð°ÐµÑ Ð²Ñполнение кода в пÑоÑеÑÑе компилÑÑии, пÑовеÑÑÑÑÐ°Ñ ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° избегаÑÑ Ð¿ÑовеÑок, коÑоÑÑе влекÑÑ Ð·Ð° Ñобой Ñакое вÑполнение. Ð ÑаÑÑноÑÑи, ÑказаннÑй паÑамеÑÑ Ð¾ÑклÑÑÐ°ÐµÑ ÑÑилиÑа pg_dump, ÑÑÐ¾Ð±Ñ Ð¾Ð½Ð° могла загÑÑжаÑÑ ÑÑнкÑии на пÑоÑедÑÑнÑÑ
ÑзÑкаÑ
, не забоÑÑÑÑ Ð¾ побоÑнÑÑ
ÑÑÑекÑаÑ
или завиÑимоÑÑÑÑ
ÑодеÑжимого ÑÑнкÑий Ð¾Ñ Ð´ÑÑгиÑ
обÑекÑов базÑ. (ÐÑледÑÑвие ÑÑого ÑÑебованиÑ, обÑабоÑÑик ÑзÑка не должен полагаÑÑ, ÑÑо ÑÑнкÑÐ¸Ñ Ð¿ÑоÑла полнÑÑ Ð¿ÑовеÑкÑ. СмÑÑл ÑÑÑеÑÑÐ²Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑнкÑии пÑовеÑки не в Ñом, ÑÑÐ¾Ð±Ñ ÑбÑаÑÑ ÑÑи пÑовеÑки из обÑабоÑÑика вÑзова, а в Ñом, ÑÑÐ¾Ð±Ñ Ð½ÐµÐ¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾ ÑведомиÑÑ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð¾Ð± оÑевиднÑÑ
оÑибкаÑ
пÑи вÑполнении CREATE FUNCTION.) ХоÑÑ Ð²ÑбоÑ, ÑÑо именно должно пÑовеÑÑÑÑÑÑ, по болÑÑÐ¾Ð¼Ñ ÑÑÑÑÑ Ð¾ÑÑаÑÑÑÑ Ð·Ð° ÑÑнкÑией пÑовеÑки, замеÑÑÑе, ÑÑо оÑновной код CREATE FUNCTION вÑполнÑÐµÑ Ð¿ÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ SET, ÑвÑзаннÑе Ñ ÑÑнкÑией, ÑолÑко когда check_function_bodies вклÑÑÑн. Таким обÑазом, пÑовеÑки, ÑезÑлÑÑаÑÑ ÐºÐ¾ÑоÑÑÑ
могÑÑ Ð·Ð°Ð²Ð¸ÑеÑÑ Ð¾Ñ Ð¿Ð°ÑамеÑÑов GUC, опÑеделÑнно Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾Ð¿ÑÑкаÑÑÑÑ, когда check_function_bodies оÑклÑÑÑн, во избежание ложнÑÑ
оÑибок пÑи воÑÑÑановлении Ð±Ð°Ð·Ñ Ð¸Ð· копии.
ÐÑли Ð´Ð»Ñ Ð¿ÑоÑедÑÑного ÑзÑка пÑедоÑÑавлÑеÑÑÑ Ð¾Ð±ÑабоÑÑик вÑÑÑоенного кода, он должен обÑÑвлÑÑÑÑÑ Ð² виде ÑÑнкÑии, пÑинимаÑÑей один паÑамеÑÑ Ñипа internal. РезÑлÑÑÐ°Ñ Ñакого обÑабоÑÑика игноÑиÑÑеÑÑÑ, поÑÑÐ¾Ð¼Ñ Ð¾Ð±ÑÑно он обÑÑвлÑеÑÑÑ ÐºÐ°Ðº возвÑаÑаÑÑий Ñип void. ÐбÑабоÑÑик вÑÑÑоенного кода бÑÐ´ÐµÑ Ð²ÑзÑваÑÑÑÑ Ð¿Ñи вÑполнении опеÑаÑоÑа DO Ñ Ð´Ð°Ð½Ð½Ñм пÑоÑедÑÑнÑм ÑзÑком. РкаÑеÑÑве паÑамеÑÑа ÐµÐ¼Ñ Ð½Ð° Ñамом деле пеÑедаÑÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ InlineCodeBlock, ÑодеÑжаÑÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ паÑамеÑÑаÑ
DO, в ÑаÑÑноÑÑи, ÑекÑÑ Ð²ÑполнÑемого анонимного блока внедÑÑнного кода.
ÐÑе подобнÑе обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ ÑÑнкÑий, а Ñакже ÑÐ°Ð¼Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE LANGUAGE, ÑекомендÑеÑÑÑ ÑпаковÑваÑÑ Ð² ÑаÑÑиÑение Ñак, ÑÑÐ¾Ð±Ñ Ð´Ð»Ñ ÑÑÑановки ÑзÑка бÑло доÑÑаÑоÑно пÑоÑÑой ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE EXTENSION. Ðа инÑоÑмаÑией о ÑазÑабоÑке ÑаÑÑиÑений обÑаÑиÑеÑÑ Ðº РазделÑ 36.17.
РеализаÑÐ¸Ñ Ð¿ÑоÑедÑÑнÑÑ
ÑзÑков, вклÑÑÑннÑÑ
в ÑÑандаÑÑнÑй диÑÑÑибÑÑив, Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑлÑжиÑÑ Ñ
оÑоÑим пÑимеÑом пÑи напиÑании ÑобÑÑвеннÑÑ
обÑабоÑÑиков ÑзÑков. ÐÑ Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе найÑи в подкаÑалоге src/pl деÑева иÑÑ
одного кода. ÐекоÑоÑÑе полезнÑе деÑали Ñакже можно ÑзнаÑÑ Ð½Ð° ÑÑÑаниÑе ÑпÑавки CREATE LANGUAGE.