37.10. ФÑнкÑии на ÑзÑке C #
- 37.10.1. ÐинамиÑеÑÐºÐ°Ñ Ð·Ð°Ð³ÑÑзка
- 37.10.2. ÐазовÑе ÑÐ¸Ð¿Ñ Ð² ÑÑнкÑиÑÑ Ð½Ð° ÑзÑке C
- 37.10.3. СоглаÑение о вÑÐ·Ð¾Ð²Ð°Ñ Ð²ÐµÑÑии 1
- 37.10.4. ÐапиÑание кода
- 37.10.5. ÐомпилÑÑÐ¸Ñ Ð¸ компоновка динамиÑеÑки загÑÑжаемÑÑ ÑÑнкÑий
- 37.10.6. ÐÑгÑменÑÑ ÑоÑÑавного Ñипа
- 37.10.7. ÐозвÑÐ°Ñ ÑÑÑок (ÑоÑÑавнÑÑ Ñипов)
- 37.10.8. ÐозвÑÐ°Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑв
- 37.10.9. ÐолимоÑÑнÑе ÑÐ¸Ð¿Ñ Ð°ÑгÑменÑов и ÑезÑлÑÑаÑа
- 37.10.10. РазделÑÐµÐ¼Ð°Ñ Ð¿Ð°Ð¼ÑÑÑ Ð¸ лÑгкие блокиÑовки
- 37.10.11. ÐÑполÑзование C++ Ð´Ð»Ñ ÑаÑÑиÑÑемоÑÑи
- 37.10.2. ÐазовÑе ÑÐ¸Ð¿Ñ Ð² ÑÑнкÑиÑÑ Ð½Ð° ÑзÑке C
ÐолÑзоваÑелÑÑкие ÑÑнкÑии могÑÑ Ð±ÑÑÑ Ð½Ð°Ð¿Ð¸ÑÐ°Ð½Ñ Ð½Ð° C (или на ÑзÑке, коÑоÑÑй Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑовмеÑÑим Ñ C, напÑÐ¸Ð¼ÐµÑ C++). Такие ÑÑнкÑии компилиÑÑÑÑÑÑ Ð² динамиÑеÑки загÑÑжаемÑе обÑекÑÑ (Ñакже назÑваемÑе ÑазделÑемÑми библиоÑеками) и загÑÑжаÑÑÑÑ ÑеÑвеÑом по ÑÑебованиÑ. Ðменно меÑод динамиÑеÑкой загÑÑзки оÑлиÑÐ°ÐµÑ ÑÑнкÑии «на ÑзÑке C» Ð¾Ñ Â«Ð²Ð½ÑÑÑÐµÐ½Ð½Ð¸Ñ Â» ÑÑнкÑий â пÑавила напиÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° по ÑÑÑи одни и Ñе же. (СобÑÑвенно, поÑÑÐ¾Ð¼Ñ ÑÑандаÑÑÐ½Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñека внÑÑÑÐµÐ½Ð½Ð¸Ñ ÑÑнкÑий Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð¾Ð³Ð°ÑÑм иÑÑоÑником пÑимеÑов Ð´Ð»Ñ Ð½Ð°Ð¿Ð¸ÑÐ°Ð½Ð¸Ñ ÑобÑÑвеннÑÑ ÑÑнкÑий на ÑзÑке C.)
РнаÑÑоÑÑее вÑÐµÐ¼Ñ Ð´Ð»Ñ ÑÑнкÑий на C пÑименÑеÑÑÑ ÑолÑко одно ÑоглаÑение о вÑзоваÑ
(«веÑÑии 1»). ÐоддеÑжка ÑÑого ÑоглаÑÐµÐ½Ð¸Ñ Ð¾Ð±Ð¾Ð·Ð½Ð°ÑаеÑÑÑ Ð¾Ð±ÑÑвлением ÑÑнкÑии Ñ Ð¼Ð°ÐºÑоÑом (PG_FUNCTION_INFO_V1), как показано ниже.
37.10.1. ÐинамиÑеÑÐºÐ°Ñ Ð·Ð°Ð³ÑÑзка #
РпеÑвÑй Ñаз, когда в ÑеанÑе вÑзÑваеÑÑÑ Ð¿Ð¾Ð»ÑзоваÑелÑÑÐºÐ°Ñ ÑÑнкÑÐ¸Ñ Ð² опÑеделÑнном внеÑнем обÑекÑном Ñайле, загÑÑзÑик динамиÑеÑкиÑ
модÑлей загÑÑÐ¶Ð°ÐµÑ ÑÑÐ¾Ñ Ñайл в памÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¼Ð¾Ð¶Ð½Ð¾ бÑло вÑзваÑÑ ÑÑÑ ÑÑнкÑиÑ. Таким обÑазом, в команде CREATE FUNCTION, обÑÑвлÑÑÑей полÑзоваÑелÑÑкÑÑ ÑÑнкÑÐ¸Ñ Ð½Ð° ÑзÑке C, необÑ
одимо опÑеделиÑÑ Ð´Ð²Ðµ ÑÑÑноÑÑи Ð´Ð»Ñ ÑÑнкÑии: Ð¸Ð¼Ñ Ð·Ð°Ð³ÑÑжаемого обÑекÑного Ñайла и Ð¸Ð¼Ñ ÑÑÐ¾Ð²Ð½Ñ C (Ñимвол Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸) заданной ÑÑнкÑии в ÑÑом обÑекÑном Ñайле. ÐÑли Ð¸Ð¼Ñ ÑÑÐ¾Ð²Ð½Ñ C не Ñказано Ñвно, пÑедполагаеÑÑÑ, ÑÑо оно ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ ÑÑнкÑии в SQL.
ÐÐ»Ñ Ð½Ð°Ñ
Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ ÑазделÑемого обÑекÑного Ñайла по имени, Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ Ð² команде CREATE FUNCTION, пÑименÑеÑÑÑ ÑледÑÑÑий алгоÑиÑм:
ÐÑли Ð¸Ð¼Ñ Ð·Ð°Ð´Ð°ÑÑÑÑ Ð°Ð±ÑолÑÑнÑм пÑÑÑм, загÑÑжаеÑÑÑ Ð·Ð°Ð´Ð°Ð½Ð½Ñй Ñайл.
ÐÑли Ð¸Ð¼Ñ Ð½Ð°ÑинаеÑÑÑ Ñо ÑÑÑоки
$libdir, ÑÑа ÑаÑÑÑ Ð¿ÑÑи заменÑеÑÑÑ Ð¿ÑÑÑм к каÑÐ°Ð»Ð¾Ð³Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñек Postgres Pro, коÑоÑÑй опÑеделÑеÑÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ ÑбоÑки.ÐÑли в имени не ÑказÑваеÑÑÑ ÐºÐ°Ñалог, поиÑк Ñайла пÑоизводиÑÑÑ Ð¿Ð¾ пÑÑи, Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ ÐºÐ¾Ð½ÑигÑÑаÑионной пеÑеменной dynamic_library_path.
РпÑоÑивном ÑлÑÑае (Ñайл не бÑл найден в пÑÑи поиÑка, или в его имени ÑказÑваеÑÑÑ Ð½Ðµ абÑолÑÑнÑй пÑÑÑ Ðº каÑалогÑ), загÑÑзÑик попÑÑаеÑÑÑ Ð¿ÑинÑÑÑ Ð¸Ð¼Ñ ÐºÐ°Ðº еÑÑÑ, ÑÑо, ÑкоÑее вÑего, не ÑвенÑаеÑÑÑ ÑÑÐ¿ÐµÑ Ð¾Ð¼. (ÐолагаÑÑÑÑ Ð½Ð° ÑекÑÑий ÑабоÑий каÑалог ненадÑжно.)
ÐÑли ÑÑа поÑледоваÑелÑноÑÑÑ Ð½Ðµ даÑÑ Ð¿Ð¾Ð»Ð¾Ð¶Ð¸ÑелÑнÑй ÑезÑлÑÑаÑ, к Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ Ð¸Ð¼ÐµÐ½Ð¸ добавлÑеÑÑÑ Ð¿ÑинÑÑое на данной плаÑÑоÑме ÑаÑÑиÑение Ñайлов библиоÑек (ÑаÑÑо .so) и поÑледоваÑелÑноÑÑÑ Ð¿Ð¾Ð²ÑоÑÑеÑÑÑ Ñнова. ÐÑли и ÑÑо не пÑÐ¸Ð²Ð¾Ð´Ð¸Ñ Ðº ÑÑпеÑ
Ñ, пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ñбой загÑÑзки.
ÐÐ»Ñ Ð¿Ð¾Ð¸Ñка ÑазделÑемÑÑ
библиоÑек ÑекомендÑеÑÑÑ Ð·Ð°Ð´Ð°Ð²Ð°ÑÑ Ð»Ð¸Ð±Ð¾ пÑÑÑ Ð¾ÑноÑиÑелÑно $libdir, либо пÑÑÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑкиÑ
библиоÑек. ÐÑо ÑпÑоÑÐ°ÐµÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ðµ веÑÑии пÑи пеÑемеÑении новой инÑÑаллÑÑии в дÑÑгое меÑÑо. Ðакой именно каÑалог подÑазÑмеваеÑÑÑ Ð¿Ð¾Ð´ $libdir, можно ÑзнаÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ pg_config --pkglibdir.
ÐолÑзоваÑелÑ, Ð¾Ñ Ð¸Ð¼ÐµÐ½Ð¸ коÑоÑого ÑабоÑÐ°ÐµÑ ÑеÑÐ²ÐµÑ Postgres Pro, должен имеÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð¿ÑойÑи пÑÑÑ Ðº ÑайлÑ, коÑоÑÑй ÑÑебÑеÑÑÑ Ð·Ð°Ð³ÑÑзиÑÑ. ÐÑÐµÐ½Ñ ÑаÑпÑоÑÑÑанÑÐ½Ð½Ð°Ñ Ð¾Ñибка â когда Ñам Ñайл или каÑалог веÑÑ Ð½ÐµÐ³Ð¾ ÑÑÐ¾Ð²Ð½Ñ Ð¾ÐºÐ°Ð·ÑваеÑÑÑ Ð½ÐµÐ´Ð¾ÑÑÑпнÑм Ð´Ð»Ñ ÑÑÐµÐ½Ð¸Ñ Ð¸/или иÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ postgres.
РлÑбом ÑлÑÑае Ð¸Ð¼Ñ Ñайла, заданное в команде CREATE FUNCTION, запиÑÑваеÑÑÑ Ð² ÑиÑÑемнÑе каÑалоги бÑквалÑно, Ñак ÑÑо еÑли ÑÑÐ¾Ñ Ñайл поÑÑебÑеÑÑÑ Ð·Ð°Ð³ÑÑзиÑÑ ÐµÑÑ Ñаз, Ñа же пÑоÑедÑÑа бÑÐ´ÐµÑ Ð¿Ñоделана Ñнова.
ÐÑимеÑание
Postgres Pro не бÑÐ´ÐµÑ ÐºÐ¾Ð¼Ð¿Ð¸Ð»Ð¸ÑоваÑÑ ÑÑнкÑÐ¸Ñ Ð½Ð° C авÑомаÑиÑеÑки, поÑÑÐ¾Ð¼Ñ Ð¿Ñежде Ñем ÑÑÑлаÑÑÑÑ Ð½Ð° обÑекÑнÑй Ñайл в команде CREATE FUNCTION, его нÑжно ÑкомпилиÑоваÑÑ. Ðа дополниÑелÑнÑми ÑведениÑми обÑаÑиÑеÑÑ Ðº ÐодÑазделÑ 37.10.5.
ЧÑÐ¾Ð±Ñ Ð³Ð°ÑанÑиÑоваÑÑ, ÑÑо динамиÑеÑки загÑÑжаемÑй обÑекÑнÑй Ñайл не бÑÐ´ÐµÑ Ð·Ð°Ð³ÑÑжен неÑовмеÑÑимÑм ÑеÑвеÑом, Postgres Pro пÑовеÑÑеÑ, ÑодеÑÐ¶Ð¸Ñ Ð»Ð¸ ÑÑÐ¾Ñ Ñайл «оÑлиÑиÑелÑнÑй блок» Ñ ÑÑебÑемÑм ÑодеÑжимÑм ÐлагодаÑÑ ÑÑÐ¾Ð¼Ñ ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð¶ÐµÑ Ð²ÑÑвиÑÑ Ð¾ÑевиднÑÑ Ð½ÐµÑовмеÑÑимоÑÑÑ, напÑимеÑ, когда код ÑкомпилиÑован Ð´Ð»Ñ Ð´ÑÑгой ÑÑаÑÑей веÑÑии Postgres Pro. ÐÑлиÑиÑелÑнÑй блок ÑÑал обÑзаÑелÑнÑм, наÑÐ¸Ð½Ð°Ñ Ñ Ð²ÐµÑÑии PostgreSQL 8.2. ЧÑÐ¾Ð±Ñ Ð²ÐºÐ»ÑÑиÑÑ ÐµÐ³Ð¾ в Ñвой модÑлÑ, напиÑиÑе ÑÑо в одном (и ÑолÑко одном) из иÑÑ
однÑÑ
Ñайлов модÑлÑ, поÑле вклÑÑÐµÐ½Ð¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ñного Ñайла fmgr.h:
PG_MODULE_MAGIC;
ÐоÑле Ñого как он бÑл иÑполÑзован пеÑвÑй Ñаз, динамиÑеÑки загÑÑжаемÑй обÑекÑнÑй Ñайл ÑÐ¾Ñ ÑанÑеÑÑÑ Ð² памÑÑи. СледÑÑÑие обÑаÑÐµÐ½Ð¸Ñ Ð² Ñом же ÑеанÑе к ÑÑнкÑиÑм в ÑÑом Ñайле повлекÑÑ ÑолÑко неболÑÑие издеÑжки, ÑвÑзаннÑе Ñ Ð¿Ð¾Ð¸Ñком в ÑаблиÑе Ñимволов. ÐÑли вам нÑжно пÑинÑдиÑелÑно пеÑезагÑÑзиÑÑ Ð¾Ð±ÑекÑнÑй Ñайл, напÑимеÑ, поÑле пеÑекомпилÑÑии, наÑниÑе новÑй ÑеанÑ.
ÐинамиÑеÑки загÑÑжаемÑй Ñайл Ð¼Ð¾Ð¶ÐµÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑно ÑодеÑжаÑÑ ÑÑнкÑии иниÑиализаÑии и завеÑÑÐµÐ½Ð¸Ñ ÑабоÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñеки. ÐÑли в Ñайле наÑ
одиÑÑÑ ÑÑнкÑÐ¸Ñ Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ _PG_init, ÑÑа ÑÑнкÑÐ¸Ñ Ð±ÑÐ´ÐµÑ Ð²Ñзвана ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле загÑÑзки Ñайла. ÐÑа ÑÑнкÑÐ¸Ñ Ð½Ðµ пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð¿Ð°ÑамеÑÑÑ Ð¸ не должна ниÑего возвÑаÑаÑÑ. РнаÑÑоÑÑее вÑÐµÐ¼Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑи вÑгÑÑзиÑÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑки загÑÑженнÑй Ñайл неÑ.
37.10.2. ÐазовÑе ÑÐ¸Ð¿Ñ Ð² ÑÑнкÑиÑÑ Ð½Ð° ÑзÑке C #
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð½Ð¸Ð¼Ð°ÑÑ, как напиÑаÑÑ ÑÑнкÑÐ¸Ñ Ð½Ð° ÑзÑке C, Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð·Ð½Ð°ÑÑ, как внÑÑÑи Postgres Pro пÑедÑÑавлÑÑÑÑÑ Ð±Ð°Ð·Ð¾Ð²Ñе ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ Ð¸ как Ð¸Ñ Ð¼Ð¾Ð³ÑÑ Ð¿ÑинимаÑÑ Ð¸ пеÑедаваÑÑ ÑÑнкÑии. Postgres Pro внÑÑÑи воÑпÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð±Ð°Ð·Ð¾Ð²Ñе ÑÐ¸Ð¿Ñ ÐºÐ°Ðº «блоки памÑÑи». ÐолÑзоваÑелÑÑкие ÑÑнкÑии, ÑÑÑанавливаемÑе Ð´Ð»Ñ Ñипов, в ÑÐ²Ð¾Ñ Ð¾ÑеÑедÑ, опÑеделÑÑÑ, как Postgres Pro Ð¼Ð¾Ð¶ÐµÑ ÑабоÑаÑÑ Ñ ÑÑими Ñипами. То еÑÑÑ, Postgres Pro ÑолÑко ÑÐ¾Ñ ÑанÑÐµÑ Ð¸ загÑÑÐ¶Ð°ÐµÑ Ð´Ð°Ð½Ð½Ñе Ñ Ð´Ð¸Ñка, а Ð´Ð»Ñ Ð²Ð²Ð¾Ð´Ð°, обÑабоÑки и вÑвода даннÑÑ Ð¾Ð½ иÑполÑзÑÐµÑ Ð¾Ð¿ÑеделÑемÑе вами ÑÑнкÑии.
ÐазовÑе ÑÐ¸Ð¿Ñ Ð¼Ð¾Ð³ÑÑ Ð¸Ð¼ÐµÑÑ Ð¾Ð´Ð¸Ð½ из ÑÑÑÑ Ð²Ð½ÑÑÑÐµÐ½Ð½Ð¸Ñ ÑоÑмаÑов:
пеÑедаÑÑÑÑ Ð¿Ð¾ знаÑениÑ, ÑикÑиÑованной длинÑ
пеÑедаÑÑÑÑ Ð¿Ð¾ ÑÑÑлке, ÑикÑиÑованной длинÑ
пеÑедаÑÑÑÑ Ð¿Ð¾ ÑÑÑлке, пеÑеменной длинÑ
ТипÑ, пеÑедаваемÑе по знаÑениÑ, могÑÑ Ð¸Ð¼ÐµÑÑ ÑÐ°Ð·Ð¼ÐµÑ ÑолÑко 1, 2 или 4 байÑа (и 8 байÑ, еÑли sizeof(Datum) Ñавен 8 на ваÑей маÑине). ÐпÑеделÑÑ ÑобÑÑвеннÑе ÑипÑ, ÑледÑÐµÑ Ð¿Ð¾Ð·Ð°Ð±Ð¾ÑиÑÑÑÑ Ð¾ Ñом, ÑÑÐ¾Ð±Ñ Ð¾Ð½Ð¸ имели одинаковÑй ÑÐ°Ð·Ð¼ÐµÑ (в байÑаÑ
) во вÑеÑ
аÑÑ
иÑекÑÑÑаÑ
. ÐапÑимеÑ, Ñип long опаÑен, Ñак как он Ð¸Ð¼ÐµÐµÑ ÑÐ°Ð·Ð¼ÐµÑ 4 байÑа на одниÑ
маÑинаÑ
, и 8 Ð±Ð°Ð¹Ñ Ð½Ð° дÑÑгиÑ
, Ñогда как Ñип int ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· 4 Ð±Ð°Ð¹Ñ Ð² болÑÑинÑÑве ÑиÑÑем Unix. ÐоÑÑÐ¾Ð¼Ñ ÑазÑмной ÑеализаÑией Ñипа int4 на плаÑÑоÑме Unix Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑакаÑ:
/* 4-байÑное Ñелое, пеÑедаÑÑÑÑ Ð¿Ð¾ знаÑÐµÐ½Ð¸Ñ */ typedef int int4;
(Ркоде ÑобÑÑвенно Postgres Pro ÑÑÐ¾Ñ Ñип назÑваеÑÑÑ int32, Ñак как в C пÑинÑÑо ÑоглаÑение, ÑÑо int подÑазÑÐ¼ÐµÐ²Ð°ÐµÑ XXXX биÑ. ÐамеÑÑÑе, ÑÑо вÑледÑÑвие ÑÑого Ñип int8 в C Ð¸Ð¼ÐµÐµÑ ÑÐ°Ð·Ð¼ÐµÑ 1 байÑ. Тип int8, пÑинÑÑÑй в SQL, в C назÑваеÑÑÑ int64. См. Ñакже ТаблиÑÑ 37.2.)
С дÑÑгой ÑÑоÑонÑ, ÑÐ¸Ð¿Ñ ÑикÑиÑованной Ð´Ð»Ð¸Ð½Ñ Ð»Ñбого ÑазмеÑа можно пеÑедаваÑÑ Ð¿Ð¾ ÑÑÑлке. ÐапÑимеÑ, взглÑниÑе на пÑÐ¸Ð¼ÐµÑ ÑеализаÑии Ñипа Postgres Pro:
/* 16-байÑÐ½Ð°Ñ ÑÑÑÑкÑÑÑа, пеÑедаÑÑÑÑ Ð¿Ð¾ ÑÑÑлке */
typedef struct
{
double x, y;
} Point; Ð ÑÑнкÑии Postgres Pro и из ниÑ
могÑÑ Ð¿ÐµÑедаваÑÑÑÑ ÑолÑко ÑказаÑели на Ñакие ÑипÑ. ЧÑÐ¾Ð±Ñ Ð²ÐµÑнÑÑÑ Ð·Ð½Ð°Ñение Ñакого Ñипа, вÑделиÑе Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ нÑжное колиÑеÑÑво памÑÑи ÑÑнкÑией palloc, заполниÑе вÑделеннÑÑ Ð¿Ð°Ð¼ÑÑÑ Ð¸ веÑниÑе ÑказаÑÐµÐ»Ñ Ð½Ð° неÑ. (ÐÑли Ð²Ñ Ð·Ð°Ñ
оÑиÑе пÑоÑÑо веÑнÑÑÑ Ñо же знаÑение, ÑÑо бÑло полÑÑено во вÑ
одном аÑгÑменÑе ÑÑого же Ñипа даннÑÑ
, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑопÑÑÑиÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑй вÑзов palloc и пÑоÑÑо веÑнÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑо поÑÑÑпивÑее знаÑение.)
ÐаконеÑ, вÑе ÑÐ¸Ð¿Ñ Ð¿ÐµÑеменной Ð´Ð»Ð¸Ð½Ñ Ñакже Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÐµÑедаваÑÑÑÑ Ð¿Ð¾ ÑÑÑлке. ÐÑе ÑÐ¸Ð¿Ñ Ð¿ÐµÑеменной Ð´Ð»Ð¸Ð½Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð½Ð°ÑинаÑÑÑÑ Ñ Ð¾Ð±ÑзаÑелÑного Ð¿Ð¾Ð»Ñ Ð´Ð»Ð¸Ð½Ñ ÑазмеÑом Ñовно 4 байÑа, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð·Ð°Ð´Ð°Ð²Ð°ÑÑÑÑ Ð¼Ð°ÐºÑоÑом SET_VARSIZE; никогда не ÑÑÑанавливайÑе ÑÑо поле вÑÑÑнÑÑ! ÐÑе даннÑе, коÑоÑÑе бÑдÑÑ Ñ
ÑаниÑÑÑÑ Ð² ÑÑом Ñипе, Ð´Ð¾Ð»Ð¶Ð½Ñ ÑазмеÑаÑÑÑÑ Ð² памÑÑи непоÑÑедÑÑвенно за ÑÑим полем длинÑ. Ðоле Ð´Ð»Ð¸Ð½Ñ ÑодеÑÐ¶Ð¸Ñ Ð¿Ð¾Ð»Ð½ÑÑ Ð´Ð»Ð¸Ð½Ñ ÑÑÑÑкÑÑÑÑ, Ñо еÑÑÑ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐ°Ð·Ð¼ÐµÑ Ñамого Ð¿Ð¾Ð»Ñ Ð´Ð»Ð¸Ð½Ñ.
ÐÑÑ Ð¾Ð´Ð¸Ð½ важнÑй Ð¼Ð¾Ð¼ÐµÐ½Ñ â ÑÑаÑайÑеÑÑ Ð½Ðµ оÑÑавлÑÑÑ Ð½ÐµÐ¸Ð½Ð¸ÑиализиÑованнÑÑ Ð±Ð°Ð¹Ñ Ð² знаÑениÑÑ Ð´Ð°Ð½Ð½ÑÑ ; напÑимеÑ, обнÑлÑйÑе вÑе возможнÑе байÑÑ Ð²ÑÑавниваниÑ, коÑоÑÑе могÑÑ Ð¿ÑиÑÑÑÑÑвоваÑÑ Ð² ÑÑÑÑкÑÑÑÐ°Ñ . ÐÑли ÑÑого не делаÑÑ, логиÑеÑки ÑавнÑе знаÑÐµÐ½Ð¸Ñ Ð²Ð°ÑÐ¸Ñ Ð´Ð°Ð½Ð½ÑÑ Ð¼Ð¾Ð³ÑÑ Ð¿ÑедÑÑавлÑÑÑÑÑ Ð½ÐµÑавнÑми планиÑовÑикÑ, ÑÑо пÑиведÑÑ Ðº поÑÑÑÐ¾ÐµÐ½Ð¸Ñ Ð½ÐµÑÑÑекÑивнÑÑ (Ñ Ð¾ÑÑ Ð¸ коÑÑекÑнÑÑ ) планов.
ÐÑедÑпÑеждение
Ðикогда не изменÑйÑе ÑодеÑжимое, пеÑедаваемое на Ð²Ñ Ð¾Ð´ по ÑÑÑлке. ÐÑли Ð²Ñ ÑделаеÑе ÑÑо, Ð²Ñ ÑкоÑее вÑего иÑпоÑÑиÑе даннÑе на диÑке, Ñак как полÑÑеннÑй вами ÑказаÑÐµÐ»Ñ ÑказÑÐ²Ð°ÐµÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно на меÑÑо в диÑковом бÑÑеÑе. ÐдинÑÑвенное иÑклÑÑение из ÑÑого пÑавила оÑвеÑаеÑÑÑ Ð² Разделе 37.12.
РкаÑеÑÑве пÑимеÑа Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ опÑеделиÑÑ Ñип text Ñак:
typedef struct {
int32 length;
char data[FLEXIBLE_ARRAY_MEMBER];
} text; ÐапиÑÑ [FLEXIBLE_ARRAY_MEMBER] ознаÑаеÑ, ÑÑо дейÑÑвиÑелÑÐ½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° маÑÑива даннÑÑ
в ÑÑом обÑÑвлении не ÑказÑваеÑÑÑ.
РабоÑÐ°Ñ Ñ Ñипами пеÑеменной длинÑ, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð°ÐºÐºÑÑаÑно вÑделиÑÑ Ð½ÑжнÑй обÑÑм памÑÑи и запиÑаÑÑ ÐµÐ³Ð¾ ÑÐ°Ð·Ð¼ÐµÑ Ð² поле длинÑ. ÐапÑимеÑ, еÑли нÑжно ÑоÑ
ÑаниÑÑ 40 Ð±Ð°Ð¹Ñ Ð² ÑÑÑÑкÑÑÑе text, можно пÑимениÑÑ Ñакой код:
#include "postgres.h" ... char buffer[40]; /* our source data */ ... text *destination = (text *) palloc(VARHDRSZ + 40); SET_VARSIZE(destination, VARHDRSZ + 40); memcpy(destination->data, buffer, 40); ...
VARHDRSZ ÑÐ¾Ð²Ð¿Ð°Ð´Ð°ÐµÑ Ñ sizeof(int32), но Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑазмеÑа заголовка Ñипа пеÑеменной Ð´Ð»Ð¸Ð½Ñ Ñ
оÑоÑим ÑÑилем ÑÑиÑаеÑÑÑ Ð¿ÑименÑÑÑ Ð¼Ð°ÐºÑÐ¾Ñ VARHDRSZ. ÐÑоме Ñого, поле Ð´Ð»Ð¸Ð½Ñ Ð´Ð¾Ð»Ð¶Ð½Ð¾ ÑÑÑанавливаÑÑÑÑ Ð¼Ð°ÐºÑоÑом SET_VARSIZE, а не пÑоÑÑÑм пÑиÑваиванием.
РТаблиÑе 37.2 Ñказано, какие ÑÐ¸Ð¿Ñ ÑзÑка C ÑооÑвеÑÑÑвÑÑÑ Ñипам SQL пÑи напиÑании ÑÑнкÑий на C Ñ Ð¸ÑполÑзованием вÑÑÑоеннÑÑ
Ñипов Postgres Pro. Ð ÑÑолбÑе «ÐпÑеделÑн в» ÑказÑваеÑÑÑ, какой заголовоÑнÑй Ñайл необÑ
одимо подклÑÑиÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð¾Ð¿Ñеделение Ñипа. (ФакÑиÑеÑкое опÑеделение Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð² дÑÑгом Ñайле, коÑоÑÑй подклÑÑаеÑÑÑ Ð¸Ð· Ñказанного, однако ÑекомендÑеÑÑÑ Ð¿ÑидеÑживаÑÑÑÑ Ð¾Ð±Ð¾Ð·Ð½Ð°Ñенного инÑеÑÑейÑа.) ÐамеÑÑÑе, ÑÑо в лÑбом иÑÑ
одном Ñайле пеÑвÑм вÑегда необÑ
одимо вклÑÑаÑÑ postgres.h, поÑÐ¾Ð¼Ñ ÑÑо в нÑм обÑÑвлÑеÑÑÑ ÑÑд веÑей, коÑоÑÑе нÑÐ¶Ð½Ñ Ð² лÑбом ÑлÑÑае, и поÑÐ¾Ð¼Ñ ÑÑо вклÑÑение пеÑвÑм дÑÑгого заголовоÑного Ñайла Ð¼Ð¾Ð¶ÐµÑ ÑделаÑÑ ÐºÐ¾Ð´ непеÑеноÑимÑм.
ТаблиÑа 37.2. Ð¢Ð¸Ð¿Ñ C, ÑквиваленÑнÑе вÑÑÑоеннÑм Ñипам SQL
| Тип SQL | Тип C | ÐпÑеделÑн в |
|---|---|---|
boolean | bool | postgres.h (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²ÑÑÑоен в компилÑÑоÑе) |
box | BOX* | utils/geo_decls.h |
bytea | bytea* | postgres.h |
"char" | char | (вÑÑÑоен в компилÑÑоÑе) |
character | BpChar* | postgres.h |
cid | CommandId | postgres.h |
date | DateADT | utils/date.h |
float4 (real) | float4 | postgres.h |
float8 (double precision) | float8 | postgres.h |
int2 (smallint) | int16 | postgres.h |
int4 (integer) | int32 | postgres.h |
int8 (bigint) | int64 | postgres.h |
interval | Interval* | datatype/timestamp.h |
lseg | LSEG* | utils/geo_decls.h |
name | Name | postgres.h |
numeric | Numeric | utils/numeric.h |
oid | Oid | postgres.h |
oidvector | oidvector* | postgres.h |
path | PATH* | utils/geo_decls.h |
point | POINT* | utils/geo_decls.h |
regproc | RegProcedure | postgres.h |
text | text* | postgres.h |
tid | ItemPointer | storage/itemptr.h |
time | TimeADT | utils/date.h |
time with time zone | TimeTzADT | utils/date.h |
timestamp | Timestamp | datatype/timestamp.h |
timestamp with time zone | TimestampTz | datatype/timestamp.h |
varchar | VarChar* | postgres.h |
xid | TransactionId | postgres.h |
ТепеÑÑ, когда Ð¼Ñ ÑаÑÑмоÑÑели вÑе возможнÑе ÑÑÑÑкÑÑÑÑ Ð´Ð»Ñ Ð±Ð°Ð·Ð¾Ð²ÑÑ Ñипов, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ пеÑейÑи к пÑимеÑам ÑеалÑнÑÑ ÑÑнкÑий.
37.10.3. СоглаÑение о вÑÐ·Ð¾Ð²Ð°Ñ Ð²ÐµÑÑии 1 #
СоглаÑение о вÑÐ·Ð¾Ð²Ð°Ñ Ð²ÐµÑÑии 1 полагаеÑÑÑ Ð½Ð° макÑоÑÑ, ÑкÑÑваÑÑие оÑновнÑÑ Ð´Ð¾Ð»Ñ ÑложноÑÑей, ÑвÑзаннÑÑ Ñ Ð¿ÐµÑедаÑей аÑгÑменÑов и ÑезÑлÑÑаÑов. Ðо ÑоглаÑÐµÐ½Ð¸Ñ Ð²ÐµÑÑии 1 ÑÑнкÑÐ¸Ñ Ð½Ð° C должна вÑегда опÑеделÑÑÑÑÑ Ñак:
Datum funcname(PG_FUNCTION_ARGS)
Рдополнение к ÑÑомÑ, в Ñом же иÑÑ Ð¾Ð´Ð½Ð¾Ð¼ Ñайле должен пÑиÑÑÑÑÑвоваÑÑ Ð²Ñзов макÑоÑа:
PG_FUNCTION_INFO_V1(funcname);
(ÐбÑÑно его пÑинÑÑо запиÑÑваÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно пеÑед ÑÑнкÑией.) ÐÑÐ¾Ñ Ð²Ñзов макÑоÑа не нÑжен Ð´Ð»Ñ ÑÑнкÑий internal, Ñак как Postgres Pro пÑедполагаеÑ, ÑÑо вÑе внÑÑÑенние ÑÑнкÑии иÑполÑзÑÑÑ ÑоглаÑении веÑÑии 1. Ðднако Ð´Ð»Ñ ÑÑнкÑий, загÑÑжаемÑÑ
динамиÑеÑки, ÑÑÐ¾Ñ Ð¼Ð°ÐºÑÐ¾Ñ Ð½ÐµÐ¾Ð±Ñ
одим.
Ð ÑÑнкÑии веÑÑии 1 каждÑй аÑгÑÐ¼ÐµÐ½Ñ Ð²ÑбиÑаеÑÑÑ Ð¼Ð°ÐºÑоÑом PG_GETARG_, коÑоÑÑй ÑооÑвеÑÑÑвÑÐµÑ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
аÑгÑменÑа. РнеÑÑÑогиÑ
ÑÑнкÑиÑÑ
ÑÑÐ¾Ð¼Ñ Ð²ÑÐ·Ð¾Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° пÑедÑеÑÑвоваÑÑ Ð¿ÑовеÑка на NULL в аÑгÑменÑе Ñ Ð¸ÑполÑзованием xxx()PG_ARGISNULL() (Ñм. ниже). РезÑлÑÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑаеÑÑÑ Ð¼Ð°ÐºÑоÑом PG_RETURN_ Ð´Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑаемого Ñипа. xxx()PG_GETARG_ пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð² каÑеÑÑве паÑамеÑÑа Ð½Ð¾Ð¼ÐµÑ Ð²ÑбиÑаемого аÑгÑменÑа ÑÑнкÑии (нÑмеÑаÑÐ¸Ñ Ð½Ð°ÑинаеÑÑÑ Ñ 0). xxx()PG_RETURN_ пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ ÑакÑиÑеÑкое знаÑение, коÑоÑое нÑжно возвÑаÑиÑÑ.xxx()
ÐеÑколÑко пÑимеÑов иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑоглаÑÐµÐ½Ð¸Ñ Ð¾ вÑÐ·Ð¾Ð²Ð°Ñ Ð²ÐµÑÑии 1:
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include "varatt.h"
PG_MODULE_MAGIC;
/* by value */
PG_FUNCTION_INFO_V1(add_one);
Datum
add_one(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg + 1);
}
/* by reference, fixed length */
PG_FUNCTION_INFO_V1(add_one_float8);
Datum
add_one_float8(PG_FUNCTION_ARGS)
{
/* The macros for FLOAT8 hide its pass-by-reference nature. */
float8 arg = PG_GETARG_FLOAT8(0);
PG_RETURN_FLOAT8(arg + 1.0);
}
PG_FUNCTION_INFO_V1(makepoint);
Datum
makepoint(PG_FUNCTION_ARGS)
{
/* Here, the pass-by-reference nature of Point is not hidden. */
Point *pointx = PG_GETARG_POINT_P(0);
Point *pointy = PG_GETARG_POINT_P(1);
Point *new_point = (Point *) palloc(sizeof(Point));
new_point->x = pointx->x;
new_point->y = pointy->y;
PG_RETURN_POINT_P(new_point);
}
/* by reference, variable length */
PG_FUNCTION_INFO_V1(copytext);
Datum
copytext(PG_FUNCTION_ARGS)
{
text *t = PG_GETARG_TEXT_PP(0);
/*
* VARSIZE_ANY_EXHDR is the size of the struct in bytes, minus the
* VARHDRSZ or VARHDRSZ_SHORT of its header. Construct the copy with a
* full-length header.
*/
text *new_t = (text *) palloc(VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
SET_VARSIZE(new_t, VARSIZE_ANY_EXHDR(t) + VARHDRSZ);
/*
* VARDATA is a pointer to the data region of the new struct. The source
* could be a short datum, so retrieve its data through VARDATA_ANY.
*/
memcpy(VARDATA(new_t), /* destination */
VARDATA_ANY(t), /* source */
VARSIZE_ANY_EXHDR(t)); /* how many bytes */
PG_RETURN_TEXT_P(new_t);
}
PG_FUNCTION_INFO_V1(concat_text);
Datum
concat_text(PG_FUNCTION_ARGS)
{
text *arg1 = PG_GETARG_TEXT_PP(0);
text *arg2 = PG_GETARG_TEXT_PP(1);
int32 arg1_size = VARSIZE_ANY_EXHDR(arg1);
int32 arg2_size = VARSIZE_ANY_EXHDR(arg2);
int32 new_text_size = arg1_size + arg2_size + VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
SET_VARSIZE(new_text, new_text_size);
memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size);
memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size);
PG_RETURN_TEXT_P(new_text);
}
РпÑедположении, ÑÑо пÑиведÑннÑй вÑÑе код бÑл подгоÑовлен в Ñайле funcs.c и ÑкомпилиÑован в ÑазделÑемÑй обÑекÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ обÑÑвиÑÑ ÑÑи ÑÑнкÑии в Postgres Pro ÑледÑÑÑими командами:
CREATE FUNCTION add_one(integer) RETURNS integer
AS 'ÐÐТÐÐÐÐ/funcs', 'add_one'
LANGUAGE C STRICT;
-- обÑаÑиÑе внимание â ÑÑо пеÑегÑÑзка SQL-ÑÑнкÑии "add_one"
CREATE FUNCTION add_one(double precision) RETURNS double precision
AS 'ÐÐТÐÐÐÐ/funcs', 'add_one_float8'
LANGUAGE C STRICT;
CREATE FUNCTION makepoint(point, point) RETURNS point
AS 'ÐÐТÐÐÐÐ/funcs', 'makepoint'
LANGUAGE C STRICT;
CREATE FUNCTION copytext(text) RETURNS text
AS 'ÐÐТÐÐÐÐ/funcs', 'copytext'
LANGUAGE C STRICT;
CREATE FUNCTION concat_text(text, text) RETURNS text
AS 'ÐÐТÐÐÐÐ/funcs', 'concat_text'
LANGUAGE C STRICT;ÐдеÑÑ ÐÐТÐÐÐÐ â ÑÑо пÑÑÑ Ðº каÑалогÑ, в коÑоÑÑй помеÑÑн ÑазделÑемÑй библиоÑеÑнÑй Ñайл (напÑимеÑ, каÑалог ÑÑебнÑÑ
маÑеÑиалов (tutorial) в иÑÑ
одном коде Postgres Pro, ÑодеÑжаÑий код пÑимеÑов, иÑполÑзованнÑÑ
в ÑÑом Ñазделе). (ÐÑÑÑе бÑло Ð±Ñ Ð¿ÑоÑÑо напиÑаÑÑ 'funcs' в пÑедложении AS, пÑедваÑиÑелÑно добавив ÐÐТÐÐÐРв пÑÑÑ Ð¿Ð¾Ð¸Ñка. РлÑбом ÑлÑÑае Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ опÑÑÑиÑÑ Ð¿ÑинÑÑое в ÑиÑÑеме ÑаÑÑиÑение Ñайлов ÑазделÑемÑÑ
библиоÑек, обÑÑно .so.)
ÐамеÑÑÑе, ÑÑо Ð¼Ñ Ð¾Ð±ÑÑвили ÑÑи ÑÑнкÑии как «strict» (ÑÑÑогие) â ÑÑо ознаÑаеÑ, ÑÑо ÑиÑÑема бÑÐ´ÐµÑ Ð°Ð²ÑомаÑиÑеÑки подÑазÑмеваÑÑ ÑезÑлÑÑÐ°Ñ NULL, еÑли в одном из вÑ
однÑÑ
знаÑений пеÑедаÑÑÑÑ NULL. ÐлагодаÑÑ ÑÑомÑ, Ð¼Ñ Ð¸Ð·Ð±ÐµÐ³Ð°ÐµÐ¼ необÑ
одимоÑÑи пÑовеÑÑÑÑ Ð²Ñ
однÑе знаÑÐµÐ½Ð¸Ñ Ð½Ð° NULL в коде ÑÑнкÑии. Ðез Ñакого обÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð½Ð°Ð¼ пÑиÑлоÑÑ Ð±Ñ Ñвно пÑовеÑÑÑÑ Ð¿Ð°ÑамеÑÑÑ Ð½Ð° NULL, иÑполÑзÑÑ PG_ARGISNULL().
ÐакÑÐ¾Ñ PG_ARGISNULL( позволÑÐµÑ ÑÑнкÑии пÑовеÑиÑÑ Ð½Ð° NULL каждÑй из ÐµÑ Ð°ÑгÑменÑов. (РазÑмееÑÑÑ, ÑÑо нÑжно делаÑÑ ÑолÑко в ÑÑнкÑиÑÑ
, обÑÑвленнÑÑ
без Ñ
аÑакÑеÑиÑÑики «strict».) Ðак и Ñ Ð¼Ð°ÐºÑоÑом n)PG_GETARG_, вÑ
однÑе аÑгÑменÑÑ Ð½ÑмеÑÑÑÑÑÑ, наÑÐ¸Ð½Ð°Ñ Ñ Ð½ÑлÑ. ÐамеÑÑÑе, ÑÑо не ÑледÑÐµÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº макÑоÑÑ xxx()PG_GETARG_, не ÑбедивÑиÑÑ, ÑÑо ÑооÑвеÑÑÑвÑÑÑий аÑгÑÐ¼ÐµÐ½Ñ Ð½Ðµ NULL. ЧÑÐ¾Ð±Ñ Ð²Ð¾Ð·Ð²ÑаÑиÑÑ NULL в каÑеÑÑве ÑезÑлÑÑаÑа, воÑполÑзÑйÑеÑÑ Ð¼Ð°ÐºÑоÑом xxx()PG_RETURN_NULL(); ÑÑо ÑабоÑÐ°ÐµÑ Ð¸ Ñо ÑÑÑогими, и Ñ Ð½ÐµÑÑÑогими ÑÑнкÑиÑми.
Ðа пеÑвÑй взглÑд ÑоглаÑÐµÐ½Ð¸Ñ Ð¾ вÑзоваÑ
веÑÑии 1 могÑÑ Ð¿Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ Ð²Ñего лиÑÑ Ð±ÐµÑÑмÑÑленнÑм мÑакобеÑием, по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ ÑоглаÑениÑми пÑоÑÑого C. Ðднако они позволÑÑÑ ÑабоÑаÑÑ Ñ Ð°ÑгÑменÑами и возвÑаÑаемÑми знаÑениÑми, в коÑоÑÑÑ
Ð¼Ð¾Ð¶ÐµÑ Ð¿ÐµÑедаваÑÑÑÑ NULL, а Ñакже Ñо знаÑениÑми в ÑоÑмаÑе TOAST (ÑжаÑÑми или Ñ
ÑанимÑми оÑделÑно).
ÐÑоме Ñого, в инÑеÑÑейÑе веÑÑии 1 поÑвилиÑÑ Ð´Ð²Ðµ ваÑиаÑии макÑоÑа PG_GETARG_. ÐеÑÐ²Ð°Ñ Ð²Ð°ÑиаÑиÑ, xxx()PG_GETARG_, гаÑанÑиÑованно возвÑаÑÐ°ÐµÑ ÐºÐ¾Ð¿Ð¸Ñ Ñказанного аÑгÑменÑа, коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ безопаÑно модиÑиÑиÑоваÑÑ. (ÐбÑÑнÑй макÑÐ¾Ñ Ð¸Ð½Ð¾Ð³Ð´Ð° возвÑаÑÐ°ÐµÑ ÑказаÑÐµÐ»Ñ Ð½Ð° знаÑение, коÑоÑое ÑизиÑеÑки Ñ
ÑаниÑÑÑ Ð² ÑаблиÑе, в коÑоÑÑÑ Ð½ÐµÐ»ÑÐ·Ñ Ð¿Ð¸ÑаÑÑ. С макÑоÑом xxx_COPY()PG_GETARG_ гаÑанÑиÑованно полÑÑаеÑÑÑ ÑезÑлÑÑаÑ, доÑÑÑпнÑй Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи.) ÐÑоÑÐ°Ñ Ð²Ð°ÑиаÑÐ¸Ñ Ð¿ÑедÑÑавлена макÑоÑом xxx_COPY()PG_GETARG_, пÑинимаÑÑим ÑÑи паÑамеÑÑа. РпеÑвом пеÑедаÑÑÑÑ Ð½Ð¾Ð¼ÐµÑ Ð°ÑгÑменÑа ÑÑнкÑии (как и ÑанÑÑе). Ðо вÑоÑом и ÑÑеÑÑем пеÑедаÑÑÑÑ ÑмеÑение и длина ÑегменÑа, коÑоÑÑй должен бÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑÑн. СмеÑение оÑÑÑиÑÑваеÑÑÑ Ñ Ð½ÑлÑ, а оÑÑиÑаÑелÑÐ½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° ÑказÑваеÑ, ÑÑо запÑаÑиваеÑÑÑ Ð¾ÑÑавÑаÑÑÑ ÑаÑÑÑ Ð·Ð½Ð°ÑениÑ. ÐÑи макÑоÑÑ Ð´Ð°ÑÑ Ð±Ð¾Ð»ÐµÐµ ÑÑÑекÑивнÑй доÑÑÑп к ÑаÑÑÑм болÑÑиÑ
знаÑений, имеÑÑим Ñип Ñ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ Â«external». (Тип Ñ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ ÑÑолбÑа Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð´Ð°Ð²Ð°ÑÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ xxx_SLICE()ALTER TABLE , где имÑ_ÑаблиÑÑ ALTER COLUMN имÑ_ÑÑолбÑа SET STORAGE Ñип_Ñ
ÑанениÑÑип_Ñ
ÑанениÑ: plain, external, extended или main.)
ÐаконеÑ, ÑоглаÑÐµÐ½Ð¸Ñ Ð¾ вÑÐ·Ð¾Ð²Ð°Ñ Ð²ÐµÑÑии 1 позволÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑва (ÐодÑаздел 37.10.8) и ÑеализовÑваÑÑ ÑÑиггеÑнÑе ÑÑнкÑии (Ðлава 38) и обÑабоÑÑики вÑзовов пÑоÑедÑÑнÑÑ ÑзÑков (Ðлава 55).
37.10.4. ÐапиÑание кода #
ÐÑежде Ñем пеÑейÑи к более ÑложнÑм Ñемам, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾Ð±ÑÑдиÑÑ Ð½ÐµÐºÐ¾ÑоÑÑе пÑавила напиÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° ÑÑнкÑий на ÑзÑке C Ð´Ð»Ñ Postgres Pro. ХоÑÑ Ð¿ÑинÑипиалÑно можно загÑÑжаÑÑ Ð² Postgres Pro ÑÑнкÑии, напиÑаннÑе на ÑзÑÐºÐ°Ñ , оÑлиÑнÑÑ Ð¾Ñ C, обÑÑно ÑÑо доволÑно Ñложно (когда вообÑе возможно), Ñак как дÑÑгие ÑзÑки, напÑÐ¸Ð¼ÐµÑ C++, FORTRAN или Pascal ÑаÑÑо не ÑледÑÑÑ ÑоглаÑениÑм, пÑинÑÑÑм в C. То еÑÑÑ Ð´ÑÑгие ÑзÑки могÑÑ Ð¿ÐµÑедаваÑÑ Ð°ÑгÑменÑÑ Ð¸ возвÑаÑаемÑе знаÑÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñ ÑÑнкÑиÑми ÑазнÑми ÑпоÑобами. ÐоÑÑÐ¾Ð¼Ñ Ð´Ð°Ð»ÐµÐµ пÑедполагаеÑÑÑ, ÑÑо ваÑи ÑÑнкÑии на ÑзÑке C дейÑÑвиÑелÑно напиÑÐ°Ð½Ñ Ð½Ð° C.
ÐÑновнÑе пÑавила напиÑÐ°Ð½Ð¸Ñ Ð¸ компилÑÑии ÑÑнкÑий на C ÑаковÑ:
ЧÑÐ¾Ð±Ñ Ð²ÑÑÑниÑÑ, где Ð½Ð°Ñ Ð¾Ð´ÑÑÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾ÑнÑе ÑÐ°Ð¹Ð»Ñ ÑеÑвеÑа Postgres Pro, ÑÑÑановленнÑе в ваÑей ÑиÑÑеме (или в ÑиÑÑеме, Ñ ÐºÐ¾ÑоÑой бÑдÑÑ ÑабоÑаÑÑ Ð²Ð°Ñи полÑзоваÑели), воÑполÑзÑйÑеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹
pg_config --includedir-server.ÐÐ»Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии и компоновки кода, коÑоÑÑй можно бÑÐ´ÐµÑ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÑеÑки загÑÑзиÑÑ Ð² Postgres Pro, ÑÑебÑеÑÑÑ ÑказаÑÑ ÑпеÑиалÑнÑе Ñлаги. ЧÑÐ¾Ð±Ñ ÐºÐ¾Ð½ÐºÑеÑнее ÑзнаÑÑ, как ÑÑо ÑделаÑÑ Ð² ваÑей конкÑеÑной опеÑаÑионной ÑиÑÑеме, обÑаÑиÑеÑÑ Ðº ÐодÑазделÑ 37.10.5.
Ðе забÑдÑÑе опÑеделиÑÑ Â«Ð¾ÑлиÑиÑелÑнÑй блок» Ð´Ð»Ñ Ð²Ð°Ñей ÑазделÑемой библиоÑеки, как опиÑано в ÐодÑазделе 37.10.1.
ÐÐ»Ñ Ð²ÑÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ð°Ð¼ÑÑи иÑполÑзÑйÑе ÑÑнкÑÐ¸Ñ Postgres Pro
palloc, а Ð´Ð»Ñ Ð¾ÑвобождениÑpfree, вмеÑÑо ÑооÑвеÑÑÑвÑÑÑÐ¸Ñ ÑÑнкÑий библиоÑеки Cmallocиfree. ÐамÑÑÑ, вÑделÑÐµÐ¼Ð°Ñ ÑÑнкÑиейpalloc, бÑÐ´ÐµÑ Ð°Ð²ÑомаÑиÑеÑки оÑвобождаÑÑÑÑ Ð² конÑе каждой ÑÑанзакÑии, во избежание ÑÑеÑек памÑÑи.ÐÑегда обнÑлÑйÑе байÑÑ Ð²Ð°ÑÐ¸Ñ ÑÑÑÑкÑÑÑ, пÑименÑÑ
memset(или ÑÑÐ°Ð·Ñ Ð²ÑделÑйÑе памÑÑÑ ÑÑнкÑиейpalloc0). Ðаже еÑли Ð²Ñ Ð¿ÑиÑвоиÑе знаÑение ÐºÐ°Ð¶Ð´Ð¾Ð¼Ñ Ð¿Ð¾Ð»Ñ ÑÑÑÑкÑÑÑÑ, в ней могÑÑ Ð¾ÑÑаваÑÑÑÑ Ð±Ð°Ð¹ÑÑ Ð²ÑÑÐ°Ð²Ð½Ð¸Ð²Ð°Ð½Ð¸Ñ (пÑÑÑоÑÑ Ð² ÑÑÑÑкÑÑÑе), ÑодеÑжаÑие ÑлÑÑайнÑе знаÑениÑ. ÐÑли иÑклÑÑиÑÑ ÑÑо ÑÑебование, бÑÐ´ÐµÑ Ñложно поддеÑживаÑÑ Ð¸Ð½Ð´ÐµÐºÑÑ Ð¸Ð»Ð¸ Ñоединение по Ñ ÐµÑÑ, Ñак как Ð´Ð»Ñ Ð²ÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ñ ÐµÑа пÑидÑÑÑÑ Ð²ÑбиÑаÑÑ ÑолÑко знаÑаÑие биÑÑ Ð¸Ð· ваÑей ÑÑÑÑкÑÑÑÑ Ð´Ð°Ð½Ð½ÑÑ . ÐланиÑовÑик Ñакже иногда полагаеÑÑÑ Ð½Ð° побиÑовое ÑÑавнение конÑÑанÑ, Ñак ÑÑо ÑезÑлÑÑаÑÑ Ð¿Ð»Ð°Ð½Ð¸ÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð³ÑÑ Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ñми, еÑли логиÑеÑки ÑавнÑе знаÑÐµÐ½Ð¸Ñ Ð¾ÐºÐ°Ð¶ÑÑÑÑ Ð½ÐµÑавнÑми на биÑовом ÑÑовне.ÐолÑÑинÑÑво внÑÑÑÐµÐ½Ð½Ð¸Ñ Ñипов Postgres Pro обÑÑÐ²Ð»ÐµÐ½Ñ Ð²
postgres.h, Ñогда как инÑеÑÑÐµÐ¹Ñ Ð¼ÐµÐ½ÐµÐ´Ð¶ÐµÑа ÑÑнкÑий (PG_FUNCTION_ARGSи Ñ. д.) опÑеделÑн вfmgr.h, Ñак ÑÑо поÑÑебÑеÑÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑÑиÑÑ ÐºÐ°Ðº минимÑм два ÑÑÐ¸Ñ Ñайла. Ðо ÑообÑажениÑм поÑÑиÑÑемоÑÑи, лÑÑÑе вклÑÑиÑÑpostgres.hпеÑвÑм, до ÐºÐ°ÐºÐ¸Ñ -либо дÑÑÐ³Ð¸Ñ ÑиÑÑемнÑÑ Ð¸Ð»Ð¸ полÑзоваÑелÑÑÐºÐ¸Ñ Ñайлов заголовков. ÐÑи подклÑÑенииpostgres.hавÑомаÑиÑеÑки Ñакже бÑдÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑÑенÑelog.hиpalloc.h.Ðмена Ñимволов, опÑеделÑннÑе в обÑекÑнÑÑ ÑÐ°Ð¹Ð»Ð°Ñ , не Ð´Ð¾Ð»Ð¶Ð½Ñ ÐºÐ¾Ð½ÑликÑоваÑÑ Ð´ÑÑг Ñ Ð´ÑÑгом или Ñ Ð¸Ð¼ÐµÐ½Ð°Ð¼Ð¸ дÑÑÐ³Ð¸Ñ Ñимволов, опÑеделÑннÑÑ Ð² иÑполнÑемÑÑ ÑÐ°Ð¹Ð»Ð°Ñ ÑеÑвеÑа Postgres Pro. ÐÑли Ð²Ñ ÑÑолкнÑÑеÑÑ Ñ Ð¾Ñибками, вÑзваннÑми Ñаким конÑликÑом, вам пÑидÑÑÑÑ Ð¿ÐµÑеименоваÑÑ Ð²Ð°Ñи ÑÑнкÑии или пеÑеменнÑе.
37.10.5. ÐомпилÑÑÐ¸Ñ Ð¸ компоновка динамиÑеÑки загÑÑжаемÑÑ ÑÑнкÑий #
ÐÑежде Ñем Ð²Ñ ÑможеÑе иÑполÑзоваÑÑ Ð²Ð°Ñи напиÑаннÑе на C ÑÑнкÑии, ÑаÑÑиÑÑÑÑие возможноÑÑи Postgres Pro, Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ ÑкомпилиÑоваÑÑ Ð¸ ÑкомпоноваÑÑ Ð¾ÑобÑм обÑазом, ÑÑÐ¾Ð±Ñ ÑеÑÐ²ÐµÑ Ð¼Ð¾Ð³ динамиÑеÑки загÑÑзиÑÑ Ð¿Ð¾Ð»ÑÑеннÑй Ñайл. ТоÑнее говоÑÑ, вам Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ ÑоздаÑÑ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑекÑ.
Ðа подÑобной инÑоÑмаÑией, дополнÑÑÑей и поÑÑнÑÑÑей Ñо, ÑÑо опиÑано в ÑÑом Ñазделе, вам ÑледÑÐµÑ Ð¾Ð±ÑаÑиÑÑÑÑ Ðº докÑменÑаÑии ваÑей опеÑаÑионной ÑиÑÑемÑ, в ÑаÑÑноÑÑи к ÑÑÑаниÑам ÑÑководÑÑва компилÑÑоÑа C (cc) и компоновÑика (ld).
Создание ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñек в пÑинÑипе не оÑлиÑаеÑÑÑ Ð¾Ñ ÑбоÑки иÑполнÑемÑÑ Ñайлов: ÑнаÑала иÑÑ Ð¾Ð´Ð½Ñе ÑÐ°Ð¹Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»Ð¸ÑÑÑÑÑÑ Ð² обÑекÑнÑе, а заÑем обÑекÑнÑе ÑвÑзÑваÑÑÑÑ Ð²Ð¼ÐµÑÑе. ÐбÑекÑнÑе ÑÐ°Ð¹Ð»Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑоздаваÑÑÑÑ Ñак, ÑÑÐ¾Ð±Ñ Ð¾Ð½Ð¸ ÑодеÑжали позиÑионно-незавиÑимÑй код (PIC, position-independent code), ÑÑо ознаÑаеÑ, ÑÑо пÑи загÑÑзке Ð´Ð»Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑÑÐ¾Ñ ÐºÐ¾Ð´ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð¼ÐµÑÑн в лÑбое меÑÑо в памÑÑи. (ÐбÑекÑнÑе ÑайлÑ, пÑедназнаÑеннÑе Ð´Ð»Ñ ÑбоÑки непоÑÑедÑÑвенно иÑполнÑемÑÑ Ñайлов, обÑÑно ÑобиÑаÑÑÑÑ Ð½Ðµ Ñак.) Ðоманда Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸ ÑазделÑемой библиоÑеки пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ ÑпеÑиалÑнÑе Ñлаги, ÑÑо оÑлиÑаÑÑ ÐµÑ Ð¾Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸ иÑполнÑемого Ñайла (по кÑайней меÑе в ÑеоÑии â в некоÑоÑÑÑ ÑиÑÑÐµÐ¼Ð°Ñ ÑеалÑноÑÑÑ Ð½Ðµ Ñак пÑекÑаÑна).
Ð ÑледÑÑÑиÑ
пÑимеÑаÑ
пÑедполагаеÑÑÑ, ÑÑо иÑÑ
однÑй код наÑ
одиÑÑÑ Ð² Ñайле foo.c и Ð¼Ñ Ð±Ñдем ÑоздаваÑÑ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑÐµÐºÑ foo.so. ÐÑомежÑÑоÑнÑй обÑекÑнÑй Ñайл бÑÐ´ÐµÑ Ð½Ð°Ð·ÑваÑÑÑÑ foo.o, еÑли не оÑмеÑено дÑÑгое. РазделÑÐµÐ¼Ð°Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñека Ð¼Ð¾Ð¶ÐµÑ Ð²ÐºÐ»ÑÑаÑÑ Ð±Ð¾Ð»ÑÑе одного обÑекÑного Ñайла, но здеÑÑ Ð¼Ñ Ð¾Ð³ÑаниÑимÑÑ Ð¾Ð´Ð½Ð¸Ð¼.
- FreeBSD
ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° PIC компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг
-fPIC. ЧÑÐ¾Ð±Ñ ÑоздаÑÑ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑекÑ, иÑполÑзÑеÑÑÑ Ñлаг компилÑÑоÑа-shared.gcc -fPIC -c foo.c gcc -shared -o foo.so foo.o
ÐÑо пÑименимо как минимÑм к FreeBSD веÑÑии 3.0.
- Linux
ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° PIC компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг
-fPIC. ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑазделÑемой библиоÑеки компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг-shared. ÐолнÑй пÑÐ¸Ð¼ÐµÑ Ð±ÑÐ´ÐµÑ Ð²ÑглÑдеÑÑ Ñак:cc -fPIC -c foo.c cc -shared -o foo.so foo.o
- macOS
СледÑÑÑий пÑÐ¸Ð¼ÐµÑ Ð¿Ð¾ÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð½ÑжнÑе командÑ, в пÑедположении, ÑÑо ÑÑÑÐ°Ð½Ð¾Ð²Ð»ÐµÐ½Ñ Ð¸Ð½ÑÑÑÑменÑÑ ÑазÑабоÑÑика.
cc -c foo.c cc -bundle -flat_namespace -undefined suppress -o foo.so foo.o
- NetBSD
ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° PIC компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг
-fPIC. ÐÐ»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñек в ÑиÑÑÐµÐ¼Ð°Ñ ELF компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг-shared, а в ÑÑаÑÑÑ ÑиÑÑÐµÐ¼Ð°Ñ , не поддеÑживаÑÑÐ¸Ñ ELF, пÑименÑеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°ld -Bshareable.gcc -fPIC -c foo.c gcc -shared -o foo.so foo.o
- OpenBSD
ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° PIC компилÑÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ Ñлаг
-fPIC, а Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñек пÑименÑеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°ld -Bshareable.gcc -fPIC -c foo.c ld -Bshareable -o foo.so foo.o
- Solaris
ÐÐ»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ð´Ð° PIC компилÑÑоÑÑ Sun пеÑедаÑÑÑÑ Ñлаг
-KPIC, а компилÑÑоÑÑ GCC â Ñлаг-fPIC. ÐÐ»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ¸ ÑазделÑемой библиоÑеки можно пеÑедаÑÑ Ð¾Ð±Ð¾Ð¸Ð¼ компилÑÑоÑам Ñлаг-Gлибо пеÑедаÑÑ Ñлаг-sharedкомпилÑÑоÑÑ GCC.cc -KPIC -c foo.c cc -G -o foo.so foo.o
или
gcc -fPIC -c foo.c gcc -G -o foo.so foo.o
ÐодÑказка
ÐÑли ÑÑо ÑлиÑком Ñложно Ð´Ð»Ñ Ð²Ð°Ñ, попÑобÑйÑе иÑполÑзоваÑÑ ÑÑедÑÑво GNU Libtool, коÑоÑое ÑкÑÑÐ²Ð°ÐµÑ ÑазлиÑÐ¸Ñ Ð¿Ð»Ð°ÑÑоÑм за единÑм инÑеÑÑейÑом.
ÐолÑÑеннÑÑ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑÐµÐºÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑÐ´ÐµÑ Ð·Ð°Ñем загÑÑзиÑÑ Ð² Postgres Pro. Ðогда команде CREATE FUNCTION пеÑедаÑÑÑÑ Ð¸Ð¼Ñ Ñайла, ÑÑо должно бÑÑÑ Ð¸Ð¼Ñ Ñайла ÑазделÑемой библиоÑеки, а не пÑомежÑÑоÑного обÑекÑного Ñайла. ÐамеÑÑÑе, ÑÑо пÑинÑÑое в ÑиÑÑеме ÑаÑÑиÑение Ñайлов библиоÑек (как пÑавило, .so или .sl) в команде CREATE FUNCTION можно опÑÑÑиÑÑ, и Ñак обÑÑно ÑледÑÐµÑ Ð´ÐµÐ»Ð°ÑÑ Ð´Ð»Ñ Ð»ÑÑÑей поÑÑиÑÑемоÑÑи.
ЧÑÐ¾Ð±Ñ ÑÑоÑниÑÑ, где ÑеÑÐ²ÐµÑ Ð±ÑÐ´ÐµÑ Ð¸ÑкаÑÑ ÑÐ°Ð¹Ð»Ñ ÑазделÑемÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñек, веÑниÑеÑÑ Ðº ÐодÑазделÑ 37.10.1.
37.10.6. ÐÑгÑменÑÑ ÑоÑÑавного Ñипа #
СоÑÑавнÑе ÑÐ¸Ð¿Ñ Ð½Ðµ имеÑÑ ÑикÑиÑованного макеÑа даннÑÑ , как ÑÑÑÑкÑÑÑÑ C. Ð ÑаÑÑноÑÑи, ÑкземплÑÑÑ ÑоÑÑавного Ñипа могÑÑ ÑодеÑжаÑÑ Ð¿Ð¾Ð»Ñ NULL. ÐÑоме Ñого, в конÑекÑÑе наÑÐ»ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ ÑоÑÑавнÑе ÑÐ¸Ð¿Ñ Ð¼Ð¾Ð³ÑÑ Ð¸Ð¼ÐµÑÑ ÑазнÑе Ð¿Ð¾Ð»Ñ Ð´Ð»Ñ ÑазнÑÑ Ñленов в одной иеÑаÑÑ Ð¸Ð¸ наÑледованиÑ. ÐоÑÑÐ¾Ð¼Ñ Postgres Pro пÑедоÑÑавлÑÐµÑ ÑÑнкÑиÑм ÑпеÑиалÑнÑй инÑеÑÑÐµÐ¹Ñ Ð´Ð»Ñ Ð¾Ð±ÑаÑÐµÐ½Ð¸Ñ Ðº полÑм ÑоÑÑавнÑÑ Ñипов из C.
ÐÑедположим, ÑÑо Ð¼Ñ Ñ Ð¾Ñим напиÑаÑÑ ÑÑнкÑиÑ, оÑвеÑаÑÑÑÑ Ð½Ð° запÑоÑ:
SELECT name, c_overpaid(emp, 1500) AS overpaid
FROM emp
WHERE name = 'Bill' OR name = 'Sam'; С ÑоглаÑениÑми о вÑзоваÑ
веÑÑии 1 Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ опÑеделиÑÑ ÑÑнкÑÐ¸Ñ c_overpaid Ñак:
#include "postgres.h"
#include "executor/executor.h" /* for GetAttributeByName() */
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(c_overpaid);
Datum
c_overpaid(PG_FUNCTION_ARGS)
{
HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(0);
int32 limit = PG_GETARG_INT32(1);
bool isnull;
Datum salary;
salary = GetAttributeByName(t, "salary", &isnull);
if (isnull)
PG_RETURN_BOOL(false);
/* Alternatively, we might prefer to do PG_RETURN_NULL() for null salary. */
PG_RETURN_BOOL(DatumGetInt32(salary) > limit);
}
GetAttributeByName â ÑÑо ÑиÑÑÐµÐ¼Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Postgres Pro, коÑоÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð°ÑÑибÑÑÑ Ñказанной ÑÑÑоки. Ðна пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ ÑÑи паÑамеÑÑа: аÑгÑÐ¼ÐµÐ½Ñ Ñипа HeapTupleHeader, Ð¸Ð¼Ñ Ð½Ñжного аÑÑибÑÑа и вÑÑ
одной паÑамеÑÑ, ÑÑÑанавливаемÑй, еÑли знаÑение аÑÑибÑÑа â NULL. GetAttributeByName возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение Datum, коÑоÑое Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑивеÑÑи к подÑ
одÑÑÐµÐ¼Ñ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
, иÑполÑзÑÑ ÑооÑвеÑÑÑвÑÑÑÑÑ ÑÑнкÑÐ¸Ñ DatumGet. ÐамеÑÑÑе, ÑÑо возвÑаÑаемое знаÑение недейÑÑвиÑелÑно, еÑли ÑÑÑановлен Ñлаг null; вÑегда пÑовеÑÑйÑе ÑÑÐ¾Ñ Ñлаг, пÑежде Ñем ÑÑо-либо делаÑÑ Ñ ÑезÑлÑÑаÑом.XXX()
ÐÑÑÑ Ñакже ÑÑнкÑÐ¸Ñ GetAttributeByNum, коÑоÑÐ°Ñ Ð²ÑбиÑÐ°ÐµÑ Ñелевой аÑÑибÑÑ Ð½Ðµ по имени, а по номеÑÑ ÑÑолбÑа.
СледÑÑÑÐ°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° обÑÑвлÑÐµÑ ÑÑнкÑÐ¸Ñ c_overpaid в SQL:
CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
AS 'ÐÐТÐÐÐÐ/funcs', 'c_overpaid'
LANGUAGE C STRICT; ÐамеÑÑÑе, ÑÑо Ð¼Ñ Ð¸ÑполÑзовали STRICT, ÑÑÐ¾Ð±Ñ Ð½Ð°Ð¼ не пÑиÑлоÑÑ Ð¿ÑовеÑÑÑÑ Ð²Ñ
однÑе аÑгÑменÑÑ Ð½Ð° ÑавенÑÑво NULL.
37.10.7. ÐозвÑÐ°Ñ ÑÑÑок (ÑоÑÑавнÑÑ Ñипов) #
ЧÑÐ¾Ð±Ñ Ð²ÐµÑнÑÑÑ ÑÑÑÐ¾ÐºÑ Ð¸Ð»Ð¸ знаÑение ÑоÑÑавного Ñипа из ÑÑнкÑии на ÑзÑке C, можно иÑполÑзоваÑÑ ÑпеÑиалÑнÑй API, пÑедоÑÑавлÑÑÑий макÑоÑÑ Ð¸ ÑÑнкÑии, ÑкÑÑваÑÑие оÑновнÑÑ ÑложноÑÑÑ ÑоÑмиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÑоÑÑавнÑÑ Ñипов даннÑÑ . ÐÐ»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÑÑого API Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ вклÑÑиÑÑ Ð² иÑÑ Ð¾Ð´Ð½Ñй Ñайл:
#include "funcapi.h"
СÑоÑмиÑоваÑÑ Ð·Ð½Ð°Ñение ÑоÑÑавного Ñипа (далее «коÑÑеж») можно двÑÐ¼Ñ ÑпоÑобами: его можно поÑÑÑоиÑÑ Ð¸Ð· маÑÑива знаÑений Datum, или из маÑÑива ÑÑÑок C, коÑоÑÑе бÑдÑÑ Ð¿ÐµÑÐµÐ´Ð°Ð½Ñ ÑÑнкÑиÑм пÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð²Ð¾Ð´Ð° Ð´Ð»Ñ Ñипов ÑÑолбÑов коÑÑежа. РлÑбом ÑлÑÑае ÑнаÑала нÑжно полÑÑиÑÑ Ð¸Ð»Ð¸ ÑконÑÑÑÑиÑоваÑÑ Ð´ÐµÑкÑипÑÐ¾Ñ TupleDesc Ð´Ð»Ñ ÑÑÑÑкÑÑÑÑ ÐºÐ¾ÑÑежа. РабоÑÐ°Ñ Ñо знаÑениÑми Datum, Ð²Ñ Ð¿ÐµÑедаÑÑе TupleDesc ÑÑнкÑии BlessTupleDesc, а заÑем вÑзÑваеÑе heap_form_tuple Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки. РабоÑÐ°Ñ Ñо ÑÑÑоками C, Ð²Ñ Ð¿ÐµÑедаÑÑе TupleDesc ÑÑнкÑии TupleDescGetAttInMetadata, а заÑем Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки вÑзÑваеÑе BuildTupleFromCStrings. Ð ÑлÑÑае ÑÑнкÑии, возвÑаÑаÑÑей множеÑÑво коÑÑежей, вÑе подгоÑовиÑелÑнÑе дейÑÑÐ²Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ вÑполниÑÑ Ð¾Ð´Ð¸Ð½ Ñаз пÑи пеÑвом вÑзове ÑÑнкÑии.
ÐÐ»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑÑебÑемого деÑкÑипÑоÑа TupleDesc пÑедлагаеÑÑÑ Ð½ÐµÑколÑко дополниÑелÑнÑÑ
ÑÑнкÑий. РекомендованнÑй ÑпоÑоб возвÑаÑа ÑоÑÑавнÑÑ
знаÑений заклÑÑаеÑÑÑ Ð² вÑзове ÑÑнкÑии:
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
Oid *resultTypeId,
TupleDesc *resultTupleDesc) ÐÑи ÑÑом в fcinfo должна пеÑедаваÑÑÑÑ Ñа же ÑÑÑÑкÑÑÑа, ÑÑо бÑла пеÑедана Ñамой вÑзÑваÑÑей ÑÑнкÑии. (ÐÐ»Ñ ÑÑого, конеÑно, необÑ
одимо иÑполÑзоваÑÑ ÑоглаÑÐµÐ½Ð¸Ñ Ð¾ вÑзоваÑ
веÑÑии 1.) Ð resultTypeId можно пеÑедаÑÑ NULL или адÑÐµÑ Ð»Ð¾ÐºÐ°Ð»Ñной пеÑеменной, в коÑоÑÑÑ Ð±ÑÐ´ÐµÑ Ð·Ð°Ð¿Ð¸Ñан OID Ñипа ÑезÑлÑÑаÑа ÑÑнкÑии. Ð resultTupleDesc должен пеÑедаваÑÑÑÑ Ð°Ð´ÑÐµÑ Ð»Ð¾ÐºÐ°Ð»Ñной пеÑеменной TupleDesc. УбедиÑÑ, ÑÑо ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑила ÑезÑлÑÑÐ°Ñ TYPEFUNC_COMPOSITE; в ÑÑом ÑлÑÑае в resultTupleDesc оказÑваеÑÑÑ ÑÑебÑÐµÐ¼Ð°Ñ ÑÑÑÑкÑÑÑа TupleDesc. (ÐÑли полÑÑен дÑÑгой ÑезÑлÑÑаÑ, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе вÑдаÑÑ Ð¾ÑÐ¸Ð±ÐºÑ Ñ ÑообÑением «ÑÑнкÑиÑ, возвÑаÑаÑÑÐ°Ñ Ð·Ð°Ð¿Ð¸ÑÑ, вÑзвана в конÑекÑÑе, не допÑÑкаÑÑем ÑÑÐ¾Ñ Ñип».)
ÐодÑказка
get_call_result_type позволÑÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ ÑакÑиÑеÑкий Ñип ÑезÑлÑÑаÑа полимоÑÑной ÑÑнкÑии, Ñак ÑÑо она полезна и в ÑÑнкÑиÑÑ
, возвÑаÑаÑÑиÑ
ÑкалÑÑнÑе полимоÑÑнÑе ÑезÑлÑÑаÑÑ, не ÑолÑко в ÑÑнкÑиÑÑ
, возвÑаÑаÑÑиÑ
ÑоÑÑавнÑе ÑипÑ. ÐÑÑ
одной паÑамеÑÑ resultTypeId полезен в пеÑвÑÑ Ð¾ÑеÑÐµÐ´Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑÑ
ÑкалÑÑнÑÑ
ÑÑнкÑий.
ÐÑимеÑание
Рдополнение к get_call_result_type еÑÑÑ ÑÑ
Ð¾Ð¶Ð°Ñ ÑÑнкÑÐ¸Ñ get_expr_result_type, позволÑÑÑÐ°Ñ Ð¿Ð¾Ð»ÑÑиÑÑ Ð¾Ð¶Ð¸Ð´Ð°ÐµÐ¼Ñй Ñип ÑезÑлÑÑаÑа Ð´Ð»Ñ Ð²Ñзова ÑÑнкÑии, пÑедÑÑавленного деÑевом вÑÑажениÑ. ÐÑ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ, когда Ñип ÑезÑлÑÑаÑа нÑжно опÑеделиÑÑ Ð¸Ð·Ð²Ð½Ðµ Ñамой ÑÑнкÑии. ÐÑÑÑ Ñакже ÑÑнкÑÐ¸Ñ get_func_result_type, коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ пÑименÑÑÑ, когда извеÑÑен ÑолÑко OID ÑÑнкÑии. Ðднако ÑÑи две ÑÑнкÑии неÑпоÑÐ¾Ð±Ð½Ñ Ð²ÑдаÑÑ Ñип ÑезÑлÑÑаÑа ÑÑнкÑий, возвÑаÑаÑÑиÑ
record, а get_func_result_type неÑпоÑобна ÑазÑеÑаÑÑ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑе ÑипÑ, Ñак ÑÑо вмеÑÑо ниÑ
лÑÑÑе иÑполÑзоваÑÑ get_call_result_type.
Ранее Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ TupleDesc иÑполÑзовалиÑÑ ÑепеÑÑ Ñже ÑÑÑаÑевÑие ÑÑнкÑии:
TupleDesc RelationNameGetTupleDesc(const char *relname)
(возвÑаÑÐ°ÐµÑ TupleDesc Ð´Ð»Ñ Ñипа ÑÑÑок Ñказанного оÑноÑениÑ) и:
TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
(возвÑаÑÐ°ÐµÑ TupleDesc Ð´Ð»Ñ Ñипа, задаваемого по OID). ÐÑименÑÑ ÐµÑ, можно полÑÑиÑÑ TupleDesc Ð´Ð»Ñ Ð±Ð°Ð·Ð¾Ð²Ð¾Ð³Ð¾ или ÑоÑÑавного Ñипа. Ðднако она не подойдÑÑ Ð´Ð»Ñ ÑÑнкÑии, возвÑаÑаÑÑей Ñип record, и не ÑÐ¼Ð¾Ð¶ÐµÑ ÑазÑеÑиÑÑ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑнÑе ÑипÑ.
ÐолÑÑив TupleDesc, вÑзовиÑе:
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
еÑли Ð²Ñ Ð¿Ð»Ð°Ð½Ð¸ÑÑеÑе ÑабоÑаÑÑ Ñо ÑÑÑÑкÑÑÑами Datum, либо:
AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
еÑли планиÑÑеÑе ÑабоÑаÑÑ Ñо ÑÑÑоками C. ÐÑли Ð²Ñ ÑазÑабаÑÑваеÑе ÑÑнкÑиÑ, возвÑаÑаÑÑÑÑ Ð½Ð°Ð±Ð¾Ñ Ð´Ð°Ð½Ð½ÑÑ
, Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе ÑоÑ
ÑаниÑÑ ÑезÑлÑÑаÑÑ ÑÑиÑ
ÑÑнкÑий в ÑÑÑÑкÑÑÑе FuncCallContext, в поле tuple_desc или attinmeta, ÑооÑвеÑÑÑвенно.
ÐÑли Ð²Ñ ÑабоÑаеÑе Ñо ÑÑÑÑкÑÑÑами Datum, воÑполÑзÑйÑеÑÑ ÑÑнкÑией:
HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)
Ðна ÑоÑмиÑÑÐµÑ HeapTuple из пеÑеданнÑÑ
ей даннÑÑ
в ÑоÑме Datum.
ÐÑли Ð²Ñ ÑабоÑаеÑе Ñо ÑÑÑоками C, воÑполÑзÑйÑеÑÑ ÑÑнкÑией:
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Ðна ÑоÑмиÑÑÐµÑ HeapTuple из пеÑеданнÑÑ
ей даннÑÑ
в виде ÑÑÑок C. РпаÑамеÑÑе values ей пеÑедаÑÑÑÑ Ð¼Ð°ÑÑив ÑÑÑок C, по одной Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ аÑÑибÑÑа вÑÑ
одной ÑÑÑоки. ÐÐ°Ð¶Ð´Ð°Ñ Ð¸Ð· ÑÑиÑ
ÑÑÑок должна имеÑÑ ÑоÑмаÑ, пÑинимаемÑй ÑÑнкÑией ввода Ñипа даннÑÑ
аÑÑибÑÑа. ЧÑÐ¾Ð±Ñ Ð·Ð°Ð´Ð°ÑÑ Ð·Ð½Ð°Ñение NULL Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ из ÑÑиÑ
аÑÑибÑÑов, вмеÑÑо ÑооÑвеÑÑÑвÑÑÑего ÑказаÑÐµÐ»Ñ Ð² маÑÑиве values нÑжно пеÑедаÑÑ NULL. ÐÑÑ ÑÑнкÑÐ¸Ñ Ð½Ñжно вÑзÑваÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки, коÑоÑÑÑ Ð²Ñ Ð±ÑдеÑе возвÑаÑаÑÑ.
ÐолÑÑив коÑÑеж, коÑоÑÑй Ð²Ñ Ð±ÑдеÑе возвÑаÑаÑÑ Ð¸Ð· ваÑей ÑÑнкÑии, Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑеобÑазоваÑÑ ÐµÐ³Ð¾ в Ñип Datum. ЧÑÐ¾Ð±Ñ Ð¿ÑеобÑазоваÑÑ HeapTuple в Datum, воÑполÑзÑйÑеÑÑ ÑÑнкÑией:
HeapTupleGetDatum(HeapTuple tuple)
ÐолÑÑеннÑй Ñип Datum можно веÑнÑÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно, еÑли должна возвÑаÑаÑÑÑÑ ÑолÑко одна ÑÑÑока, либо иÑполÑзоваÑÑ ÐºÐ°Ðº ÑекÑÑее вÑдаваемое знаÑение в ÑÑнкÑии, возвÑаÑаÑÑей Ð½Ð°Ð±Ð¾Ñ ÑÑÑок.
ÐÑÐ¸Ð¼ÐµÑ Ð¿ÑиведÑн в ÑледÑÑÑем Ñазделе.
37.10.8. ÐозвÑÐ°Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑв #
ФÑнкÑии на ÑзÑке C могÑÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð½Ð°Ð±Ð¾ÑÑ Ð´Ð°Ð½Ð½ÑÑ (множеÑÑва ÑÑÑок) двÑÐ¼Ñ ÑпоÑобами. ÐеÑвÑй ÑпоÑоб, коÑоÑÑй назÑваеÑÑÑ ValuePerCall (знаÑение за вÑзов), заклÑÑаеÑÑÑ Ð² многокÑаÑном вÑзове ÑÑнкÑии (пÑи ÑÑом ей каждÑй Ñаз пеÑедаÑÑÑÑ Ð¾Ð´Ð½Ð¸ и Ñе же аÑгÑменÑÑ). ÐÑа ÑÑнкÑÐ¸Ñ Ð¿Ñи оÑеÑедном вÑзове должна возвÑаÑаÑÑ ÑледÑÑÑÑÑ ÑÑÑокÑ, пока не вÑдаÑÑ Ð²Ñе ÑÑÑоки, о ÑÑм она ÑообÑаеÑ, возвÑаÑÐ°Ñ NULL. Таким обÑазом, возвÑаÑаÑÑÐ°Ñ Ð¼Ð½Ð¾Ð¶ÐµÑÑво ÑÑнкÑÐ¸Ñ (Set-Returning Function, SRF) должна ÑÐ¾Ñ ÑанÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами ÑÐ²Ð¾Ñ ÑоÑÑоÑние в доÑÑаÑоÑном обÑÑме, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¼Ð½Ð¸ÑÑ, какие даннÑе Ñже бÑли вÑданÑ, и возвÑаÑаÑÑ ÑледÑÑÑие пÑи оÑеÑедном вÑзове. ÐÑоÑой ваÑианÑ, Materialize (ÐаÑеÑиализаÑиÑ), заклÑÑаеÑÑÑ Ð² ÑоÑмиÑовании в SRF обÑекÑа tuplestore, ÑодеÑжаÑего ÑÑÐ°Ð·Ñ Ð²ÐµÑÑ ÑезÑлÑÑиÑÑÑÑий набоÑ; единÑÑвеннÑй вÑзов пÑоизводиÑÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑÑÐ°Ð·Ñ Ð²Ñего ÑезÑлÑÑаÑа, и никакое ÑоÑÑоÑние Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами ÑÐ¾Ñ ÑанÑÑÑ Ð½Ðµ нÑжно.
РеализÑÑ Ñежим ValuePerCall, важно не забÑваÑÑ, ÑÑо вÑполнение запÑоÑа до полного завеÑÑÐµÐ½Ð¸Ñ Ð½Ðµ гаÑанÑиÑÑеÑÑÑ. Так, напÑимеÑ, полÑÑив Ñказание LIMIT, иÑполниÑÐµÐ»Ñ Ð·Ð°Ð¿ÑоÑа Ð¼Ð¾Ð¶ÐµÑ Ð¿ÐµÑеÑÑаÑÑ Ð²ÑзÑваÑÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво ÑÑнкÑÐ¸Ñ Ð´Ð¾ полÑÑÐµÐ½Ð¸Ñ Ð²ÑеÑ
ÑÑÑок. ÐÑо ознаÑаеÑ, ÑÑо вÑполнÑÑÑ Ð´ÐµÐ¹ÑÑвиÑ, ÑвÑзаннÑе Ñ Ð¾ÑиÑÑкой, в поÑледнем вÑзове небезопаÑно, Ñак как он Ð¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð²Ñе не ÑоÑÑоÑÑÑÑÑ. ÐоÑÑÐ¾Ð¼Ñ Ð´Ð»Ñ ÑÑнкÑий, коÑоÑÑм нÑжно обÑаÑаÑÑÑÑ Ðº внеÑним ÑеÑÑÑÑам, напÑимеÑ, оÑкÑÑÐ²Ð°Ñ ÑайловÑе деÑкÑипÑоÑÑ, ÑекомендÑеÑÑÑ Ð¸ÑполÑзоваÑÑ Ñежим маÑеÑиализаÑии ÑезÑлÑÑаÑов.
РпÑодолжении ÑÑого Ñаздела опиÑÑваÑÑÑÑ Ð½ÐµÑколÑко вÑпомогаÑелÑнÑÑ Ð¼Ð°ÐºÑоÑов, коÑоÑÑе ÑаÑÑо иÑполÑзÑÑÑÑÑ (Ñ Ð¾ÑÑ Ð½Ðµ ÑвлÑÑÑÑÑ Ð¾Ð±ÑзаÑелÑнÑми) в SRF, ÑеализÑÑÑÐ¸Ñ Ð¼ÐµÑод ValuePerCall.
ÐÐ»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð¿Ð¸ÑаннÑÑ
здеÑÑ Ð¼Ð°ÐºÑоÑов поддеÑжки ValuePerCall подклÑÑиÑе funcapi.h. ÐÑи макÑоÑÑ ÑабоÑаÑÑ Ñо ÑÑÑÑкÑÑÑой FuncCallContext, ÑодеÑжаÑей ÑоÑÑоÑние, коÑоÑое ÑÑебÑеÑÑÑ ÑоÑ
ÑанÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами. УказаÑÐµÐ»Ñ Ð½Ð° FuncCallContext внÑÑÑи вÑзÑваемой SRF ÑоÑ
ÑанÑеÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами в поле fcinfo->flinfo->fn_extra, коÑоÑое макÑоÑÑ Ð°Ð²ÑомаÑиÑеÑки заполнÑÑÑ Ð¿Ñи пеÑвом иÑполÑзовании, ÑаÑÑÑиÑÑÐ²Ð°Ñ Ð¿ÑоÑеÑÑÑ Ð¸Ð· него ÑÐ¾Ñ Ð¶Ðµ ÑказаÑÐµÐ»Ñ Ð¿Ñи поÑледÑÑÑиÑ
вÑзоваÑ
.
typedef struct FuncCallContext
{
/*
* СÑÑÑÑик ÑиÑла Ñанее вÑполненнÑÑ
вÑзовов
*
* call_cntr ÑбÑаÑÑваеÑÑÑ Ð² 0 макÑоÑом SRF_FIRSTCALL_INIT() и
* ÑвелиÑиваеÑÑÑ Ð½Ð° 1 каждÑй Ñаз, когда вÑзÑваеÑÑÑ SRF_RETURN_NEXT().
*/
uint64 call_cntr;
/*
* ÐакÑималÑное ÑиÑло вÑзовов (Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ иÑполÑзоваÑÑÑÑ)
*
* max_calls не ÑвлÑеÑÑÑ Ð¾Ð±ÑзаÑелÑнÑм и пÑиÑÑÑÑÑвÑÐµÑ Ð·Ð´ÐµÑÑ ÑолÑко Ð´Ð»Ñ ÑдобÑÑва.
* ÐÑли ÑÑо знаÑение не задано, Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑедоÑÑавиÑÑ Ð´ÑÑгÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð¾Ð¿ÑеделиÑÑ,
* когда ÑÑнкÑÐ¸Ñ Ð·Ð°Ð²ÐµÑÑила ÑÐ²Ð¾Ñ ÑабоÑÑ.
*/
uint64 max_calls;
/*
* УказаÑÐµÐ»Ñ Ð½Ð° ÑазнообÑазнÑÑ ÐºÐ¾Ð½ÑекÑÑнÑÑ Ð¸Ð½ÑоÑмаÑиÑ,
* пÑедÑÑавленнÑÑ Ð¿Ð¾Ð»ÑзоваÑелем; (Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ иÑполÑзоваÑÑÑÑ)
*
* user_fctx иÑполÑзÑеÑÑÑ ÐºÐ°Ðº ÑказаÑÐµÐ»Ñ Ð½Ð° ваÑи ÑобÑÑвеннÑе даннÑе,
* позволÑÑÑий ÑоÑ
ÑаниÑÑ ÐºÐ¾Ð½ÑекÑÑнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами ÑÑнкÑии.
*/
void *user_fctx;
/*
* УказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ, ÑодеÑжаÑÑÑ Ð¼ÐµÑаданнÑе ввода Ñипа аÑÑибÑÑа
* (Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ иÑполÑзоваÑÑÑÑ)
*
* attinmeta задейÑÑвÑеÑÑÑ, когда возвÑаÑаÑÑÑÑ ÐºÐ¾ÑÑежи (Ñ. е. ÑоÑÑавнÑе ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
),
* и не пÑименÑеÑÑÑ Ð´Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑа базовÑÑ
Ñипов. Ðн нÑжен, ÑолÑко еÑли
* Ð²Ñ Ð¿Ð»Ð°Ð½Ð¸ÑÑеÑе иÑполÑзоваÑÑ BuildTupleFromCStrings() Ð´Ð»Ñ ÑоÑмиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð¾Ð·Ð²ÑаÑаемого
* коÑÑежа.
*/
AttInMetadata *attinmeta;
/*
* ÐонÑекÑÑ Ð¿Ð°Ð¼ÑÑи, нÑжнÑй Ð´Ð»Ñ ÑÑÑÑкÑÑÑ, коÑоÑÑе Ð´Ð¾Ð»Ð¶Ð½Ñ ÑоÑ
ÑанÑÑÑÑÑ Ð¿Ñи неÑколÑкиÑ
вÑзоваÑ
*
* Ðоле multi_call_memory_ctx заполнÑеÑÑÑ Ð² SRF_FIRSTCALL_INIT() и иÑполÑзÑеÑÑÑ
* в SRF_RETURN_DONE() Ð´Ð»Ñ Ð¾ÑиÑÑки. ÐÑо наиболее подÑ
одÑÑий конÑекÑÑ
* Ð´Ð»Ñ Ð»ÑбÑÑ
блоков памÑÑи, коÑоÑÑе Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¼Ð½Ð¾Ð³Ð¾ÐºÑаÑно иÑполÑзоваÑÑÑÑ Ð¿Ñи
* повÑоÑнÑÑ
вÑзоваÑ
SRF.
*/
MemoryContext multi_call_memory_ctx;
/*
* УказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ, ÑодеÑжаÑÑÑ Ð¾Ð¿Ð¸Ñание коÑÑежа (Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ иÑполÑзоваÑÑÑÑ)
*
* tuple_desc задейÑÑвÑеÑÑÑ, когда возвÑаÑаÑÑÑÑ ÐºÐ¾ÑÑежи (Ñ. е. ÑоÑÑавнÑе ÑипÑ),
* и нÑжен ÑолÑко, еÑли Ð²Ñ Ð¿Ð»Ð°Ð½Ð¸ÑÑеÑе ÑоÑмиÑоваÑÑ ÐºÐ¾ÑÑежи Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑÑнкÑии
* heap_form_tuple(), а не BuildTupleFromCStrings(). ÐамеÑÑÑе, ÑÑо ÑоÑ
ÑанÑемÑй
* здеÑÑ ÑказаÑÐµÐ»Ñ TupleDesc обÑÑно должен ÑнаÑала пÑойÑи ÑеÑез вÑзов
* BlessTupleDesc().
*/
TupleDesc tuple_desc;
} FuncCallContext;ÐÐ»Ñ SRF пÑедоÑÑавлÑеÑÑÑ ÑÑд макÑоÑов, иÑполÑзÑÑÑÐ¸Ñ ÑÑÑ Ð¸Ð½ÑÑаÑÑÑÑкÑÑÑÑ:
SRF_IS_FIRSTCALL()
ÐÑполÑзÑйÑе ÑÑÐ¾Ñ Ð¼Ð°ÐºÑоÑ, ÑÑÐ¾Ð±Ñ Ð¾Ð¿ÑеделиÑÑ, вÑзÑваеÑÑÑ Ð»Ð¸ ваÑа ÑÑнкÑÐ¸Ñ Ð² пеÑвÑй Ñаз. ÐÑи пеÑвом вÑзове (но не пÑи поÑледÑÑÑÐ¸Ñ ) вÑполниÑе:
SRF_FIRSTCALL_INIT()
Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¸Ð½Ð¸ÑиализиÑоваÑÑ FuncCallContext. ÐÑи каждом вÑзове ÑÑнкÑии, вклÑÑÐ°Ñ Ð¿ÐµÑвÑй, вÑполнÑйÑе:
SRF_PERCALL_SETUP()
Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð´Ð³Ð¾ÑовиÑÑÑÑ Ðº иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ FuncCallContext.
ÐÑли Ñ Ð²Ð°Ñей ÑÑнкÑии еÑÑÑ Ð´Ð°Ð½Ð½Ñе, коÑоÑÑе она должна вÑдаÑÑ Ð² ÑекÑÑем вÑзове, вÑполниÑе:
SRF_RETURN_NEXT(funcctx, result)
Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¿ÐµÑедаÑÑ Ð¸Ñ
вÑзÑваÑÑемÑ. (ÐеÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ result должна бÑÑÑ Ñипа Datum, либо одним знаÑением, либо коÑÑежем, подгоÑовленнÑм как опиÑано вÑÑе.) ÐаконеÑ, когда ваÑа ÑÑнкÑÐ¸Ñ Ð·Ð°ÐºÐ¾Ð½Ñила вÑдаваÑÑ Ð´Ð°Ð½Ð½Ñе, вÑполниÑе:
SRF_RETURN_DONE(funcctx)
Ð´Ð»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¿ÑовеÑÑи оÑиÑÑÐºÑ Ð¸ завеÑÑиÑÑ SRF.
ÐонÑекÑÑ Ð¿Ð°Ð¼ÑÑи, в коÑоÑом вÑзÑваеÑÑÑ SRF, вÑеменнÑй, он бÑÐ´ÐµÑ Ð¾ÑиÑаÑÑÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами. ÐÑо знаÑиÑ, ÑÑо вам не нÑжно вÑзÑваÑÑ pfree Ð´Ð»Ñ Ð²ÑеÑ
блоков памÑÑи, коÑоÑÑе Ð²Ñ Ð¿Ð¾Ð»ÑÑили ÑеÑез palloc; они вÑÑ Ñавно бÑдÑÑ Ð¾ÑвобожденÑ. Ðднако еÑли Ð²Ñ Ñ
оÑиÑе вÑделиÑÑ ÑÑÑÑкÑÑÑÑ Ð´Ð°Ð½Ð½ÑÑ
, ÑоÑ
ÑанÑÑÑиеÑÑ Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами, вам нÑжно ÑазмеÑÑиÑÑ Ð¸Ñ
где-Ñо в дÑÑгом меÑÑе. ÐÐ»Ñ ÑазмеÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½ÑÑ
, коÑоÑÑе не Ð´Ð¾Ð»Ð¶Ð½Ñ ÑниÑÑожаÑÑÑÑ, пока SRF не законÑÐ¸Ñ ÑабоÑÑ, подÑ
Ð¾Ð´Ð¸Ñ ÐºÐ¾Ð½ÑекÑÑ Ð¿Ð°Ð¼ÑÑи, на коÑоÑÑй ÑказÑÐ²Ð°ÐµÑ multi_call_memory_ctx. РболÑÑинÑÑве ÑлÑÑаев ÑÑо ознаÑаеÑ, ÑÑо Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÐµÑеклÑÑиÑÑÑÑ Ð² конÑекÑÑ multi_call_memory_ctx в коде подгоÑовки пÑи пеÑвом вÑзове. ÐÐ»Ñ ÑоÑ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ ÑказаÑÐµÐ»Ñ Ð½Ð° Ñакие долгоживÑÑие ÑÑÑÑкÑÑÑÑ Ð²Ð¾ÑполÑзÑйÑеÑÑ Ð¿Ð¾Ð»ÐµÐ¼ funcctx->user_fctx. (ÐамÑÑÑ, коÑоÑÑÑ Ð²Ñ Ð¿Ð¾Ð»ÑÑаеÑе в конÑекÑÑе multi_call_memory_ctx, бÑÐ´ÐµÑ Ð¾Ñвобождена авÑомаÑиÑеÑки пÑи завеÑÑении запÑоÑа, Ñак ÑÑо и ÐµÑ Ð¾ÑвобождаÑÑ Ð²ÑÑÑнÑÑ Ð½ÐµÑ Ð½ÐµÐ¾Ð±Ñ
одимоÑÑи.)
ÐÑедÑпÑеждение
Тогда как ÑакÑиÑеÑкие аÑгÑменÑÑ Ñакой ÑÑнкÑии не менÑÑÑÑÑ Ð¾Ñ Ð²Ñзова к вÑзовÑ, еÑли Ð²Ñ ÑаÑпаковÑваеÑе знаÑÐµÐ½Ð¸Ñ Ð°ÑгÑменÑов (ÑÑо обÑÑно пÑозÑаÑно делаÑÑ Ð¼Ð°ÐºÑоÑÑ PG_GETARG_) во вÑеменном конÑекÑÑе, ÑаÑпакованнÑе копии бÑдÑÑ Ð¾ÑвобождаÑÑÑÑ Ð¿Ñи каждом вÑзове. СооÑвеÑÑÑвенно, еÑли Ð²Ñ ÑоÑ
ÑаниÑе ÑÑÑлки на Ñакие знаÑÐµÐ½Ð¸Ñ Ð² ÑвоÑм конÑекÑÑе xxxuser_fctx, Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð»Ð¸Ð±Ð¾ ÑкопиÑоваÑÑ ÑÑи знаÑÐµÐ½Ð¸Ñ Ð² multi_call_memory_ctx поÑле ÑаÑпаковки, либо ÑаÑпаковÑваÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ ÑолÑко в ÑÑом конÑекÑÑе.
ÐолнÑй пÑÐ¸Ð¼ÐµÑ Ñ Ð¿Ñевдокодом бÑÐ´ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
Datum
my_set_returning_function(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
Datum result;
дÑÑгие необÑ
одимÑе обÑÑвлениÑ
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Ðод подгоÑовки пÑи пеÑвом вÑзове: */
некоÑоÑÑй код
еÑли возвÑаÑаеÑÑÑ ÑоÑÑавной Ñип
полÑÑиÑÑ TupleDesc и, возможно, AttInMetadata
ÐºÐ¾Ð½ÐµÑ Ð²ÐµÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑоÑÑавного Ñипа
некоÑоÑÑй код
MemoryContextSwitchTo(oldcontext);
}
/* Ðод подгоÑовки Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ вÑзова: */
некоÑоÑÑй код
funcctx = SRF_PERCALL_SETUP();
некоÑоÑÑй код
/* ТолÑко Ñак Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ опÑеделиÑÑ, не поÑледний ли ÑÑо вÑзов: */
if (funcctx->call_cntr < funcctx->max_calls)
{
/* ÐдеÑÑ Ð¼Ñ Ð²Ð¾Ð·Ð²ÑаÑаем еÑÑ Ð¾Ð´Ð¸Ð½ ÑезÑлÑÑаÑ: */
некоÑоÑÑй код
полÑÑение ÑезÑлÑÑиÑÑÑÑиÑ
даннÑÑ
SRF_RETURN_NEXT(funcctx, result);
}
else
{
/* ÐÑ Ð·Ð°ÐºÐ°Ð½Ñиваем вÑдаваÑÑ ÑезÑлÑÑаÑÑ, и ÑÑо надо оÑÑазиÑÑ. */
/* (ÐоздеÑжиÑеÑÑ Ð¾Ñ Ñоблазна напиÑаÑÑ Ð·Ð´ÐµÑÑ ÐºÐ¾Ð´, оÑвобождаÑÑий ÑеÑÑÑÑÑ.) */
SRF_RETURN_DONE(funcctx);
}
}ÐолнÑй пÑÐ¸Ð¼ÐµÑ Ð¿ÑоÑÑой SRF-ÑÑнкÑии, возвÑаÑаÑÑей ÑоÑÑавной Ñип, вÑглÑÐ´Ð¸Ñ Ñак:
PG_FUNCTION_INFO_V1(retcomposite);
Datum
retcomposite(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
int call_cntr;
int max_calls;
TupleDesc tupdesc;
AttInMetadata *attinmeta;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* total number of tuples to be returned */
funcctx->max_calls = PG_GETARG_INT32(0);
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context "
"that cannot accept type record")));
/*
* generate attribute metadata needed later to produce tuples from raw
* C strings
*/
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
MemoryContextSwitchTo(oldcontext);
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
call_cntr = funcctx->call_cntr;
max_calls = funcctx->max_calls;
attinmeta = funcctx->attinmeta;
if (call_cntr < max_calls) /* do when there is more left to send */
{
char **values;
HeapTuple tuple;
Datum result;
/*
* Prepare a values array for building the returned tuple.
* This should be an array of C strings which will
* be processed later by the type input functions.
*/
values = (char **) palloc(3 * sizeof(char *));
values[0] = (char *) palloc(16 * sizeof(char));
values[1] = (char *) palloc(16 * sizeof(char));
values[2] = (char *) palloc(16 * sizeof(char));
snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
/* build a tuple */
tuple = BuildTupleFromCStrings(attinmeta, values);
/* make the tuple into a datum */
result = HeapTupleGetDatum(tuple);
/* clean up (this is not really necessary) */
pfree(values[0]);
pfree(values[1]);
pfree(values[2]);
pfree(values);
SRF_RETURN_NEXT(funcctx, result);
}
else /* do when there is no more left */
{
SRF_RETURN_DONE(funcctx);
}
}
Ð SQL ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ обÑÑвиÑÑ ÑледÑÑÑим обÑазом:
CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer);
CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
RETURNS SETOF __retcomposite
AS 'имÑ_Ñайла', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT;Также ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ обÑÑвиÑÑ Ñ Ð¿Ð°ÑамеÑÑами OUT:
CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
OUT f1 integer, OUT f2 integer, OUT f3 integer)
RETURNS SETOF record
AS 'имÑ_Ñайла', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT; ÐамеÑÑÑе, ÑÑо пÑи Ñаком подÑ
оде вÑÑ
однÑм Ñипом ÑÑнкÑии ÑоÑмалÑно ÑвлÑеÑÑÑ Ð°Ð½Ð¾Ð½Ð¸Ð¼Ð½Ñй Ñип record.
37.10.9. ÐолимоÑÑнÑе ÑÐ¸Ð¿Ñ Ð°ÑгÑменÑов и ÑезÑлÑÑаÑа #
ФÑнкÑии на ÑзÑке C могÑÑ Ð±ÑÑÑ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ñ ÐºÐ°Ðº пÑинимаÑÑие и возвÑаÑаÑÑие полимоÑÑнÑе ÑипÑ, коÑоÑÑе опиÑÐ°Ð½Ñ Ð² ÐодÑазделе 37.2.5. Ðогда ÑÐ¸Ð¿Ñ Ð°ÑгÑменÑов или ÑезÑлÑÑаÑа опÑÐµÐ´ÐµÐ»ÐµÐ½Ñ ÐºÐ°Ðº полимоÑÑнÑе, авÑÐ¾Ñ ÑÑнкÑии не Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ñанее знаÑÑ, Ñ ÐºÐ°ÐºÐ¸Ð¼Ð¸ Ñипами даннÑÑ
она бÑÐ´ÐµÑ Ð²ÑзÑваÑÑÑÑ Ð¸ какой возвÑаÑаÑÑ. ЧÑÐ¾Ð±Ñ ÑÑнкÑÐ¸Ñ Ð½Ð° C в ÑÑиле веÑÑии 1 могла опÑеделиÑÑ ÑакÑиÑеÑкие ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
ÑвоиÑ
аÑгÑменÑов и Ñип, коÑоÑÑй она должна веÑнÑÑÑ, в fmgr.h пÑедлагаÑÑÑÑ Ð´Ð²Ðµ ÑÑнкÑии. Ðни назÑваÑÑÑÑ get_fn_expr_rettype(FmgrInfo *flinfo) и get_fn_expr_argtype(FmgrInfo *flinfo, int argnum) и возвÑаÑаÑÑ ÑооÑвеÑÑÑвенно OID Ñипа ÑезÑлÑÑаÑа и аÑгÑменÑа, либо InvalidOid, еÑли инÑоÑмаÑÐ¸Ñ Ð¾ Ñипе оÑÑÑÑÑÑвÑеÑ. СÑÑÑкÑÑÑÑ flinfo обÑÑно можно полÑÑиÑÑ Ð¿Ð¾ ÑÑÑлке fcinfo->flinfo. ÐÐ¾Ð¼ÐµÑ Ð°ÑгÑменÑа argnum задаÑÑÑÑ, наÑÐ¸Ð½Ð°Ñ Ñ Ð½ÑлÑ. РкаÑеÑÑве алÑÑеÑнаÑÐ¸Ð²Ñ get_fn_expr_rettype Ñакже можно иÑполÑзоваÑÑ ÑÑнкÑии get_call_result_type. ÐÑоме Ñого, еÑÑÑ ÑÑнкÑÐ¸Ñ get_fn_expr_variadic, позволÑÑÑÐ°Ñ Ð¾Ð¿ÑеделиÑÑ, бÑли ли пеÑеменнÑе аÑгÑменÑÑ Ð¾Ð±ÑÐµÐ´Ð¸Ð½ÐµÐ½Ñ Ð² маÑÑив. ÐÑо полезно в оÑновном Ð´Ð»Ñ ÑÑнкÑий VARIADIC "any", Ñак как Ñакое обÑединение вÑегда Ð¸Ð¼ÐµÐµÑ Ð¼ÐµÑÑо Ð´Ð»Ñ ÑÑнкÑий Ñ Ð¿ÐµÑеменнÑми аÑгÑменÑами, пÑинимаÑÑиÑ
обÑÑнÑе ÑипÑ.
ÐапÑимеÑ, пÑедположим, ÑÑо нам нÑжно напиÑаÑÑ ÑÑнкÑиÑ, пÑинимаÑÑÑÑ Ð¾Ð´Ð¸Ð½ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð»Ñбого Ñипа и возвÑаÑаÑÑÑÑ Ð¾Ð´Ð½Ð¾Ð¼ÐµÑнÑй маÑÑив ÑÑого Ñипа:
PG_FUNCTION_INFO_V1(make_array);
Datum
make_array(PG_FUNCTION_ARGS)
{
ArrayType *result;
Oid element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
Datum element;
bool isnull;
int16 typlen;
bool typbyval;
char typalign;
int ndims;
int dims[MAXDIM];
int lbs[MAXDIM];
if (!OidIsValid(element_type))
elog(ERROR, "could not determine data type of input");
/* полÑÑиÑÑ Ð¿ÐµÑеданнÑй ÑлеменÑ, ÑÑиÑÑваÑ, ÑÑо ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ NULL */
isnull = PG_ARGISNULL(0);
if (isnull)
element = (Datum) 0;
else
element = PG_GETARG_DATUM(0);
/* Ð¼Ñ Ð¸Ð¼ÐµÐµÐ¼ дело Ñ Ð¾Ð´Ð½Ð¾Ð¹ ÑазмеÑноÑÑÑÑ */
ndims = 1;
/* и одним ÑлеменÑом */
dims[0] = 1;
/* Ñ Ð½Ð¸Ð¶Ð½ÐµÐ¹ гÑаниÑей, Ñавной 1 */
lbs[0] = 1;
/* полÑÑиÑÑ ÑÑебÑемÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ Ñипе ÑлеменÑа */
get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
/* ÑепеÑÑ ÑоздаÑÑ Ð¼Ð°ÑÑив */
result = construct_md_array(&element, &isnull, ndims, dims, lbs,
element_type, typlen, typbyval, typalign);
PG_RETURN_ARRAYTYPE_P(result);
}СледÑÑÑÐ°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° обÑÑвлÑÐµÑ ÑÑнкÑÐ¸Ñ make_array в SQL:
CREATE FUNCTION make_array(anyelement) RETURNS anyarray
AS 'ÐÐТÐÐÐÐ/funcs', 'make_array'
LANGUAGE C IMMUTABLE;СÑÑеÑÑвÑÐµÑ Ð¾Ð´Ð¸Ð½ ваÑÐ¸Ð°Ð½Ñ Ð¿Ð¾Ð»Ð¸Ð¼Ð¾ÑÑизма, коÑоÑÑм могÑÑ Ð¿Ð¾Ð»ÑзоваÑÑÑÑ ÑолÑко ÑÑнкÑии на ÑзÑке C: иÑ
можно обÑÑвиÑÑ Ñ Ð¿Ð°ÑамеÑÑами Ñипа "any". (ÐамеÑÑÑе, ÑÑо Ð¸Ð¼Ñ ÑÑого Ñипа нÑжно заклÑÑаÑÑ Ð² двойнÑе кавÑÑки, Ñак как ÑÑо Ñакже заÑезеÑвиÑованное Ñлово в SQL.) Ðн ÑабоÑÐ°ÐµÑ Ñак же, как anyelement, за иÑклÑÑением Ñого, ÑÑо он не ÑÑебÑеÑ, ÑÑÐ¾Ð±Ñ Ð°ÑгÑменÑÑ "any" имели одинаковÑй Ñип, и не Ð¿Ð¾Ð¼Ð¾Ð³Ð°ÐµÑ Ð¾Ð¿ÑеделиÑÑ Ñип ÑезÑлÑÑаÑа ÑÑнкÑии. ФÑнкÑÐ¸Ñ Ð½Ð° ÑзÑке C можно Ñакже обÑÑвиÑÑ Ñ Ð¿Ð¾Ñледним паÑамеÑÑом VARIADIC "any". ÐÐ¼Ñ Ð±ÑдÑÑ ÑооÑвеÑÑÑвоваÑÑ Ð¾Ð´Ð¸Ð½ или более ÑакÑиÑеÑкиÑ
аÑгÑменÑов лÑбого Ñипа (не обÑзаÑелÑно одинакового). ÐÑи аÑгÑменÑÑ Ð½Ðµ бÑдÑÑ ÑобиÑаÑÑÑÑ Ð² маÑÑив, как ÑÑо пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ñ Ð¾Ð±ÑÑнÑми ÑÑнкÑиÑми Ñ Ð¿ÐµÑеменнÑми аÑгÑменÑами; они пÑоÑÑо бÑдÑÑ Ð¿ÐµÑÐµÐ´Ð°Ð½Ñ ÑÑнкÑии по оÑделÑноÑÑи. ÐÑли пÑименÑеÑÑÑ ÑÑÐ¾Ñ Ð²Ð°ÑианÑ, Ñо ÑÑÐ¾Ð±Ñ Ð¾Ð¿ÑеделиÑÑ ÑиÑло ÑакÑиÑеÑкиÑ
аÑгÑменÑов и иÑ
ÑипÑ, нÑжно иÑполÑзоваÑÑ Ð¼Ð°ÐºÑÐ¾Ñ PG_NARGS() и ÑÑнкÑии, опиÑаннÑе вÑÑе. ÐолÑзоваÑели Ñакой ÑÑнкÑии Ñакже могÑÑ Ð¿Ð¾Ð¶ÐµÐ»Ð°ÑÑ Ð¸ÑполÑзоваÑÑ ÐºÐ»ÑÑевое Ñлово VARIADIC в вÑзове ÑÑнкÑии, ожидаÑ, ÑÑо ÑÑнкÑÐ¸Ñ Ð¾Ð±ÑабоÑÐ°ÐµÑ ÑлеменÑÑ Ð¼Ð°ÑÑива как оÑделÑнÑе аÑгÑменÑÑ. ÐÑи необÑ
одимоÑÑи ÑооÑвеÑÑÑвÑÑÑее поведение должна ÑеализовÑваÑÑ Ñама ÑÑнкÑиÑ, опÑеделив Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ get_fn_expr_variadic, бÑл ли ÑакÑиÑеÑкий аÑгÑÐ¼ÐµÐ½Ñ Ð¿ÐµÑедан Ñ Ñказанием VARIADIC.
37.10.10. РазделÑÐµÐ¼Ð°Ñ Ð¿Ð°Ð¼ÑÑÑ Ð¸ лÑгкие блокиÑовки #
ÐодÑли ÑаÑÑиÑений могÑÑ ÑезеÑвиÑоваÑÑ Ð»Ñгкие блокиÑовки и облаÑÑÑ Ð² ÑазделÑемой памÑÑи пÑи запÑÑке ÑеÑвеÑа. ЧÑÐ¾Ð±Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ñека модÑÐ»Ñ Ð¿ÑедваÑиÑелÑно загÑÑжалаÑÑ Ð½Ð° ÑÑапе запÑÑка ÑеÑвеÑа, нÑжно ÑказаÑÑ ÐµÑ Ð² shared_preload_libraries. ÐиблиоÑека должна заÑегиÑÑÑиÑоваÑÑ Ð² Ñвоей ÑÑнкÑии _PG_init обÑабоÑÑик shmem_request_hook, коÑоÑÑй ÑÐ¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð¿ÑоÑиÑÑ Ð½ÑжнÑе ÑеÑÑÑÑÑ. ЧÑÐ¾Ð±Ñ Ð·Ð°ÑезеÑвиÑоваÑÑ ÑазделÑемÑÑ Ð¿Ð°Ð¼ÑÑÑ, вÑзовиÑе из shmem_request_hook:
void RequestAddinShmemSpace(int size)
ЧÑÐ¾Ð±Ñ Ð·Ð°ÑезеÑвиÑоваÑÑ Ð»Ñгкие блокиÑовки, из shmem_request_hook нÑжно вÑзваÑÑ:
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Ð ÑезÑлÑÑаÑе бÑÐ´ÐµÑ ÑÑоÑмиÑован маÑÑив из num_lwlocks лÑгкиÑ
блокиÑовок под именем tranche_name. ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÐ¾Ñ Ð¼Ð°ÑÑив, воÑполÑзÑйÑеÑÑ ÑÑнкÑией GetNamedLWLockTranche.
Ðо избежание возможнÑÑ
ÑÑловий гонки каждÑй обÑлÑживаÑÑий пÑоÑеÑÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ вÑзÑваÑÑ LWLock AddinShmemInitLock в Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¿Ð¾Ð´ÐºÐ»ÑÑÐµÐ½Ð¸Ñ Ð¸ пÑи иниÑиализаÑии ÑазделÑемой памÑÑи, как показано здеÑÑ:
static mystruct *ptr = NULL;
if (!ptr)
{
bool found;
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
ptr = ShmemInitStruct("my struct name", size, &found);
if (!found)
{
/* иниÑиализиÑоваÑÑ ÑодеÑжимое облаÑÑи ÑазделÑемой памÑÑи; */
/* полÑÑиÑÑ Ð²Ñе ÑÑебÑемÑе блокиÑовки LWLocks:
*/ ptr->locks = GetNamedLWLockTranche("my tranche name");
}
LWLockRelease(AddinShmemInitLock);
}37.10.11. ÐÑполÑзование C++ Ð´Ð»Ñ ÑаÑÑиÑÑемоÑÑи #
ХоÑÑ ÐºÐ¾Ð´ ÑеÑвеÑа Postgres Pro напиÑан на C, ÑаÑÑиÑÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ можно пиÑаÑÑ Ð¸ на C++, еÑли ÑоблÑдаÑÑ ÑÑи пÑавила:
ÐÑе ÑÑнкÑии, к коÑоÑÑм бÑÐ´ÐµÑ Ð¾Ð±ÑаÑаÑÑÑÑ ÑеÑвеÑ, Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÑедоÑÑавлÑÑÑ ÐµÐ¼Ñ Ð¸Ð½ÑеÑÑÐµÐ¹Ñ C; ÑÑи ÑÑнкÑии на C заÑем могÑÑ Ð²ÑзÑваÑÑ ÑÑнкÑии на ÑзÑке C++. Ð ÑаÑÑноÑÑи, Ð´Ð»Ñ ÑÑнкÑий, доÑÑÑпнÑÑ ÑеÑвеÑÑ, Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ ÑказаÑÑ
extern C. ÐÑо Ñакже Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ Ð´Ð»Ñ Ð²ÑÐµÑ ÑÑнкÑий, ÑказаÑели на коÑоÑÑе пеÑедаÑÑÑÑ Ð¼ÐµÐ¶Ð´Ñ ÐºÐ¾Ð´Ð¾Ð¼ ÑеÑвеÑа и подклÑÑаемÑм кодом на C++.ÐÑвобождайÑе памÑÑÑ, пÑименÑÑ Ð´Ð»Ñ ÑÑого Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий меÑод. ÐапÑимеÑ, памÑÑÑ ÑеÑвеÑа в оÑновном вÑделÑеÑÑÑ ÑÑнкÑией
palloc(), Ñак ÑÑо оÑвобождаÑÑ ÐµÑ Ð½Ñжно, вÑзÑваÑpfree(). ÐопÑÑка иÑполÑзоваÑÑ Ð² ÑÐ°ÐºÐ¸Ñ ÑлÑÑаÑÑ Ð¿ÑинÑÑÑÑ Ð² C++ опеÑаÑиÑdeleteпÑиведÑÑ Ðº оÑибке.Ðе допÑÑкайÑе ÑаÑпÑоÑÑÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¸ÑклÑÑений в код C (добавлÑйÑе блок, пеÑÐµÑ Ð²Ð°ÑÑваÑÑий вÑе иÑклÑÑениÑ, на веÑÑ Ð½ÐµÐ¼ ÑÑовне ÑÑнкÑий
extern C). ÐÑо Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾, даже еÑли код на C++ не генеÑиÑÑÐµÑ Ð¸ÑклÑÑÐµÐ½Ð¸Ñ Ñвно, поÑÐ¾Ð¼Ñ ÑÑо иÑклÑÑÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑÑ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÑÑ, напÑимеÑ, и пÑи Ð½ÐµÑ Ð²Ð°Ñке памÑÑи. ÐÑе иÑклÑÑÐµÐ½Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÐµÑÐµÑ Ð²Ð°ÑÑваÑÑÑÑ, и в инÑеÑÑÐµÐ¹Ñ C Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¿ÐµÑедаваÑÑÑÑ ÑооÑвеÑÑÑвÑÑÑие оÑибки. ÐÑли возможно, ÑкомпилиÑÑйÑе код C++ Ñ Ñказанием-fno-exceptions, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ Ð¾ÑклÑÑиÑÑ Ð¸ÑклÑÑениÑ; в ÑÐ°ÐºÐ¸Ñ ÑлÑÑаÑÑ Ð²Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑдеÑе вÑÑвлÑÑÑ Ð¸ÑклÑÑиÑелÑнÑе ÑиÑÑаÑии в коде C++, напÑимеÑ, пÑовеÑÑÑÑ Ð½Ð° NULL адÑеÑ, возвÑаÑÑннÑйnew().ÐÑзÑÐ²Ð°Ñ ÑеÑвеÑнÑе ÑÑнкÑии из кода C++, ÑбедиÑеÑÑ, ÑÑо в ÑÑеке вÑзова C++ ÑодеÑжаÑÑÑ ÑолÑко пÑоÑÑÑе ÑÑÑÑкÑÑÑÑ Ð´Ð°Ð½Ð½ÑÑ . ÐÑо Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾, поÑÐ¾Ð¼Ñ ÑÑо в ÑлÑÑае оÑибки ÑеÑвеÑа вÑполнÑеÑÑÑ ÑÑнкÑиÑ
longjmp(), а она не оÑмаÑÑÐ²Ð°ÐµÑ ÑÑек вÑзовов C++ должнÑм обÑазом Ð´Ð»Ñ Ð¾Ð±ÑекÑов, оÑлиÑнÑÑ Ð¾Ñ Ð¿ÑоÑÑÑÑ ÑÑÑÑкÑÑÑ.
РезÑмиÑÑÑ, лÑÑÑе вÑего помеÑÑиÑÑ ÐºÐ¾Ð´ C++ за огÑÐ°Ð´Ñ Ð¸Ð· ÑÑнкÑий extern C, коÑоÑÑе бÑдÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ ÑеÑвеÑÑ Ð¸ ÑмогÑÑ Ð·Ð°ÑиÑиÑÑ Ð¾Ñ Ð¸ÑклÑÑений, а Ñакже поÑеÑи ÑÑека вÑзовов и ÑÑеÑки памÑÑи.