33.9. C¾ð¾î ÇÔ¼ö

»ç¿ëÀÚ Á¤ÀÇÀÇ ÇÔ¼ö´Â C(ȤÀº C++¿Í °°Àº C¿Í ȣȯ¼ºÀÌ ÀÖ´Â ¾ð¾î)·Î ÀÛ¼ºÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ±×·¯ÇÑ ÇÔ¼ö´Â µ¿Àû ·Îµå °¡´É ¿ÀºêÁ§Æ®(°øÀ¯ ¶óÀ̺귯¸®¶ó°íµµ ºÒ¸³´Ï´Ù)·Î¼­ ÄÄÆÄÀÏ µÇ¾î Çʿ信 µû¶ó¼­ ¼­¹ö¿¡ ·Îµå µË´Ï´Ù. µ¿Àû ·Îµå ±â´ÉÀÌ, "C¾ð¾î"ÇÔ¼ö¸¦ "³»ºÎ"ÇÔ¼ö¿Í ±¸º°ÇÏ´Â °ÍÀÔ´Ï´Ù. ÄÚµù ¹æ¹ýÀº ±âº»ÀûÀ¸·Î ¾çÂÊ ¸ðµÎ °°½À´Ï´Ù (µû¶ó, Ç¥ÁØ ³»ºÎ ÇÔ¼ö ¶óÀ̺귯¸®´Â, »ç¿ëÀÚ Á¤ÀÇÀÇ CÇÔ¼öÀÇ ÄÚµù ¿¹ÀÇ Ç³ºÎÇÑ Á¤º¸¿øÀÌ µË´Ï´Ù).

ÇöÀç, µÎ °¡ÁöÀÇ ´Ù¸¥ È£Ãâ ±Ô¾àÀÌ CÇÔ¼ö·Î »ç¿ëµÇ°í ÀÖ½À´Ï´Ù. º¸´Ù »õ·Î¿î "Version-1"È£Ãâ ±Ô¾àÀº, ÀÌÇÏ¿¡ ³ªÅ¸³»µíÀÌ, ±× ÇÔ¼ö¿ëÀ¸·Î È£Ãâ ¸ÅÅ©·ÎPG_FUNCTION_INFO_V1()¸¦ ¾²´Â °ÍÀ¸·Î ³ªÅ¸³³´Ï´Ù. ÀÌ ¸ÅÅ©·Î°¡ Á¸ÀçÇÏÁö ¾ÊÀ¸¸é, ±¸Çü½Ä("Version-0")ÀÇ ÇÔ¼öÀÎ °ÍÀ» ³ªÅ¸³À´Ï´Ù. ¾î´À ÂÊÀÇ °æ¿ìµµ CREATE FUNCTION·Î ÁöÁ¤ÇÏ´Â ¾ð¾î¸íÀº CÀÔ´Ï´Ù. ±¸Çü½ÄÀÇ ÇÔ¼ö´Â, À̽ļºÀÇ ¹®Á¦¿Í ±â´ÉÀÇ ºÎÁ·¶§¹®¿¡ ±ÇÀ¯¹ÞÁö ¾Ê½À´Ï´Ù. À̰ÍÀº ÇöÀç, ȣȯ¼ºÀÇ ÀÌÀ¯ ¶§¹®¿¡ Á¸ÀçÇϰí ÀÖ½À´Ï´Ù.

33.9.1. µ¿Àû ·Îµù

ƯÁ¤ÀÇ ·Îµå °¡´É °´Ã¼ ³»ÀÇ »ç¿ëÀÚ Á¤ÀÇÀÇ ÇÔ¼ö°¡ ¼¼¼ÇÀ¸·Î ÃÖÃÊ·Î ºÒ·Á °¡¸é, µ¿Àû ·Î´õ´Â, ±× ÇÔ¼ö¸¦ È£ÃâÇÒ ¼ö ÀÖµµ·Ï, °´Ã¼ ÆÄÀÏÀ» ¸Þ¸ð¸®³»¿¡ ÀоîµéÀÔ´Ï´Ù. ±× ¶§¹®¿¡, »ç¿ëÀÚ Á¤ÀÇ CÇÔ¼ö¿ëÀÇ CREATE FUNCTION´Â ±× ÇÔ¼ö¿¡ ´ëÇØ, ·Îµå °¡´É °´Ã¼ ÆÄÀÏÀÇ À̸§°ú, °´Ã¼ ÆÄÀÏÀÌ ºÒ·Á °¡´Â ƯÁ¤ÀÇ ÇÔ¼öÀÇ C¸íĪ(¸µÅ© ½Éº¼)À̶ó´Â 2°³ÀÇ Á¤º¸¸¦ ÁöÁ¤ÇؾßÇÕ´Ï´Ù. C¸íĪÀÌ ¸í½ÃÀûÀ¸·Î ÁöÁ¤µÇÁö ¾Ê¾Ò´ø °æ¿ì, SQL¿¡¼­ÀÇ ÇÔ¼ö¸í°ú °°Àº °Í°ú °¡Á¤µË´Ï´Ù.

CREATE FUNCTION¸í·ÉÀ¸·Î ÁÖ¾îÁø À̸§¿¡ ±Ù°ÅÇØ, °øÀ¯ °´Ã¼ ÆÄÀÏÀÇ Àå¼Ò¸¦ ã¾Æ³¾ ¶§¿¡ ÀÌÇÏÀÇ ¾Ë°í¸®ÁòÀÌ »ç¿ëµË´Ï´Ù.

  1. À̸§ÀÌ Àý´ë ÆÐ½ºÀÇ °æ¿ì, ÁöÁ¤µÈ ÆÄÀÏÀÌ ÀÐÈü´Ï´Ù.

  2. À̸§ÀÌ $libdir¶ó°í ÇÏ´Â ¹®ÀÚ¿­·Î ½ÃÀ۵Ǵ °æ¿ì, ±× ºÎºÐÀº PostgreSQLÆÐŰÁöÀÇ ¶óÀ̺귯¸® µð·ºÅ丮¿¡¼­ ¿Å°Ü³õÀ» ¼ö ÀÖ½À´Ï´Ù. ÀÌ µð·ºÅ丮´Â ±¸Ãà ½Ã °áÁ¤µË´Ï´Ù.

  3. À̸§¿¡ µð·ºÅ丮 ºÎºÐÀÌ ¾ø´Â °æ¿ì, ±× ÆÄÀÏÀº dynamic_library_path¼³Á¤ º¯¼ö·Î ÁöÁ¤µÈ ÆÐ½º³»·ÎºÎÅÍ °Ë»öµË´Ï´Ù.

  4. »ó±â ÀÌ¿ÜÀÇ °æ¿ì(ÆÄÀÏÀÌ ÆÐ½º³»¿¡ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì³ª »ó´ë µð·ºÅ丮 ºÎºÐÀ» °¡Áö´Â °æ¿ì), µ¿Àû ·Î´õ´Â ÁöÁ¤µÈ À̸§À» ±×´ë·Î »ç¿ëÇØ, ´ëºÎºÐÀÇ °æ¿ì´Â ½ÇÆÐÇÕ´Ï´Ù (À̰ÍÀº ÇöÀçÀÇ ÀÛ¾÷ µð·ºÅ丮¿¡ ÀÇÁ¸Çϱâ À§ÇØ ½Å·ÚÇÒ ¼ö ¾ø½À´Ï´Ù).

¿©±â±îÁöÀÇ È帧ÀÌ Àß µÇÁö ¾Ê¾Ò´ø °æ¿ì, Ç÷§Æû µ¶ÀÚÀûÀÎ °øÀ¯ ¶óÀ̺귯¸® ÆÄÀÏ È®ÀåÀÚ(extension)(¸¹Àº °æ¿ì. so)°¡ ÁöÁ¤µÈ À̸§¿¡ Ãß°¡µÇ¾î ÀçÂ÷ ÀÌ È帧À» ½ÃµµÇÕ´Ï´Ù. ¶Ç ½ÇÆÐÇßÀ» °æ¿ì, ·Îµå°¡ ½ÇÆÐÇÕ´Ï´Ù.

°øÀ¯ ¶óÀ̺귯¸®¸¦ $libdir·ÎºÎÅÍ »ó´ëÀûÀ¸·Î, ȤÀº µ¿Àû ¶óÀ̺귯¸® ÆÐ½º°¡ ´Ù´Ñ °÷¿¡ ¹èÄ¡ÇÏ´Â °ÍÀ» Ãßõ ÇÕ´Ï´Ù. ´Ù¸¥ Àå¼Ò¿¡ »õ·Î¿î ¼³Ä¡¸¦ ¹èÄ¡ÇÏ´Â °æ¿ì¿¡ ¹öÀü ¾÷À» °£´ÜÇÏ°Ô ÇÕ´Ï´Ù. $libdir°¡ °¡¸®Å°´Â ½ÇÁ¦ÀÇ µð·ºÅ丮´Â pg_config --pkglibdir¸í·ÉÀ» »ç¿ëÇÏ´Â °ÍÀ¸·Î ÇÕ´Ï´Ù.

PostgreSQL¼­¹öÀÇ ½ÇÈ¿ »ç¿ëÀÚ ID´Â ·Îµå ¿¹Á¤ÀÇ ÆÄÀÏÀÇ ÆÐ½º±îÁö µµ´ÞÇÒ ¼ö ÀÖ¾î¾ß ÇÕ´Ï´Ù. postgres»ç¿ëÀÚ¿¡ ÀÇÇØ ÀÐÀ» ¼ö ÀÖ°í, ½ÇÇà°¡´ÉÇÑ ÆÄÀÏ »Ó¸¸ ¾Æ´Ï¶ó »óÀ§ µð·ºÅ丮¸¦¸¸µéÁö ¸øÇÏ´Â °ÍÀÌ ÀÚÁÖ ÀÖ´Â ½Ç¼öÀÔ´Ï´Ù.

¾î´À °æ¿ì¿¡¼­µµ, CREATE FUNCTION¸í·É¿¡°Ô ÁØ ÆÄÀϸíÀº ±×´ë·Î ½Ã½ºÅÛ Ä«Å»·Î±×¿¡ º¸Á¸µË´Ï´Ù. ±×·¯¹Ç·Î, ¸¸¾à ±× ÆÄÀÏÀ» ÀçÂ÷ ÀоîµéÀÏ Çʿ䰡 ÀÖ´Â °æ¿ì, °°Àº 󸮰¡ Àû¿ëµË´Ï´Ù.

Note: PostgreSQL´Â CÇÔ¼ö¸¦ ÀÚµ¿ÀûÀ¸·Î ÄÄÆÄÀÏ ÇÏÁö ¾Ê½À´Ï´Ù. CREATE FUNCTION¸í·ÉÀ¸·Î ÂüÁ¶Çϱâ Àü¿¡, ±× °´Ã¼ ÆÄÀÏÀº ÄÄÆÄÀϵǾî ÀÖÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. »õ·Î¿î Á¤º¸¿¡ ´ëÇØ¼­´Â, Section 33.9.6À» ÂüÁ¶ÇØ ÁÖ¼¼¿ä.

µ¿ÀûÀ¸·Î ·ÎµåµÈ °´Ã¼ ÆÄÀÏÀÌ È£È¯¼ºÀÌ ¾ø´Â ¼­¹ö¿¡ ·ÎµåµÇÁö ¾Ê°Ô Çϱâ À§ÇØ, PostgreSQL´Â, ±× ÆÄÀÏ¿¡ ÀûÀýÇÑ ³»¿ëÀ» °¡Áö´Â "¸¶¹ýÀÇ ºí·Ï"ÀÌ Æ÷ÇԵǾî ÀÖ´ÂÁö °Ë»çÇÕ´Ï´Ù. ¸ÞÀÌÀú ¹öÁ¯ÀÌ ´Ù¸¥ PostgreSQL¿ëÀ¸·Î ÄÄÆÄÀÏ µÈ ¸ðµâ µî°ú °°ÀÌ, ¼­¹ö°¡ ´«¿¡ ¶ç°Ô ȣȯ¼ºÀÌ ¾ø´Â °ÍÀ» °¨ÁöÇÏ°Ô ÇØÁÝ´Ï´Ù. ¸¶¹ýÀÇ ºí·ÏÀº PostgreSQL 8.2·ÎºÎÅÍ ¿ä±¸µÇ°í ÀÖ½À´Ï´Ù. ¸¶¹ýÀÇ ºí·ÏÀ» Æ÷ÇÔ½ÃŰ·Á¸é,ÀÌÇϸ¦ ¸ðµâÀÇ ¼Ò½º ÆÄÀÏ¿¡ ÇÑ ¹ø(ÇÑ ¹ø¸¸), fmgr.hÇì´õ ÆÄÀÏÀ» Æ÷ÇÔ½ÃŲ ´ÙÀ½¿¡, ±â¼úÇØ ÁÖ¼¼¿ä.

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

±× Äڵ带 ¸±¸®½º 8.2º¸´Ù ÀÌÀüÀÇ PostgreSQL¿ëÀ¸·Î ÄÄÆÄÀÏ ÇÒ Çʿ䰡 ¾øÀ¸¸é, #ifdefÅ×½ºÆ®¸¦ »ý·« ÇÒ ¼ö ÀÖ½À´Ï´Ù.

ÃÖÃÊ·Î »ç¿ëµÈ ÈÄ¿¡, µ¿ÀûÀ¸·Î ·Îµå µÈ °´Ã¼´Â ¸Þ¸ð¸® ³»¿¡ º¸°ü À¯ÁöµË´Ï´Ù. µ¿ÀÏ ¼¼¼Ç¿¡ ´ëÇØ ±× ÆÄÀÏ ³»ÀÇ ÇÔ¼ö¸¦ ÇâÈÄ¿¡ È£ÃâÇßÀ» °æ¿ì, ½Éº¼ Å×ÀÌºí °Ë»ö¿¡ ÇÊ¿äÇÑ ÀÛÀº ¿À¹öÇìµå ¹Û¿¡ °É¸®Áö ¾Ê½À´Ï´Ù. ¿¹¸¦ µé¸é ÀçÄÄÆÄÀÏ ÇÑ ÈÄ Ã³·³, ±× °´Ã¼ ÆÄÀÏÀ» °­Á¦ÀûÀ¸·Î ÀçÂ÷ ·ÎµåÇÏ°Ô ÇÒ Çʿ䰡 ÀÖ´Â °æ¿ì´Â, LOAD ¸í·ÉÀ» »ç¿ëÇϰųª »õ·Î¿î ¼¼¼ÇÀ» ½ÃÀÛÇØ ÁÖ¼¼¿ä.

»ý·« ÇÒ ¼öµµ ÀÖ½À´Ï´Ù¸¸, µ¿ÀûÀ¸·Î ·Îµå µÇ´Â ÆÄÀÏ¿¡, ÃʱâÈ­ ó¸® ÇÔ¼ö¿Í ÃÖÁ¾ ó¸® ÇÔ¼ö¸¦ Æ÷ÇÔÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. _PG_init¶ó°í ÇÏ´Â ÇÔ¼ö°¡ ÆÄÀÏ¿¡ Á¸ÀçÇϸé, ÀÌ ÇÔ¼ö´Â ÆÄÀÏÀÌ ·Îµå µÈ Á÷ÈÄ¿¡ ºÒ·Á °©´Ï´Ù. _PG_fini¶ó°í ÇÏ´Â ÇÔ¼ö°¡ ÆÄÀÏ¿¡ Á¸ÀçÇϸé, ÀÌ ÇÔ¼ö´Â ÆÄÀÏÀÌ ¾ð·ÎµåµÇ±â Á÷Àü¿¡ ºÒ·Á °©´Ï´Ù. ¶Ç, ÀÌ ÇÔ¼ö´Â ÀÎÀÚ¸¦ ÃëÇÏÁö ¾Ê°í ºó °ªÀ» µ¹·ÁÁÖÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. _PG_fini°¡ ÆÄÀÏÀÇ ¾ð·Îµå½Ã¿¡¸¸ ºÒ·Á °¡´Â °ÍÀ¸·Î, ó¸®ÀÇ Á¾·á½Ã¿¡ ºÒ·Á °¡´Â °ÍÀÌ ¾Æ´Ñ °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä. (ÇöÀç, ¾ð·Îµå´Â ¸í½ÃÀûÀÎ LOAD¸í·É¿¡ ÀÇÇÑ ÆÄÀÏ Àç·ÎµåÀÇ ¹®¸Æ¿¡¼­¸¸ ¹ß»ýÇÕ´Ï´Ù. )

33.9.2. C¾ð¾î ÇÔ¼öÀÇ ±âº»Çü

C¾ð¾î ÇÔ¼öÀÇ ÀÛ¼º ¹æ¹ýÀ» ÀÌÇØÇϱâ À§Çؼ­´Â, PostgreSQL°¡ ±âº» µ¥ÀÌÅÍÇüÀ» ³»ºÎ¿¡¼­ ¾î¶»°Ô Ç¥ÇöÇØ, ¾î¶»°Ô ±×°ÍµéÀ» ÇÔ¼ö·Î ±³È¯Çϰí ÀÖ´ÂÁö¸¦ ÀÌÇØÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù. ³»ºÎÀûÀ¸·Î PostgreSQL´Â ±âº»ÇüÀ» "¸Þ¸ð¸®ÀÇ ÀÛÀº µ¢¾î¸®"·Î °£ÁÖÇÕ´Ï´Ù. ¾î¶°ÇÑ ÇüŸ¦ Á¤ÀÇÇÏ´Â »ç¿ëÀÚ Á¤ÀÇ ÇÔ¼ö´Â, ¹Ù²Ù¾î ¸»Çϸé, PostgreSQL°¡ ±×°ÍÀ» Á¶ÀÛÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀ» Á¤ÀÇÇÕ´Ï´Ù. Áï, PostgreSQL´Â µ¥ÀÌÅÍÀÇ ÀúÀå, µð½ºÅ©·ÎºÎÅÍÀÇ Ãëµæ¸¸À» ½Ç½ÃÇØ, µ¥ÀÌÅÍÀÇ ÀÔ·ÂÀ̳ª ó¸®, Ãâ·Â¿¡´Â »ç¿ëÀÚ Á¤ÀÇ ÇÔ¼ö¸¦ »ç¿ëÇÕ´Ï´Ù.

±âº»ÇüÀº ¾Æ·¡¿Í °°Àº ¼¼ °¡Áö Áß ÇϳªÀÇ ³»ºÎ ¼­½ÄÀ» »ç¿ëÇϰí ÀÖ½À´Ï´Ù.

°ªÀεµ´Â, 1, 2, 4¹ÙÀÌÆ® ±æÀÌÀÇ ÇüŸ¸ÀÌ »ç¿ë °¡´ÉÇÕ´Ï´Ù(»ç¿ëÇÏ´Â ¸Ó½ÅÀÇ sizeof(Datum)°¡ 8ÀÇ °æ¿ì´Â 8¹ÙÀÌÆ®³ª °¡´ÉÇÕ´Ï´Ù). µ¥ÀÌÅÍÇüÀ» Á¤ÀÇÇÒ ¶§, ±× ÇüŰ¡ ¸ðµç ¾ÆÅ°ÅØÃÄ¿¡ ´ëÇØ µ¿ÀÏÇÑ Å©±â(¹ÙÀÌÆ®¼ö)°¡ µÇµµ·Ï Á¤ÀÇÇϵµ·Ï ÁÖÀÇÇØ ÁÖ¼¼¿ä. ¿¹¸¦ µé¸é, longÇüÀº ¸Ó½Å¿¡ µû¶ó¼­´Â 4¹ÙÀÌÆ®³ª 8¹ÙÀÌÆ®À̱⠶§¹®¿¡ À§ÇèÇÏÁö¸¸, intÇüÀº ´ëºÎºÐÀÇ Unix ¸Ó½Å¿¡¼­´Â 4¹ÙÀÌÆ®ÀÔ´Ï´Ù. Unix ¸Ó½Å¿¡ À־ÀÇ int4ÀÇ ÀÌ·ÐÀûÀÎ ±¸ÇöÀº ÀÌÇÏ¿Í °°ÀÌ µË´Ï´Ù.

/* 4-byte integer, passed by value */
typedef int int4;

ÇÑÆí, ÀÓÀÇÀÇ Å©±âÀÇ °íÁ¤ ±æÀÌÀÇ ÇüÅ´ ÂüÁ¶·Î¼­ ÀεµÇÏ´Â °ÍÀÌ °¡´ÉÇÕ´Ï´Ù. ¿¹·Î¼­ ÀÌÇÏ¿¡ PostgreSQLÀÇ ÇüÅÂÀÇ ±¸Çö »ùÇÃÀ» ³ªÅ¸³À´Ï´Ù.

/* 16 ¹ÙÀÌÆ® ±¸Á¶Ã¼, ÂüÁ¶ Àεµ */
typedef struct
{
    double  x, y;
} Point;

±×·¯ÇÑ ÇüÅÂÀÇ Æ÷ÀÎÅ͸¸ÀÌ PostgreSQLÇÔ¼öÀÇ ÀÔÃâ·Â½Ã¿¡ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù. ±×·¯ÇÑ ÇüÅÂÀÇ °ªÀ» µ¹·ÁÁÖ±â À§Çؼ­´Â, palloc()¸¦ »ç¿ëÇØ ¿Ã¹Ù¸¥ Å©±âÀÇ ¸Þ¸ð¸® ¿µ¿ªÀ» ÇÒ´çÇØ ±× ¸Þ¸ð¸® ¿µ¿ª¿¡ °ªÀ» ÀÔ·ÂÇØ, ±×°ÍÀÇ Æ÷ÀÎÅ͸¦ µ¹·ÁÁÝ´Ï´Ù (¶Ç, ÀÔ·Â ÀÎÀÚÀÇ Çϳª¿Í °°Àº ÇüÅÂÀÇ °°Àº °ªÀ» µ¹·ÁÁÖ°í ½ÍÀº °ÍÀ̸é, palloc¸¦ ½Ç½ÃÇÏ´Â ¼ö°í¸¦ »ý·«ÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ÀÌ °æ¿ì´Â ÀԷ°ª¿¡ Æ÷ÀÎÅ͸¦ ´ÜÁö µ¹·ÁÁÖ¼¼¿ä).

¸¶Áö¸·À¸·Î, ¸ðµç °¡º¯ ±æÀÌÇüÀº ÂüÁ¶·Î¼­ ÀεµÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù. ¶Ç, ¸ðµç °¡º¯ ±æÀÌÇüÀº Á¤È®ÇÏ°Ô 4¹ÙÀÌÆ®ÀÇ length Çʵå·ÎºÎÅÍ ½ÃÀÛµÉ Çʿ䰡 ÀÖ¾î, ±× ÇüÅ¿¡ ÀúÀåµÇ´Â ¸ðµç µ¥ÀÌÅÍ´Â length ÇʵåÀÇ ¹Ù·Î ÈÄÀÇ ¸Þ¸ð¸® ¿µ¿ª¿¡ ³õ¿©Áú Çʿ䰡 ÀÖ½À´Ï´Ù. length Çʵ忡´Â ±× ±¸Á¶ÀÇ ÃÑ ±æÀ̰¡ ÀúÀåµË´Ï´Ù. Áï, length ÇÊµå ±× ÀÚüµµ ±× Å©±â¿¡ Æ÷ÇԵ˴ϴÙ.

Warning

ÂüÁ¶ ÀεµÀÇ ÀԷ°ªÀÇ ³»¿ëÀ» °áÄÚ º¯°æÇÏÁö ¸»¾Æ ÁÖ¼¼¿ä. ÁöÁ¤ÇÑ Æ÷ÀÎÅͰ¡ µð½ºÅ© ¹öÆÛ¸¦ Á÷Á¢ Áö½ÃÇϰí ÀÖÀ» °¡´É¼ºÀÌ ÀÚÁÖ Àֱ⠶§¹®¿¡, º¯°æÇÏ¸é µð½ºÅ©»óÀÇ µ¥ÀÌÅ͸¦ ÆÄ±«ÇØ ¹ö¸±Áöµµ ¸ð¸¨´Ï´Ù. ÀÌ ±ÔÄ¢ÀÇ À¯ÀÏÇÑ ¿¹¿Ü¿¡ ´ëÇØ Section 33.10·Î ¼³¸íÇÕ´Ï´Ù.

¿¹¸¦ µé¸é, textÇüÀ» Á¤ÀÇÇÏ·Á¸é, ¾Æ·¡¿Í °°ÀÌ ½Ç½ÃÇÒ ¼ö ÀÖ½À´Ï´Ù.

typedef struct {
    int4 length;
    char data[1];
} text;

¿©±â¼­ ¼±¾ðµÈ µ¥ÀÌÅÍ Çʵå´Â, ºÐ¸íÇÏ°Ô ¸ðµç ÃëÇÒ ¼ö ÀÖ´Â ¹®ÀÚ¿­À» º¸°ü À¯ÁöÇÒ ¼ö ÀÖ´Â ±æÀ̰¡ ¾Æ´Õ´Ï´Ù. C¾ð¾î¿¡¼­´Â °¡º¯ ±æÀÌÀÇ ±¸Á¶¸¦ Á¤ÀÇÇÏ´Â °ÍÀº ºÒ°¡´ÉÇϹǷÎ, CÄÄÆÄÀÏ·¯´Â ¹è¿­ÀÇ Ã·ÀÚÀÇ ¹üÀ§ °Ë»ç¸¦ ½Ç½ÃÇÏÁö ¾Ê´Â´Ù´Â »ç½Ç¿¡ ÀÇÁ¸ÇÕ´Ï´Ù. ÇÊ¿äÇÑ ¿µ¿ª·®À» ÇÒ´çÇØ ¸¶Ä¡ ¿Ã¹Ù¸¥ ±æÀÌ·Î ¼±¾ðµÈ °Í °°ÀÌ, ¹è¿­·Î¼­ Á¢±Ù ÇÒ »ÓÀÔ´Ï´Ù (ÀÌ ¼ö¹ýÀº ÀÚÁÖ »ç¿ëµË´Ï´Ù. C¾ð¾î¿¡ °üÇÑ ¸¹Àº ¼­ÀûÀ¸·Î ¼³¸íµÇ°í ÀÖ½À´Ï´Ù).

°¡º¯ ±æÀÌÇüÀ» Á¶ÀÛÇÒ ¶§, Á¤È®ÇÑ Å©±âÀÇ ¸Þ¸ð¸®¸¦ ÇÒ´çÇØ length Çʵ带 Á¤È®ÇÏ°Ô ¼³Á¤ÇÏ´Â °Í¿¡ ÁÖÀÇÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù. ¿¹¸¦ µé¸é, 40¹ÙÀÌÆ®¸¦ text±¸Á¶¿¡ º¸°ü À¯Áö½ÃŰ°í ½ÍÀº °æ¿ì, ¾Æ·¡¿Í °°Àº Äڵ带 »ç¿ëÇÕ´Ï´Ù.

#include "postgres.h"
...
char buffer[40]; /* our source data */
...
text *destination = (text *) palloc(VARHDRSZ + 40);
destination->length = VARHDRSZ + 40;
memcpy(destination->data, buffer, 40);
...

VARHDRSZ´Â sizeof(int4)¿Í µ¿ÀÏÇÕ´Ï´Ù¸¸, °¡º¯ ±æÀÌÇüÀÇ ¿À¹öÇìµåÀÇ Å©±â¸¦ ÂüÁ¶ÇÒ ¶§¿¡´Â, VARHDRSZ¸ÅÅ©·Î¸¦ »ç¿ëÇÏ´Â ÆíÀÌ ¹Ù¶÷Á÷ÇÑ Çü½ÄÀ¸·Î °£ÁÖÇØÁö°í ÀÖ½À´Ï´Ù.

Table 33-1´Â, PostgreSQLÀÇ ³»ÀåÇüÀ» »ç¿ëÇÏ´Â C¾ð¾î ÇÔ¼ö¸¦ ÀÛ¼ºÇÒ ¶§ÀÇ, CÀÇ ÇüÅÂ¿Í SQLÇü°úÀÇ ´ëÀÀÀ» ÁöÁ¤ÇÑ °ÍÀÔ´Ï´Ù. "Á¤ÀÇ Àå¼Ò"¿­¿¡¼­´Â, ÇüÅ Á¤ÀǸ¦ ²¨³»±â À§Çؼ­ Æ÷ÇÔÇØ¾ß ÇÏ´Â Çì´õ ÆÄÀÏÀ» ³ªÅ¸³»°í ÀÖ½À´Ï´Ù (½ÇÁ¦ÀÇ Á¤ÀÇ´Â ÆÄÀÏ¿¡ ¿­¶÷µÈ °Í°ú´Â ´Ù¸¦ °¡´É¼ºÀÌ ÀÖ½À´Ï´Ù. »ç¿ëÀÚ°¡ Á¤ÀÇµÈ ÀÎÅÍÆäÀ̽º¸¦ ¾ö¼öÇÏ´Â °ÍÀ» ÃßõµÇ°í ÀÖ½À´Ï´Ù). postgres.h¿¡´Â ¹Ýµå½Ã ÇÊ¿äÇÑ ¸¹Àº °ÍÀÌ ¼±¾ðµÇ°í Àֱ⠶§¹®¿¡, ¹Ýµå½Ã óÀ½¿¡ ¼Ò½º ÆÄÀÏ¿¡ ÀÌ ÆÄÀÏÀ» Æ÷ÇÔÇØ¾ß ÇÏ´Â °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä.

Table 33-1. ³»ÀåÇü SQLÇü¿¡ »óÀÀÇÏ´Â CÀÇ ÇüÅÂ

SQLÇü C ¾ð¾îÇü Á¤ÀÇ Àå¼Ò
abstime AbsoluteTime utils/nabstime.h
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
smallint (int2) int2 or int16 postgres.h
int2vector int2vector* postgres.h
integer (int4) int4 or int32 postgres.h
real (float4) float4* postgres.h
double precision (float8) float8* postgres.h
interval Interval* utils/timestamp.h
lseg LSEG* utils/geo_decls.h
name Name postgres.h
oid Oid postgres.h
oidvector oidvector* postgres.h
path PATH* utils/geo_decls.h
point POINT* utils/geo_decls.h
regproc regproc postgres.h
reltime RelativeTime utils/nabstime.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* utils/timestamp.h
tinterval TimeInterval utils/nabstime.h
varchar VarChar* postgres.h
xid TransactionId postgres.h

¿©±â±îÁö ±âº»Çü¿¡ °üÇØ¼­ ÀÖÀ» ¼ö ÀÖ´Â ±¸Á¶ÀÇ ¸ðµÎ¸¦ ±â¼úÇßÀ¸¹Ç·Î, ½ÇÁ¦ÀÇ ÇÔ¼öÀÇ ¿¹¸¦ ¸î °³ °¡¸®Å³ ¼ö°¡ ÀÖ½À´Ï´Ù.

33.9.3. ¹öÀü 0 È£Ãâ ±Ô¾à

ÇöÀç´Â ºñÃßõÇÏÁö¸¸ ÀÌÇØÇϱ⠽±±â ¶§¹®¿¡, ÃÖÃÊ·Î "¿À·¡µÈ ½ºÅ¸ÀÏ"ÀÇ È£Ãâ ±Ô¾àÀ» ±â¼úÇÕ´Ï´Ù. ¹öÀü-0 ¹æ¹ý¿¡¼­´Â, CÇÔ¼öÀÇ ÀÎÀÚ¿Í °á°ú´Â, Åë»óÀÇ CÀÇ ¹æ¹ý°ú °°Àº Çü½Ä¿¡¼­ ½Ç½ÃÇÕ´Ï´Ù¸¸, »ó±âÀÇ ¼³¸í°ú °°ÀÌ, °¢ SQLÀÇ µ¥ÀÌÅÍÇüÀ» ³ªÅ¸³»´Â C¾ð¾î¸¦ »ç¿ë¿¡´Â ÁÖÀÇÇØ ÁÖ¼¼¿ä.

ÀÌÇÏ¿¡ ¸î °³ÀÇ ¿¹¸¦ ³ªÅ¸³À´Ï´Ù.

#include "postgres.h"
#include <string.h>

/* °ªÀεµ */
         
int
add_one(int arg)
{
    return arg + 1;
}

/* °íÁ¤ÀåÀÇ ÂüÁ¶ Àεµ */

float8 *
add_one_float8(float8 *arg)
{
    float8    *result = (float8 *) palloc(sizeof(float8));

    *result = *arg + 1.0;
       
    return result;
}

Point *
makepoint(Point *pointx, Point *pointy)
{
    Point     *new_point = (Point *) palloc(sizeof(Point));

    new_point->x = pointx->x;
    new_point->y = pointy->y;
       
    return new_point;
}

/* °¡º¯ ±æÀÌÀÇ ÂüÁ¶ Àεµ */

text *
copytext(text *t)
{
    /*
     * VARSIZE´Â ±¸Á¶ÀÇ ÃÑ »çÀÌÁ ¹ÙÀÌÆ®¼ö·Î ³ªÅ¸³½ °ÍÀÔ´Ï´Ù.
     */
    text *new_t = (text *) palloc(VARSIZE(t));
    VARATT_SIZEP(new_t) = VARSIZE(t);
    /*
     * VARDATA´Â ±¸Á¶ÀÇ µ¥ÀÌÅÍ ¿µ¿ª¿¡ÀÇ Æ÷ÀÎÅÍÀÔ´Ï´Ù.
     */
    memcpy((void *) VARDATA(new_t), /* destination */
           (void *) VARDATA(t),     /* source */
           VARSIZE(t) - VARHDRSZ);  /* how many bytes */
    return new_t;
}

text *
concat_text(text *arg1, text *arg2)
{
    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
    text *new_text = (text *) palloc(new_text_size);

    VARATT_SIZEP(new_text) = new_text_size;
    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
    return new_text;
}

À§ÀÇ Äڵ尡 funcs.c¶ó´Â ÆÄÀÏ¿¡ ÁغñµÇ¾î °øÀ¯ °´Ã¼·Î¼­ ÄÄÆÄÀÏÀÌ ³¡³­ »óÅÂÀ̸é, ÀÌÇÏ¿Í °°Àº ¸í·ÉÀ¸·Î PostgreSQLÀÇ ÇÔ¼ö¸¦ Á¤ÀÇÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù.

CREATE FUNCTION add_one(integer) RETURNS integer
     AS '
DIRECTORY
/funcs', 'add_one'
     LANGUAGE C STRICT;

-- "add_one"À̶ó°í ÇÏ´Â SQL ÇÔ¼ö¸íÀ» ¿À¹ö·ÎµåÇϰí ÀÖ´Â °Í¿¡ ÁÖÀÇ
CREATE FUNCTION add_one(double precision) RETURNS double precision
     AS '
DIRECTORY
/funcs', 'add_one_float8'
     LANGUAGE C STRICT;

CREATE FUNCTION makepoint(point, point) RETURNS point
     AS '
DIRECTORY
/funcs', 'makepoint'
     LANGUAGE C STRICT;
                         
CREATE FUNCTION copytext(text) RETURNS text
     AS '
DIRECTORY
/funcs', 'copytext'
     LANGUAGE C STRICT;

CREATE FUNCTION concat_text(text, text) RETURNS text
     AS '
DIRECTORY
/funcs', 'concat_text'
     LANGUAGE C STRICT;

¿©±â¼­, DIRECTORY ´Â °øÀ¯ ÆÄÀÏÀÇ µð·ºÅ丮 (¿¹¸¦ µé¸é, º»Àý·Î »ç¿ëÇÏ´Â ¿¹ÀÇ Äڵ尡 Æ÷ÇԵǴ PostgreSQLÆ©Å丮¾ó µð·ºÅ丮)¸¦ ³ªÅ¸³À´Ï´Ù (AS±¸Áß¿¡¼­´Â ´ÜÁö 'funcs'¸¦ »ç¿ëÇØ, ´ÙÀ½¿¡ DIRECTORY ¸¦ °Ë»ö °æ·Î¿¡ Ãß°¡ÇÏ´Â ÆíÀÌ º¸´Ù ÁÁÀº ¹æ¹ýÀÔ´Ï´Ù. ¾î´À °æ¿ì¿¡¼­µµ, ÀϹÝÀûÀ¸·Î . so³ª . sl°¡ »ç¿ëµÇ´Â, °øÀ¯ ¶óÀ̺귯¸®¿ëÀÇ ½Ã½ºÅÛ µ¶Æ¯ÇÑ È®ÀåÀÚ(extension)¸¦ »ý·« ÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù).

¿©±â¼­, ÇÔ¼ö¸¦ "¾ö¹Ð(strict)"ÇÏ°Ô ÁöÁ¤Çϰí ÀÖ´Â °Í¿¡ ÁÖ¸ñÇØ ÁÖ¼¼¿ä. À̰ÍÀº, ¸¸¾à ÀÔ·ÂµÈ °ªÀÌ NULL¿´À» °æ¿ì¿¡, ½Ã½ºÅÛÀÌ ÀÚµ¿ÀûÀ¸·Î µ¹¾Æ°¡ °á°úµµ NULLÀ̶ó°í °£ÁÖÇÏ´Â °ÍÀ» ÀǹÌÇÕ´Ï´Ù. À̰ÍÀ» ½Ç½ÃÇÏ´Â °Í¿¡ ÀÇÇØ, ÇÔ¼öÀÇ Äڵ忡 ÀԷ°ªÀÌ NULL°ªÀÎÁö üũ¸¦ ÇÒ Çʿ䰡 ¾ø¾îÁý´Ï´Ù. À̰ÍÀÌ ¾øÀ¸¸é, °¢ ÂüÁ¶ Àεµ ÀÎÀÚÀÇ NULL Æ÷ÀÎÅÍ¿¡ ´ëÇÑ Ã¼Å©¸¦ ½Ç½ÃÇÏ´Â µî, NULL°ªÀÇ ¸í½ÃÀûÀΠüũ¸¦ ½Ç½ÃÇÒ Çʿ䰡 ÀÖ¾î Áý´Ï´Ù. (°ªÀεµ ÀÎÀÚ¿¡ °üÇØ¼­, üũ¸¦ ½Ç½ÃÇÏ´Â ¹æ¹ýÀº Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù).

ÀÌ·¯ÇÑ È£Ãâ ±Ô¾àÀº ¿ëÀÌÇÕ´Ï´Ù¸¸, ÀÌ ¹æ¹ýÀº, À̽ļºÀÇ ¸é¿¡¼­ ±×´ÙÁö ¿ì¼öÇÏÁö ¾Ê½À´Ï´Ù. intÇüÀÇ °Íº¸´Ù ÀÛÀº µ¥ÀÌÅÍÇüÀ» ÀεµÇÏ´Â ºÎºÐ¿¡¼­ ¹®Á¦¸¦ ¶°¾È°í ÀÖ´Â ¾ÆÅ°ÅØÃĵµ Á¸ÀçÇÕ´Ï´Ù. ¶Ç, ÇÔ¼öÀÇ °á°ú·Î¼­ NULL¸¦ µ¹·ÁÁÖ´Â °£´ÜÇÑ ¹æ¹ýÀº ¾ø½À´Ï´Ù. °Ô´Ù°¡, ÀÎÀڷμ­ NULL¸¦ ó¸®ÇÏ´Â ¹æ¹ýÀ¸·Î¼­´Â, ÇÔ¼ö¸¦ ¾ö¹ÐÇÑ °ÍÀ¸·Î ÇÏ´Â ÀÌ¿Ü ¹æ¹ýÀº ¾ø½À´Ï´Ù. ´ÙÀ½¿¡ ¼³¸íÇÏ´Â Version-1 ±Ô¾à¿¡¼­´Â ÀÌ·¯ÇÑ ¹®Á¦°¡ ÇØ°áµÇ°í ÀÖ½À´Ï´Ù.

33.9.4. ¹öÀü 1 È£Ãâ ±Ô¾à

¹öÀü-1 È£Ã⠱Ծ࿡¼­´Â, ÀÎÀÚ¿Í °á°úÀÇ ÀεµÀÇ º¹À⼺À» ¾ø¾Ö±â À§Çؼ­ ¸ÅÅ©·Î¸¦ »ç¿ëÇϰí ÀÖ½À´Ï´Ù. ¹öÀü-1ÇÔ¼öÀÇ C¾ð¾î ¼±¾ðÀº ¹Ýµå½Ã ¾Æ·¡¿Í °°ÀÌ ½Ç½ÃÇÕ´Ï´Ù.

Datum funcname(PG_FUNCTION_ARGS)

¶ÇÇÑ, ¸ÅÅ©·Î È£Ãâ

PG_FUNCTION_INFO_V1(funcname);

´Â, °°Àº ¼Ò½º ÆÄÀÏ¿¡ ¾²¿©Á® ÀÖ¾î¾ß ÇÕ´Ï´Ù (ÀϹÝÀûÀ¸·Î´Â, ÇÔ¼öÀÇ ¹Ù·Î ¾Õ¿¡ ¾²¿©Áý´Ï´Ù). PostgreSQL¿¡¼­´Â ¸ðµç ³»ºÎ ÇÔ¼ö´Â ¹öÀü-1À̶ó°í ÀνÄÇϹǷÎ, ÀÌ ¸ÅÅ©·ÎÀÇ È£ÃâÀº internal¾ð¾î ÇÔ¼ö¿¡¼­´Â ÇÊ¿ä ¾ø½À´Ï´Ù. ±×·¯³ª, µ¿ÀûÀ¸·Î ·Îµå µÇ´Â ÇÔ¼ö¿¡¼­´Â ÇÊ¿äÇÕ´Ï´Ù.

¹öÀü-1ÇÔ¼ö¿¡¼­´Â, °¢°¢ÀÇ ¿­¸Å ÀÎÀÚ´Â, ÀÎÀÚÀÇ µ¥ÀÌÅÍÇü¿¡ ¸Â´Â PG_GETARG_ xxx ()¸ÅÅ©·Î¸¦ »ç¿ëÇØ ³ªµ· °á°ú´Â ¹Ýȯ°ªÀÇ ÇüÅ¿¡ ¸Â´Â PG_RETURN_ xxx ()¸ÅÅ©·Î¸¦ »ç¿ëÇØ µ¹·ÁÁÖ¾îÁý´Ï´Ù. PG_GETARG_ xxx ()´Â, ±× ÀÎÀڷμ­ ²¨³»´Â ÇÔ¼ö ÀÎÀÚÀÇ ¹øÈ£¸¦ ÃëÇÕ´Ï´Ù. PG_RETURN_ xxx ()´Â, ±× ÀÎÀڷμ­ ½ÇÁ¦·Î µ¹·ÁÁÖ´Â °ªÀ» ¹Þ½À´Ï´Ù.

»ó±â¿Í °°Àº ÇÔ¼ö¸¦ ¹öÀü-1 Çü½Ä¿¡ ±â¼úÇÑ °ÍÀ» ÀÌÇÏ¿¡ ³ªÅ¸³À´Ï´Ù.

#include "postgres.h"
#include <string.h>
#include "fmgr.h"

/* °ªÀεµ */

PG_FUNCTION_INFO_V1(add_one);
         
Datum
add_one(PG_FUNCTION_ARGS)
{
    int32   arg = PG_GETARG_INT32(0);

    PG_RETURN_INT32(arg + 1);
}

/* °íÁ¤ ±æÀÌÀÇ ÂüÁ¶ Àεµ */

PG_FUNCTION_INFO_V1(add_one_float8);

Datum
add_one_float8(PG_FUNCTION_ARGS)
{
    /* FLOAT8¿ëÀÇ ¸ÅÅ©·Î´Â ÂüÁ¶ Àεµ¶ó´Â ¼ºÁúÀ» ¼û±é´Ï´Ù */

    PG_RETURN_FLOAT8(arg + 1.0);
}

PG_FUNCTION_INFO_V1(makepoint);

Datum
makepoint(PG_FUNCTION_ARGS)
{
 
    /* ¿©±âÀÇ PointÇüÀÇ ÂüÁ¶ Àεµ¶ó´Â ¼ºÁúÀº ¼û°ÜÁö°í ÀÖÁö ¾Ê½À´Ï´Ù */
   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);
}

 
/* °¡º¯ ±æÀÌÀÇ ÂüÁ¶ Àεµ */

PG_FUNCTION_INFO_V1(copytext);

Datum
copytext(PG_FUNCTION_ARGS)
{
    text     *t = PG_GETARG_TEXT_P(0);
    /*
 
     * VARSIZE´Â ±¸Á¶ÀÇ ÃÑ »çÀÌÁ ¹ÙÀÌÆ®¼ö·Î ³ªÅ¸³½ °ÍÀÔ´Ï´Ù.
    */
    text     *new_t = (text *) palloc(VARSIZE(t));
    VARATT_SIZEP(new_t) = VARSIZE(t);
    /*
 
     * VARDATA´Â ±¸Á¶ÀÇ µ¥ÀÌÅÍ ¿µ¿ª¿¡ÀÇ Æ÷ÀÎÅÍÀÔ´Ï´Ù.
    */
    memcpy((void *) VARDATA(new_t), /* destination */
           (void *) VARDATA(t),     /* source */
           VARSIZE(t) - VARHDRSZ);  /* 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_P(0);
    text  *arg2 = PG_GETARG_TEXT_P(1);
    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
    text *new_text = (text *) palloc(new_text_size);

    VARATT_SIZEP(new_text) = new_text_size;
    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
    PG_RETURN_TEXT_P(new_text);
}

CREATE FUNCTION¸í·ÉÀº, ¹öÀü-0°ú °°Àº °ÍÀÔ´Ï´Ù.

¾ð¶æ º¸±â¿¡, ¹öÀü-1ÀÇ ÄÚµù ±Ô¾àÀº ¹«ÀǹÌÇÑ °ÍÀ¸·Î º¸ÀÏÁöµµ ¸ð¸¨´Ï´Ù. ±×·¯³ª, ¸ÅÅ©·Î°¡ ÇÊ¿ä¾ø´Â Á¤º¸¸¦ ÀºÆóÇϰí ÀÖÀ¸¹Ç·Î, ´Ù¼öÀÇ °³¼±À» Çϰí ÀÖ½À´Ï´Ù. ¿¹¸¦ µé¸é, add_one_float8ÀÇ Äڵ忡¼­´Â, float8°¡ ÂüÁ¶ ÀεµÀÎ °ÍÀ» ÀǽÄÇÒ Çʿ䰡 ¾ø¾îÁ³½À´Ï´Ù. ¶Ç ´Ù¸¥ ¿¹·Î¼­´Â, °¡º¯ ±æÀÌÇüÀÇ GETARG¸ÅÅ©·Î´Â "TOAST µÈ"°ª(¾ÐÃà, ¶Ç´Â Çà¿Ü)ÀÌ Ãë±ÞÇÏ´Â Çʿ伺À» ÀºÆó ÇÕ´Ï´Ù.

¹öÀü-1ÇÔ¼öÀÇ ÇϳªÀÇ Å« °³¼±Á¡Àº, NULLÀÇ ÀÔ·Â/°á°úÀÇ Ã³¸® ´É·ÂÀÔ´Ï´Ù. PG_ARGISNULL( n )¸ÅÅ©·Î¿¡ ÀÇÇØ ÇÔ¼ö´Â °¢ ÀÔ·ÂÀÌ NULLÀÎÁö ¾Æ´ÑÁö Å×½ºÆ®¸¦ ½Ç½ÃÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù (¹°·Ð À̰ÍÀº, "¾ö¹Ð"È÷ ¼±¾ðµÇ¾î ÀÖÁö ¾ÊÀº ÇÔ¼ö¿¡¼­¸¸ ÇÊ¿äÇÕ´Ï´Ù). PG_GETARG_ xxx ()¸ÅÅ©·Î¿¡¼­´Â, ÀÔ·ÂµÈ ÀÎÀÚ´Â ½ÃÀÛµÇ¾î °ªÀ» 0À¸·Î¼­ ¿­°ÅÇÒ ¼ö ÀÖ½À´Ï´Ù. ÀÎÀÚ°¡ NULL°¡ ¾Æ´Ñ °ÍÀ» È®ÀÎÇÒ ¶§±îÁö´Â, PG_GETARG_ xxx ()ÀÇ ½ÇÇàÀº »ï°¡ÇØ¾ß ÇÕ´Ï´Ù. °á°úÀûÀ¸·Î NULL¸¦ µ¹·ÁÁÖ´Â °æ¿ì´Â, PG_RETURN_NULL()¸¦ ½ÇÇàÇÕ´Ï´Ù. À̰ÍÀº, ¾ö¹ÐÇÑ ÇÔ¼ö¿Í ¾ö¹ÐÇÏÁö ¾ÊÀº ÇÔ¼öÀÇ ¾çÂÊ ¸ðµÎ·Î »ç¿ë °¡´ÉÇÕ´Ï´Ù.

»õ·Î¿î Çü½ÄÀÇ ÀÎÅÍÆäÀ̽º¿¡¼­´Â, ±× ¿ÜÀÇ ¿É¼ÇÀ¸·Î¼­ PG_GETARG_ xxx ()¸ÅÅ©·ÎÀÇ º¯ÇüÀ» 2°³ Á¦°øÇϰí ÀÖ½À´Ï´Ù. ù¹øÂ° PG_GETARG_ xxx _COPY()¿¡ ÀÇÇØ, ¾ÈÀüÇÏ°Ô ±âÀÔÇÒ ¼ö°¡ ÀÖ´Â ÁöÁ¤ ÀÎÀÚÀÇ º¹»ç°¡ È®½ÇÈ÷ µ¹¾Æ¿É´Ï´Ù (Åë»óÀÇ ¸ÅÅ©·Î´Â, ¹°¸®ÀûÀ¸·Î Å×ÀÌºí¿¡ ÀúÀåµÇ°í ÀÖ´Â °ª¿¡ÀÇ Æ÷ÀÎÅ͸¦ µ¹·ÁÁÖ´Â ÀÏÀÌ ÀÖÀ¸¹Ç·Î, ±âÀÔµÇÁö ¾Ê½À´Ï´Ù. PG_GETARG_ xxx _COPY()¸ÅÅ©·Î¸¦ »ç¿ëÇÏ´Â °ÍÀ¸·Î ¾È½ÉÇØ °á°ú¿¡ ±âÀÔÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù). µÎ¹øÂ° º¯ÇüÀº, ÀÎÀÚ¸¦ 3°³ ÃëÇÏ´Â PG_GETARG_ xxx _SLICE()¸ÅÅ©·Î·ÎºÎÅÍ µË´Ï´Ù. ù¹øÂ°´Â ÇÔ¼öÀÇ ÀÎÀÚÀÇ ¼ö(»ó±â´ë·Î)ÀÔ´Ï´Ù. µÎ¹øÂ°¿Í ¼¼¹øÂ°´Â, ¿ÀÇÁ¼Â(offset)°ú µ¹·ÁÁÖ¾îÁö´Â ¼¼±×¸ÕÆ®(segment)ÀÇ ±æÀÌÀÔ´Ï´Ù. ¿ÀÇÁ¼Â(offset)Àº Á¦·Î·ÎºÎÅÍ ½ÃÀ۵ǰí, ºÎÀÇ ±æÀÌ´Â ³ª¸ÓÁöÀÇ °ªÀ» µ¹·ÁÁÖ´Â °ÍÀ» ¿ä±¸ÇÕ´Ï´Ù. ÀÌ·¯ÇÑ ¸ÅÅ©·Î¸¦ »ç¿ëÇϸé, ½ºÅ丮ÁöÀÇ ÇüŰ¡ "external"(¿ÜºÎ)ÀÎ Å« °ªÀÇ ÀϺο¡ Á¢±Ù ÇÒ ¶§¿¡ ¸Å¿ì È¿°úÀûÀÔ´Ï´Ù (¿­ÀÇ ½ºÅ丮ÁöÀÇ ÇüÅ´ ALTER TABLE tablename ALTER COLUMN colname SET STORAGE storagetype ¸¦ »ç¿ëÇØ ÁöÁ¤ÇÒ ¼ö ÀÖ½À´Ï´Ù. ½ºÅ丮ÁöÀÇ ÇüÅ´Â, plain, external, extended, ¶Ç´Â main Áß¿¡ ÀÖ½À´Ï´Ù).

¸¶Áö¸·À¸·Î, ¹öÀü-1ÇÔ¼ö È£Ã⠱Ծ࿡¼­´Â, °á°ú ÁýÇÕ(Section 33.9.10)À» µ¹·ÁÁÖ´Â °Í, ¹× Æ®¸®°Å ÇÔ¼ö(Chapter 34)¿Í ¼ö¼ÓÇü ¾ð¾îÀÇ È£Ãâ Çڵ鷯(Chapter 47)¸¦ ±¸ÇöÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ¶Ç, ¹öÀü-1 ÄÚµå´Â, Ç¥ÁØ CÀÇ ÇÔ¼ö È£Ãâ ÇÁ·ÎÅäÄÝÀÇ Á¦¾àÀ» Áö۱⠶§¹®¿¡, ¹öÀü-0º¸´Ù À̽ļºÀÌ ÀÖ½À´Ï´Ù. ÀÚ¼¼ÇÑ °ÍÀº ¼Ò½º ¹èÆ÷¹° ³»ÀÇ src/backend/utils/fmgr/README¸¦ ÂüÁ¶ÇØ ÁÖ¼¼¿ä.

33.9.5. ÄÚµåÀÇ ÀÛ¼º

º¸´Ù ¹ßÀüµÈ È­Á¦¿¡ µé¾î°¡±â Àü¿¡, PostgreSQL C¾ð¾î ÇÔ¼öÀÇ ÄÚµù¿¡ ´ëÇÑ ±ÔÄ¢À» ¸î °³ ¼³¸íÇÕ´Ï´Ù. C¾ð¾î ÀÌ¿ÜÀÇ ¾ð¾î·Î ±â¼úÇÑ ÇÔ¼ö¸¦ PostgreSQL¿¡ ³»ÀåÇÏ´Â °ÍÀº °¡´ÉÇÕ´Ï´Ù¸¸, ¿¹¸¦ µé¸é C++, FORTRAN³ª Pascal¶ó°í ÇÏ´Â ¾ð¾î´Â C¾ð¾î¿Í °°Àº È£Ãâ°ú ±Ô¾à¿¡ µû¸£Áö ¾ÊÀ¸¹Ç·Î, ¸¹Àº °æ¿ì, (°¡´ÉÇß´Ù°í ÇØµµ)°ï¶õÇÕ´Ï´Ù. ±×°ÍÀº Áï, ´Ù¸¥ ¾ð¾î¿¡¼­´Â °°Àº ¹æ¹ýÀ¸·Î ÇÔ¼ö¿¡ ÀÎÀÚ¸¦ °Ç³×Áְųª ÇÔ¼ö·ÎºÎÅÍ °á°ú¸¦ µ¹·ÁÁÖ´Â °ÍÀ» ½Ç½ÃÇÏÁö ¾Ê´Â´Ù´Â °ÍÀÔ´Ï´Ù. ÀÌ ¶§¹®¿¡, C¾ð¾î ÇÔ¼ö´Â ½ÇÁ¦·Î C¾ð¾î·Î ¾²¿©Á® ÀÖ´Â °ÍÀ¸·Î °¡Á¤ÇÕ´Ï´Ù.

CÇÔ¼öÀÇ ÀÛ¼º°ú ±¸ÃàÀÇ ±âº» ±ÔÄ¢À» ÀÌÇÏ¿¡ ³ªÅ¸³À´Ï´Ù.

33.9.6. µ¿ÀûÀ¸·Î ·Îµå µÇ´Â ÇÔ¼öÀÇ ÄÄÆÄÀϰú ¸µÅ©

C·Î ÀÛ¼ºµÈ PostgreSQLÀÇ È®Àå ÇÔ¼ö¸¦ »ç¿ëÇϱâ À§Çؼ­´Â ¼­¹ö¿¡ ÀÇÇØ µ¿ÀûÀ¸·Î ·ÎµåµÉ ¼ö ÀÖµµ·Ï Ưº°ÇÑ ¹æ¹ýÀ» ÅëÇØ ÄÄÆÄÀϰú ¸µÅ©¸¦ ÇØ¾ßÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù. Á¤È®ÇϰԴ°øÀ¯ ¶óÀ̺귯¸®¸¦ ¸¸µé Çʿ䰡 ÀÖ½À´Ï´Ù.

Ãß°¡ÀûÀÎ Á¤º¸´Â operating systemÀÇ ¹®¼­, ƯÈ÷ CÄÄÆÄÀÏ·¯, cc ±×¸®°í ¸µÅ© ¿¡µðÅÍ, ldÀÇ ¸Þ´º¾ó ÆäÀÌÁö¸¦ ÂüÁ¶ÇØ Áֽʽÿä. ¶ÇÇÑ, PostgreSQLÀÇ ¿ø½Ã ÄÚµå´Â contribµð·ºÅ丮 ³»¿¡¼­ ½Ç·Ê¸¦ Æ÷ÇÔÇϰí ÀÖ½À´Ï´Ù. ±×·¯³ª ÀÌ·¯ÇÑ ¿¹Á¦¿¡ ÀÇÁ¸À» ÇÏ°Ô µÇ¸é PostgreSQL ¿ø½ÃÄÚµåÀÇ À¯È¿¼º¿¡ ÀÇÁ¸ÇÑ ¸ðµâÀÌ ¸¸µéÁö°Ô µË´Ï´Ù.

°øÀ¯¶óÀ̺귯¸®¸¦ »ý¼ºÇÏ´Â °ÍÀº ÀϹÝÀûÀ¸·Î ½ÇÇà ÇÁ·Î±×·¥ÀÇ ¸µÅ©¿Í À¯»çÇÕ´Ï´Ù. ¿ì¼± ¿ø½Ã ÆÄÀÏÀÌ ¿ÀºêÁ§Æ® ÆÄÀÏ¿¡ ÄÄÆÄÀÏ µÈ ÈÄ ¿ÀºêÁ§Æ® ÆÄÀÏ °£ÀÇ ¸µÅ©°¡ ÀÌ·ç¾îÁý´Ï´Ù. ÀÌ·¯ÇÑ ¿ÀºêÁ§Æ® ÆÄÀÏÀº À§Ä¡¿¡ µ¶¸³ÀûÀÎ ÄÚµå(PIC)·Î¼­ ¸¸µé¾îÁ®¾ß ÇÕ´Ï´Ù. ¶õ °³³äÀûÀ¸·Î´Â ½ÇÇàÇÁ·Î±×·¥¿¡ ÀÇÇØ ·ÎµåµÇ¾îÁú ¶§ ¸Þ¸ð¸® »óÀÇ ÀÓÀÇÀÇ Àå¼Ò¿¡ À§Ä¡µÇ¾îÁú ¼ö ÀÖ´Ù´Â °ÍÀ» ÀǹÌÇÕ´Ï´Ù. (½ÇÇà ÇÁ·Î±×·¥¿ëÀ¸·Î ¸¸µé¾îÁø ¿ÀºêÁ§Æ® ÆÄÀÏÀº ÀÌ·¯ÇÑ ¹æ¹ýÀ¸·Î ÄÄÆÄÀϵÇÁö ¾Ê½À´Ï´Ù.) °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸µÅ©ÇÏ´Â ¸í·É¹®Àº ½ÇÇà ÇÁ·Î±×·¥ÀÇ ¸µÅ©¿Í ±¸º°µÇ±â ¿ìÇÑ Æ¯º°ÇÑ Ç÷¡±×¸¦ °¡Áý´Ï´Ù. (À̷лóÀ¸·Î ±×·¯Çϸç, ´Ù¸¥ ½Ã½ºÅÛ¿¡¼­ ½ÇÁ¦ Á» ´õ Ãß¾ÇÇÏ°Ô º¸¿©Áý´Ï´Ù.)

´ÙÀ½ÀÇ ¿¹¸¦ ÅëÇØ file foo.c ¾È¿¡ ¿ø½Ã Äڵ尡 ÀÖ´Ù°í °¡Á¤Çϰí, foo.so °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸¸µé °ÍÀÔ´Ï´Ù. Áß°£ÀÇ ¿ÀºêÁ§Æ® ÆÄÀÏÀº Ưº°ÇÑ ¾ð±ÞÀÌ ¾ø´Â ÇÑ foo.oÀ¸·Î ºÒ¸± °ÍÀÔ´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®´Â ÇÑ °³ ÀÌ»óÀÇ ¿ÀºêÁ§Æ® ÆÄÀÏÀ» °¡Áú ¼ö ÀÖÀ¸³ª, ¿©±â¿¡¼­´Â ÇÑ °¡Áö¸¸ »ç¿ëÇÏ¿´½À´Ï´Ù.

BSD/OS

PIC¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â -fpicÀÔ´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®¸¦ »ý¼ºÇÏ´Â ¸µÅ© Ç÷¡±×´Â-sharedÀÔ´Ï´Ù.

gcc -fpic -c foo.c
ld -shared -o foo.so foo.o

À§´Â ¹öÀü 4.0¿¡¼­ Àû¿ëµË´Ï´Ù.

FreeBSD

PIC¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â-fpicÀÔ´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸¸µå´Â ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â-sharedÀÔ´Ï´Ù.

gcc -fpic -c foo.c
gcc -shared -o foo.so foo.o

À§´Â FreeBSDÀÇ ¹öÀü 3.0¿¡¼­ Àû¿ëµË´Ï´Ù.

HP-UX

PIC¸¦ ¸¸µé±â À§ÇÑ ½Ã½ºÅÛ ÄÄÆÄÀÏ·¯ÀÇ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â+zÀÔ´Ï´Ù. GCC¸¦ »ç¿ëÇÏ´Â °æ¿ì´Â-fpicÀÔ´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®¸¦ À§ÇÑ ¸µÅ© Ç÷¡±×´Â-bÀÔ´Ï´Ù. µû¶ó¼­, ÀÌÇÏ¿Í °°ÀÌ µË´Ï´Ù.

cc +z -c foo.c

or

gcc -fpic -c foo.c

±×¸®°í

ld -b -o foo.sl foo.o

HP-UX´Â ´ëºÎºÐÀÇ ´Ù¸¥ ½Ã½ºÅÛ°ú ´Þ¸® °øÀ¯ ¶óÀ̺귯¸®¿¡ . sl¶ó°í ÇÏ´Â È®ÀåÀÚ(extension)¸¦ »ç¿ëÇÕ´Ï´Ù.

IRIX

PIC´Â µðÆúÆ®·Î Ưº°ÇÑ ÄÄÆÄÀÏ·¯ ¿É¼ÇÀº ÇÊ¿äÇÏÁö ¾Ê½À´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸¸µé±â À§ÇÑ ¸µÅ© ¿É¼ÇÀº-sharedÀÔ´Ï´Ù.

cc -c foo.c
ld -shared -o foo.so foo.o

Linux

PIC¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â-fpicÀÔ´Ï´Ù. ¸î°¡Áö »óȲ¿¡¼­ ¸î¸îÀÇ Ç÷§ÆûÀº -fpic°¡ µ¿ÀÛÇÏÁö ¾ÊÀ» °æ¿ì, -fPIC¸¦ »ç¿ëÇØ¾ß¸¸ ÇÕ´Ï´Ù. º¸´Ù ¸¹Àº Á¤º¸¸¦ ¿øÇϽô ºÐÀº GCCÀÇ ¸Þ´º¾óÀ» ÂüÁ¶ÇØ Áֽʽÿä. °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â-sharedÀÔ´Ï´Ù. ¿ÏÀüÇÑ ¿¹´Â ´ÙÀ½°ú °°½À´Ï´Ù.

cc -fpic -c foo.c
cc -shared -o foo.so foo.o

MacOS X

¾Æ·¡ÀÇ ¿¹´Â °³¹ßÀÚ¿ë ÅøÀÌ ¼³Ä¡µÈ °ÍÀ» ÀüÁ¦·Î Çϰí ÀÖ½À´Ï´Ù.

cc -c foo.c 
cc -bundle -flat_namespace -undefined suppress -o foo.so foo.o

NetBSD

PIC¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â-fpicÀÔ´Ï´Ù. ELF½Ã½ºÅÛ¿¡¼­´Â ÄÄÆÄÀÏ·¯°¡ -sharedÇ÷¡±×¸¦ »ç¿ëÇØ °øÀ¯ ¶óÀ̺귯¸®¸¦ ¸µÅ©ÇÕ´Ï´Ù. º¸´Ù ¿À·¡µÈ non-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·Î »ç¿ëÇÕ´Ï´Ù. ´ë½Å GCCÀÇ °æ¿ì¿¡´Â -shared¿É¼ÇÀ» »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù.

cc -KPIC -c foo.c
cc -G -o foo.so foo.o

¶Ç´Â

gcc -fpic -c foo.c
gcc -G -o foo.so foo.o

Tru64 UNIX

PIC´Â µðÆúÆ®·Î ÄÄÆÄÀÏ ¸í·É¹®Àº ÀϹÝÀûÀÎ °ÍÀÔ´Ï´Ù. ¸µÅ©¸¦ Çϱâ À§Çؼ­´Â Ưº°ÇÑ ¿É¼ÇÀ» °¡Áø ld°¡ »ç¿ëµË´Ï´Ù.

cc -c foo.c
ld -shared -expect_unresolved '*' -o foo.so foo.o

½Ã½ºÅÛÀÇ ÄÄÆÄÀÏ·¯¸¦ ´ë½ÅÇØ GCC¸¦ »ç¿ëÇÏ´Â °æ¿ìµµ °°Àº ¼ø¼­ÀÔ´Ï´Ù. Ưº°ÇÑ ¿É¼ÇÀº ÇÊ¿äÇÏÁö ¾Ê½À´Ï´Ù.

UnixWare

PIC¸¦ ¸¸µé±â À§ÇÑ ÄÄÆÄÀÏ·¯ Ç÷¡±×´Â SCO ÄÄÆÄÀÏ·¯¿¡¼­´Â-KPIC°¡ »ç¿ëµÇ¸ç, GCC¿¡¼­´Â -fpicÀÔ´Ï´Ù. °øÀ¯ ¶óÀ̺귯¸®ÀÇ ¸µÅ©Çϱâ À§Çؼ­ SCO ÄÄÆÄÀÏ·¯¿¡¼­´Â ÄÄÆÄÀÏ·¯ ¿É¼ÇÀ¸·Î -GÀÌ »ç¿ëµÇ°í, GCC¿¡¼­´Â-shared°¡ »ç¿ëµË´Ï´Ù.

cc -K PIC -c foo.c
cc -G -o foo.so foo.o

¶Ç´Â

gcc -fpic -c foo.c
gcc -shared -o foo.so foo.o

Tip: À§ÀÇ ³»¿ëÀÌ º¹ÀâÇÏ¿© ÀÌÇØ°¡ ¾î·Á¿ï °æ¿ì, µ¿ÀÏÇÑ ÀÎÅÍÆäÀ̽º¸¦ ÅëÇØ Ç÷¡ÆûÀÇ Â÷À̸¦ °¨ÃçÁÖ´Â GNU Libtool ÀÇ »ç¿ëÀ» °í·ÁÇØ º¸½Ê½Ã¿ä.

¿Ï¼ºµÈ °øÀ¯ ¶óÀ̺귯¸® ÆÄÀÏÀºPostgreSQL¿¡ ·ÎµåÇÒ ¼ö ÀÖ½À´Ï´Ù. CREATE FUNCTION ¸í·É¹®À¸·Î ÆÄÀϸíÀ» ÁöÁ¤ÇÒ ¶§¿¡´Â, Áß°£ ¿ÀºêÁ§Æ® ÆÄÀÏÀÌ ¾Æ´Ñ °øÀ¯ ¶óÀ̺귯¸® ÆÄÀϸíÀÇ À̸§À» Áֽʽÿä. ½Ã½ºÅÛÀÇ Ç¥ÁØ °øÀ¯ ¶óÀ̺귯¸®¿ëÀÇ È®ÀåÀÚ(extension)(Åë»ó. soȤÀº. sl)´Â CREATE FUNCTIONÀ¸·Î »ý·«ÀÌ °¡´ÉÇϸç, ÀϹÝÀûÀ¸·Î À̽ļºÀ» °¡Àå ³ôÀ̱â À§ÇÑ ¹æ¹ýÀ¸·Î »ý·«µÇ¾îÁý´Ï´Ù.

¼­¹ö°¡ ¶óÀ̺귯¸® ÆÄÀÏÀ» ¾îµð¿¡ ã¾Æ³¾±î¿¡ °üÇØ Section 33.9.1À» ´Ù½Ã ÂüÁ¶ÇÏ¿© Áֽʽÿä.

33.9.7. È®Àå ±¸Ãà ±â¹Ý

PostgreSQLÈ®Àå ¸ðµâÀÇ ¹èÆ÷¸¦ ¿¹Á¤Çϰí ÀÖ´Â °æ¿ì, ±¸Ãà ½Ã½ºÅÛÀ» ÀÌ½Ä °¡´ÉÇÏ°Ô Çϱâ À§ÇÑ ¼³Á¤Àº ²Ï °ï¶õÇÕ´Ï´Ù. ±× ¶§¹®¿¡, PostgreSQLÀÇ ¼³Ä¡¿¡¼­´Â, ´Ü¼øÇÑ È®Àå ¸ðµâÀ» ¼³Ä¡°¡ ³¡³­ ¼­¹ö¿¡ °£´ÜÇÏ°Ô ±¸ÃàÇÒ ¼ö ÀÖµµ·Ï PGXS¶ó´Â È®Àå¿ëÀÇ ±¸Ãà ±â¹ÝÀ» Á¦°øÇϰí ÀÖ½À´Ï´Ù. ÀÌ ±â¹ÝÀº, PostgreSQL¿Í ±³È¯ÇÏ´Â ¸ðµç ¼ÒÇÁÆ®¿þ¾î¸¦ ±¸ÃàÇϱâ À§Çؼ­ »ç¿ëÇÒ ¼ö ÀÖ´Â °Í °°Àº Á¾ÇÕÀûÀÎ ±¸Ãà ½Ã½ºÅÛ Ã¼Á¦¸¦ ¸ñÀûÀ¸·Î ÇÑ °ÍÀº ¾Æ´Ñ °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä. À̰ÍÀº ´ÜÁö ´Ü¼øÇÑ ¼­¹ö È®Àå ¸ðµâ·Î °øÅëµÇ´Â ±¸Ãà ¼ø¼­¸¦ ÀÚµ¿È­ÇÏ´Â °ÍÀÔ´Ï´Ù. Á» ´õ º¹ÀâÇÑ ÆÐŰÁö¿¡¼­´Â, µ¶ÀÚÀûÀ¸·Î ±¸Ãà ½Ã½ºÅÛÀ» ÀÛ¼ºÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù.

µ¶ÀÚÀûÀÎ È®Àå ¸ðµâ¿ëÀ¸·Î ÀÌ ±â¹ÝÀ» »ç¿ëÇÏ·Á¸é, °£´ÜÇÑ Makefile¸¦ ÀÛ¼ºÇÏÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. ÀÌ Makefile·Î, ¸î °³ÀÇ º¯¼ö¸¦ ¼³Á¤ÇØ, ¸¶Áö¸·¿¡ PGXSÀüüÀÇ Makefile¸¦ Æ÷ÇÔ½ÃÄѾßÇÕ´Ï´Ù. ¿©±â¿¡¼­´Â, isbn_issn¶ó´Â À̸§ÀÇ È®Àå ¸ðµâÀ» ±¸ÃàÇϱâ À§ÇÑ ¿¹¸¦ ³ªÅ¸³À´Ï´Ù. ÀÌ ¸ðµâÀº °øÀ¯ ¶óÀ̺귯¸®, SQL ½ºÅ©¸³Æ®, ¹× ¹®¼­¿ëÀÇ ÅØ½ºÆ® ÆÄÀϷκÎÅÍ ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù.

MODULES = isbn_issn
DATA_built = isbn_issn.sql
DOCS = README.isbn_issn

PGXS := $(shell pg_config --pgxs)
include $(PGXS)

¸¶Áö¸· 3ÇàÀº Ç×»ó °°À» °ÍÀÔ´Ï´Ù. ±× Àü¿¡, º¯¼öÀÇ ´ëÀÔÀ̳ª µ¶ÀÚÀûÀÎ make±ÔÄ¢ÀÇ Ãß°¡¸¦ ½Ç½ÃÇÕ´Ï´Ù.

ÀÌÇÏÀÇ º¯¼ö¸¦ ¼³Á¤ÇÒ ¼ö ÀÖ½À´Ï´Ù.

MODULES

°°Àº °èÅëÀÇ ¼Ò½º ÆÄÀϷκÎÅÍ ±¸ÃàµÇ´Â °øÀ¯ °´Ã¼ÀÇ ¸®½ºÆ®ÀÔ´Ï´Ù (ÀÌ ¸®½ºÆ®¿¡´Â È®ÀåÀÚ(extension)¸¦ Æ÷ÇÔÇÏÁö ¸»¾Æ ÁÖ¼¼¿ä).

DATA

prefix /share/contrib¿¡ ¼³Ä¡µÇ´Â ¿©·¯°¡Áö ÆÄÀÏÀÔ´Ï´Ù.

DATA_built

ÃÖÃÊ·Î ±¸ÃàµÇÁö ¾ÊÀ¸¸é ¾È µÇ´Â prefix /share/contrib¿¡ ¼³Ä¡µÇ´Â ¿©·¯°¡Áö ÆÄÀÏÀÔ´Ï´Ù.

DOCS

prefix /doc/contrib¿¡ ¼³Ä¡µÇ´Â ¿©·¯°¡Áö ÆÄÀÏÀÔ´Ï´Ù.

SCRIPTS

prefix /bin¿¡ ¼³Ä¡ µÇ´Â(¹ÙÀ̳ʸ®°¡ ¾Æ´Ñ) ½ºÅ©¸³Æ® ÆÄÀÏÀÔ´Ï´Ù.

SCRIPTS_built

ÃÖÃÊ·Î ±¸ÃàµÇÁö ¾ÊÀ¸¸é ¾È µÇ´Â, prefix /bin¿¡ ¼³Ä¡µÇ´Â(¹ÙÀ̳ʸ®°¡ ¾Æ´Ñ) ½ºÅ©¸³Æ® ÆÄÀÏÀÔ´Ï´Ù.

REGRESS

¸®±×·¿¼ÇÅ×½ºÆ®ÄÉÀ̽ºÀÇ(È®ÀåÀÚ(extension) ¾øÀ½ÀÇ) ¸®½ºÆ®ÀÔ´Ï´Ù. Èļú ÇÕ´Ï´Ù.

ȤÀº, ÀÌÇÏÀÇ 2°³ °¡¿îµ¥, ´ëºÎºÐ 1°³ÀÔ´Ï´Ù.

PROGRAM

(OBJSÀÇ °´Ã¼ ÆÄÀÏÀÇ ¸®½ºÆ®·ÎºÎÅÍ) ±¸ÃàµÇ´Â ¹ÙÀ̳ʸ® ÇÁ·Î±×·¥ÀÔ´Ï´Ù.

MODULE_big

(OBJSÀÇ °´Ã¼ ÆÄÀÏÀÇ ¸®½ºÆ®·ÎºÎÅÍ) ±¸ÃàµÇ´Â °øÀ¯ °´Ã¼ÀÔ´Ï´Ù.

ÀÌÇÏÀÇ º¯¼öµµ ¼³Á¤ÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù.

EXTRA_CLEAN

make clean·Î »èÁ¦µÇ´Â ºÒÇÊ¿äÇÑ ÆÄÀÏÀÔ´Ï´Ù.

PG_CPPFLAGS

À̰ÍÀº CPPFLAGS¿¡ Ãß°¡µË´Ï´Ù.

PG_LIBS

À̰ÍÀº PROGRAMÀÇ ¸µÅ©Çà¿¡ Ãß°¡µË´Ï´Ù.

SHLIB_LINK

À̰ÍÀº MODULE_bigÀÇ ¸µÅ©Çà¿¡ Ãß°¡µË´Ï´Ù.

ÀÌ Makefile¸¦ È®Àå ¸ðµâÀ» ÀúÀåÇÏ´Â µð·ºÅ丮¿¡ Makefile·Î¼­ º¸Á¸ÇØ ÁÖ¼¼¿ä. ±× ÈÄ, make·Î µ¶ÀÚ ¸ðµâÀÇ ÄÄÆÄÀÏÀ», make install·Î µ¶ÀÚ ¸ðµâÀÇ ¼³Ä¡¸¦ ½Ç½ÃÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. µðÆúÆ®·Î È®Àå ¸ðµâÀº, °Ë»ö °æ·Î³»¿¡¼­ ÃÖÃÊ·Î ¹ß°ßµÇ´Â pg_config¸í·É¿¡ ´ëÀÀÇÏ´Â PostgreSQL¼³Ä¡ Àü¿ëÀ¸·Î ÄÄÆÄÀÏ µÇ¾î ¼³Ä¡µË´Ï´Ù. Makefile³» ¶Ç´Â makeÀÇ ¸í·É ¶óÀλ󿡼­ PG_CONFIG¸¦ ´Ù¸¥ ¼³Ä¡ÀÇ pg_configÇÁ·Î±×·¥À» Áö½ÃÇϵµ·Ï º¯°æÇÏ´Â °ÍÀ¸·Î ´Ù¸¥ ¼³Ä¡¸¦ »ç¿ëÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù.

PostgreSQL ÁÖ¼­¹ö·Î »ç¿ëµÇ´Â make installcheck ¸ØÃá ±¸ °°ÀÌ REGRESSº¯¼ö³»¿¡ ¿­°ÅµÈ ½ºÅ©¸³Æ®°¡ µ¶ÀÚÀûÀÎ ¸ðµâÀÇ ¸®±×·¿¼ÇÅ×½ºÆ®¿ëÀ¸·Î »ç¿ëµË´Ï´Ù. À̰ÍÀÌ µ¿ÀÛÇϱâ À§Çؼ­´Â, µ¶ÀÚ È®ÀåÀÇ µð·ºÅ丮³»¿¡ sql/¶ó´Â ¸íĪÀÇ µð·ºÅ丮¸¦ ÁغñÇØ, ±× Áß¿¡ ½ÇÇà½ÃŰ°í ½ÍÀº ½ÃÇè ±×·ì °¢°¢ 1°³ÀÇ ÆÄÀÏÀ» ÀúÀåÇØ¾ß ÇÕ´Ï´Ù. ÀÌ ÆÄÀÏÀÇ È®ÀåÀÚ(extension)´Â . sql°¡ ¾Æ´Ï¸é ¾ÈµË´Ï´Ù. ¶Ç, makefile ÆÄÀϳ»ÀÇ REGRESS¸®½ºÆ®¿¡´Â ÀÌ È®ÀåÀÚ(extension)¸¦ Æ÷ÇÔÇØ¼­´Â ¾ÈµË´Ï´Ù. °¢°¢ÀÇ ½ÃÇè¿¡ °üÇØ¼­, expected/¶ó´Â ¸íĪÀÇ µð·ºÅ丮¿¡, . out¶ó´Â È®ÀåÀÚ(extension)·Î »óÁ¤ °á°ú¸¦ ÆÄÀϷμ­ ÀúÀåÇÕ´Ï´Ù. ½ÃÇèÀº make installcheck¿¡ ÀÇÇØ ½ÇÇàµÇ¾î ±× °á°ú´Â »óÁ¤Ä¡ ÆÄÀÏÀ̶ó°í ºñ±³µË´Ï´Ù. Â÷ÀÌÁ¡Àº diff -cÀÇ ¼­½Ä¿¡¼­ regression.diffs¶ó°í ÇÏ´Â ÆÄÀÏ¿¡ ½á³»Áý´Ï´Ù. »óÁ¤Ä¡ ÆÄÀÏÀÌ Á¸ÀçÇÏÁö ¾Ê´Â ½ÃÇèÀ» ½ÇÇàÇϸé "Àå¾Ö"·Î¼­ º¸°íµÇ±â ¶§¹®¿¡, »óÁ¤Ä¡ ÆÄÀÏÀÌ ¸ðµÎ Á¸ÀçÇÏ´ÂÁö È®ÀÎÇØ ÁÖ¼¼¿ä.

Tip: »óÁ¤Ä¡ ÆÄÀÏÀÇ °¡Àå °£´ÜÇÑ ÀÛ¼º ¹æ¹ýÀº ºó ÆÄÀÏÀ» ÀÛ¼ºÇØ, ½ÃÇèÀ» ½ÇÇàÇÑ ÈÄÀÇ °á°ú ÆÄÀÏ(results/µð·ºÅ丮¿¡ ÀÖ½À´Ï´Ù.)À», ±×°ÍÀÌ Á¤¸»·Î ½ÃÇè °á°úÀûÀ¸·Î ¿Ã¹Ù¸¥ °ÍÀÎÁö ÁÖÀÇ ±í°Ô °Ë»çÇÑ ÈÄ¿¡ expected/¿¡ º¹»çÇÏ´Â °ÍÀÔ´Ï´Ù.

33.9.8. º¹ÇÕÇü ÀÎÀÚ

º¹ÇÕÇü¿¡¼­´Â CÀÇ ±¸Á¶¿Í °°Àº °íÁ¤ÀÇ ·¹À̾ƿôÀÌ ¾ø½À´Ï´Ù. º¹ÇÕÇüÀÇ ÀνºÅϽº´Â NULL Çʵ带 °¡Áú ¼ö°¡ ÀÖ½À´Ï´Ù. °Ô´Ù°¡ º¹ÇÕÇüÀ¸·Î °è½Â °èÃþÀÇ ÀϺÎÀÎ °ÍÀº, °°Àº °è½Â °èÃþÀÇ ´Ù¸¥ ¸â¹ö¿Í´Â ´Ù¸¥ Çʵ带 °¡Áú ¼öµµ ÀÖ½À´Ï´Ù. ±× ¶§¹®¿¡, PostgreSQL´Â C¾ð¾î·ÎºÎÅÍ º¹ÇÕÇüÀÇ Çʵ忡 Á¢±ÙÇϱâ À§ÇÑ ÇÔ¼ö ÀÎÅÍÆäÀ̽º¸¦ Á¦°øÇÕ´Ï´Ù.

ÀÌÇÏ¿Í °°ÀÌ Äõ¸®¿¡ ´ë´äÇÏ´Â ÇÔ¼ö¸¦ ¾²·Á°í ÇÑ´Ù°í °¡Á¤ÇÕ´Ï´Ù.

SELECT name, c_overpaid(emp, 1500) AS overpaid
    FROM emp
    WHERE name = 'Bill' OR name = 'Sam';

¹öÀü-0 È£Ãâ ±Ô¾àÀ» »ç¿ëÇϸé, c_overpaid´Â ÀÌÇÏ¿Í °°ÀÌ Á¤ÀÇÇÒ ¼ö ÀÖ½À´Ï´Ù.

#include "postgres.h"
#include "executor/executor.h"  /* GetAttributeByName() ¿ë */

bool
c_overpaid(HeapTupleHeader t, /* empÀÇ ÇöÀçÀÇ Çà */
           int32 limit)
{
    bool isnull;
    int32 salary;

    salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
    if (isnull)
        return false;
    return salary > limit;
}

¹öÀü-1À¸·Î ÀÛ¼ºÇϸé, À§ÀÇ ÇÔ¼ö´Â ÀÌÇÏ¿Í °°ÀÌ µË´Ï´Ù.

#include "postgres.h"
#include "executor/executor.h"  /* GetAttributeByName() ¿ë */

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);
    /* ÀÌ ¿Ü, salary°¡ NULLÀÇ °æ¿ì¿¡´Â PG_RETURN_NULL()¸¦ ½Ç½ÃÇÏ´Â °ÍÀÌ ÁÁÀ» °ÍÀÔ´Ï´Ù */

    PG_RETURN_BOOL(DatumGetInt32(salary) > limit);
}

GetAttributeByName´Â, ÁöÁ¤µÈ ÇàÀ¸·ÎºÎÅÍ ¼Ó¼ºÀ» µ¹·ÁÁÖ´Â, PostgreSQL½Ã½ºÅÛ ÇÔ¼öÀÔ´Ï´Ù. À̰Ϳ¡´Â 3°³ÀÇ ÀÎÀÚ°¡ ÀÖ½À´Ï´Ù. ±×°ÍµéÀº, ÇÔ¼ö¿¡°Ô °Ç³×Áø HeapTupleHeaderÇüÀÇ ÀÎÀÚ, ¿ä±¸µÈ ¼Ó¼ºÀÇ À̸§, ¼Ó¼ºÀÌ NULLÀÎÁö ¾Æ´ÑÁö¸¦ ÅëÁöÇÏ´Â ¸Å°³º¯¼öÀÔ´Ï´Ù. GetAttributeByName´Â ÀûÀýÇÑ DatumGet XXX ()¸ÅÅ©·Î¸¦ »ç¿ëÇØ ÀûÀýÇÑ µ¥ÀÌÅÍÇü¿¡ º¯È¯ °¡´ÉÇÑ DatumÇüÀÇ °ªÀ» µ¹·ÁÁÝ´Ï´Ù. ÀÌ NULL Ç÷¡±×°¡ ¼³Á¤µÇ¾î ÀÖ´Â °æ¿ì, ¹Ýȯ°ªÀÇ Àǹ̰¡ ¾ø´Â °Í¿¡ ÁÖÀÇÇØ, ÀÌ °á°ú·Î ¹«¾ùÀΰ¡¸¦ ½Ç½ÃÇÏ·Á°í Çϱâ Àü¿¡ Ç×»ó, NULL Ç÷¡±×¸¦ °Ë»çÇØ ÁÖ¼¼¿ä.

¸ñÇ¥¿­À» À̸§Àº ¾Æ´Ï°í ¿­¹øÈ£·Î ¼±ÅÃÇÏ´Â GetAttributeByNumµµ ÀÖ½À´Ï´Ù.

¾Æ·¡¿Í °°Àº ¸í·ÉÀ¸·Î c_overpaidÇÔ¼ö¸¦ SQL·Î ¼±¾ðÇÕ´Ï´Ù.

CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
    AS '
DIRECTORY
/funcs', 'c_overpaid'
    LANGUAGE C STRICT;

ÀÔ·Â ÀÎÀÚ°¡ NULLÀÎÁö ¾Æ´ÑÁö¸¦ °Ë»çÇÒ Çʿ䰡 ¾ø°Ô STRICT¸¦ »ç¿ëÇϰí ÀÖ´Â °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä.

33.9.9. Çà(º¹ÇÕÇü)À» µ¹·ÁÁØ´Ù

C¾ð¾î ÇÔ¼ö·ÎºÎÅÍ Çà ȤÀº º¹ÇÕÇüÀÇ °ªÀ» µ¹·ÁÁÖ±â À§Çؼ­, º¹ÇÕÇüÀÇ º¹ÀâÇÑ ÀÛ¼ºÀÇ ´ëºÎºÐÀ» ÀºÆó ÇÏ´Â ¸ÅÅ©·Î³ª ÇÔ¼ö¸¦ Á¦°øÇÏ´Â, Ưº°ÇÑ API¸¦ »ç¿ëÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ÀÌ API¸¦ »ç¿ëÇϱâ À§Çؼ­´Â, ¼Ò½º ÆÄÀÏ·Î ÀÌÇϸ¦ Æ÷ÇÔÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù.

#include "funcapi.h"

º¹ÇÕÇüÀÇ µ¥ÀÌÅͰª(ÀÌÈÄ "Æ©ÇÃ" Àû´Â´Ù)¸¦ ÀÛ¼ºÇÏ´Â 2°³ÀÇ ¹æ¹ýÀÌ ÀÖ½À´Ï´Ù. Datum°ªÀÇ ¹è¿­·ÎºÎÅÍ ÀÛ¼ºÇÏ´Â ¹æ¹ý, ȤÀº Æ©ÇÃÀÌ ÀÖ´Â ¿­ÀÇ ÇüÅÂÀÇ ÀÔ·Â º¯È¯ ÇÔ¼ö¿¡ °Ç³×ÁÙ ¼ö°¡ ÀÖ´Â Cij¸¯ÅÍ ¶óÀÎÀÇ ¹è¿­·ÎºÎÅÍ ÀÛ¼ºÇÏ´Â °ÍÀÔ´Ï´Ù. ¾î´À ÂÊÀÇ ¹æ¹ý¿¡¼­µµ, ¿ì¼± Æ©Çà ±¸Á¶ ü¿ëÀÇ TupleDesc±â¼ú¾î¸¦ ÀÔ¼ö, ȤÀº ÀÛ¼ºÇÏÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. Datum¸¦ »ç¿ëÇÏ´Â °æ¿ì´Â, TupleDesc¸¦ BlessTupleDesc¿¡ °Ç³×ÁÖ¾î, °¢ Çà¿¡ ´ëÇØ¼­ heap_form_tuple¸¦ È£ÃâÇÕ´Ï´Ù. C¹®ÀÚ¿­À» »ç¿ëÇÏ´Â °æ¿ì´Â, TupleDesc¸¦ TupleDescGetAttInMetadata¿¡ °Ç³×ÁÖ¾î, °¢ Çà¿¡ ´ëÇØ¼­ BuildTupleFromCStrings¸¦ È£ÃâÇÕ´Ï´Ù. Æ©ÇÃÀÇ ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼öÀÇ °æ¿ì, ÀÌ ¼³Á¤ ´Ü°è¸¦ ÃÖÃÊÀÇ ÇÔ¼ö È£Ãâ·Î ÇÑ ¹ø¿¡ Á¤¸®ÇØ ½Ç½ÃÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù.

ÇÊ¿äÇÑ TupleDescÀÇ ¼³Á¤¿ëÀÇ º¸Á¶¿ë ÇÔ¼ö°¡ ¸î °³ ÀÖ½À´Ï´Ù. ´ëºÎºÐÀÇ º¹ÇÕÇüÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö¿¡¼­ÀÇ Ãßõ ¹æ¹ýÀº, ÀÌÇÏÀÇ ÇÔ¼ö¸¦ È£ÃâÇØ, È£Ãâ ¿ø·¡ÀÇ ÇÔ¼ö Àڽſ¡°Ô °Ç³×Áö´Â fcinfo±¸Á¶¿Í °°Àº °ÍÀ» °Ç³×ÁÖ´Â °ÍÀÔ´Ï´Ù.

TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo,
                                   Oid *resultTypeId,
                                   TupleDesc *resultTupleDesc)

(À̰Ϳ¡´Â ¹°·Ð, ¹öÀü 1 È£Ãâ ±Ô¾àÀ» »ç¿ëÇϰí ÀÖ´Â °ÍÀÌ ÇÊ¿äÇÕ´Ï´Ù). resultTypeId¸¦ NULL·Î ÇÏ´Â Àϵµ, ·ÎÄà º¯¼öÀÇ ÁÖ¼Ò¸¦ ÁöÁ¤ÇØ ÇÔ¼öÀÇ ¹Ýȯ°ªÇüÀ» ¹ÞÀ» ¼ö°¡ ÀÖ½À´Ï´Ù. resultTupleDesc´Â ·ÎÄÃÀÎ TupleDescº¯¼öÀÇ ÁÖ¼Ò°¡ ¾Æ´Ï¸é ¾ÈµË´Ï´Ù. °á°ú°¡TYPEFUNC_COMPOSITEÈ­µµÀÎÁö¸¦ È®ÀÎÇØ ÁÖ¼¼¿ä. TYPEFUNC_COMPOSITE¿´À» °æ¿ì, resultTupleDesc¿¡´Â ÇÊ¿äÇÑ TupleDesc°¡ ÀúÀåµÇ°í ÀÖ½À´Ï´Ù. (TYPEFUNC_COMPOSITE´Â ¾Æ´Ï¾ú´ø °æ¿ì, "·¹ÄÚµåÇüÀ» ¹Þ¾ÆµéÀÌÁö ¾Ê´Â ¹®¸ÆÀ¸·Î ·¹Äڵ带 µ¹·ÁÁÖ´Â ÇÔ¼ö°¡ ºÒ·Á °¬´ø "À̶ó°í ÇÏ´Â ¿¡·¯¸¦ º¸°íÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. )

Tip: get_call_result_type´Â, ´ÙÇü ÇÔ¼öÀÇ °á°úÀÇ ½ÇÁ¦ÀÇ ÇüŸ¦ ÇØ°áÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ±×·¯¹Ç·Î, º¹ÇÕÇüÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö ¸¸ÀÌ ¾Æ´Ï°í, ½ºÄ®¶óÀÇ ´Ù¾ç °á°ú¸¦ µ¹·ÁÁÖ´Â ÇÔ¼ö¿¡¼­µµ Àǹ̰¡ ÀÖ½À´Ï´Ù. resultTypeIdÃâ·ÂÀº ÁÖ·Î ½ºÄ®¶óÀÇ ´Ù¾ç °á°ú¸¦ µ¹·ÁÁÖ´Â ÇÔ¼ö·Î Àǹ̰¡ ÀÖ½À´Ï´Ù.

Note: 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)

À̰ÍÀ» ÇüÅÂÀÇ OID¿¡ ±Ù°ÅÇØ TupleDesc¸¦ ²¨³»±â À§Çؼ­ »ç¿ëÇØ ÁÖ¼¼¿ä. À̰ÍÀº ±âº»Çü, ȤÀº º¹ÇÕÇüÀÇ TupleDesc¸¦ ²¨³»±â À§Çؼ­ »ç¿ë °¡´ÉÇÕ´Ï´Ù. À̰ÍÀº record¸¦ µ¹·ÁÁÖ´Â ÇÔ¼ö¿¡¼­´Â Àß ÀÛµ¿ÇÏÁö ¾Ê½À´Ï´Ù. ¶Ç, ´ÙÇü ÇüÅÂÀ» ÇØ°áÇÒ ¼öµµ ÀÖ½À´Ï´Ù.

TupleDesc¸¦ ȹµæÇÑ ÈÄ¿¡, Datum¸¦ »ç¿ëÇÏ´Â °æ¿ì´Â ÀÌÇϸ¦ È£ÃâÇØ ÁÖ¼¼¿ä.

TupleDesc BlessTupleDesc(TupleDesc tupdesc)

Cij¸¯ÅÍ ¶óÀÎÀ» »ç¿ëÇÏ´Â °æ¿ì´Â ÀÌÇϸ¦ È£ÃâÇØ ÁÖ¼¼¿ä.

AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)

ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö¸¦ ÀÛ¼ºÇÏ´Â °æ¿ì´Â, ÀÌ·¯ÇÑ ÇÔ¼öÀÇ °á°ú¸¦ FuncCallContext±¸Á¶¿¡ ÀúÀåÇØ ÁÖ¼¼¿ä. °¢°¢ tuple_desc¿Í attinmeta¸¦ »ç¿ëÇÕ´Ï´Ù.

Datum¸¦ »ç¿ëÇÏ´Â °æ¿ì´Â, »ç¿ëÀÚ µ¥ÀÌÅ͸¦ Datum Çü½Ä¿¡ ÀúÀåÇÑ HeapTuple¸¦ ±¸ÃàÇϱâ À§Çؼ­ ÀÌÇϸ¦ »ç¿ëÇÕ´Ï´Ù.

HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)

C¹®ÀÚ¿­À» »ç¿ëÇÏ´Â °æ¿ì´Â, »ç¿ëÀÚ µ¥ÀÌÅ͸¦ C¹®ÀÚ¿­ Çü½Ä¿¡ ÀúÀåÇÑ HeapTuple¸¦ ±¸ÃàÇϱâ À§Çؼ­ ÀÌÇϸ¦ »ç¿ëÇÕ´Ï´Ù.

HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)

valuesÇÏÇàÀÇ °¢ ¼Ó¼ºÀ» 1 ¿ä¼Ò·Î ÇÑ C¹®ÀÚ¿­ÀÇ ¹è¿­ÀÔ´Ï´Ù. °¢ C¹®ÀÚ¿­Àº, ¼Ó¼ºÀÇ µ¥ÀÌÅÍÇü¿ëÀÇ ÀÔ·Â ÇÔ¼ö°¡ ¹Þ¾ÆµéÀÌ°í °¡´ÉÇÑ Çü½ÄÀÌ ¾Æ´Ï¸é ¾ÈµË´Ï´Ù. ¼Ó¼ºÀÇ °ªÀ» NULL°ªÀ¸·Î¼­ µ¹·ÁÁÖ±â À§Çؼ­´Â, values¹è¿­ÀÇ ´ëÀÀÇÏ´Â Æ÷ÀÎÅÍ¿¡ NULL¸¦ ¼³Á¤ÇØ ÁÖ¼¼¿ä. ÀÌ ÇÔ¼ö´Â µ¹·ÁÁÖ´Â Çà °¢°¢ ´ëÇØ ¹Ýº¹ÇØ È£ÃâÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù.

ÇÔ¼ö·ÎºÎÅÍ µ¹·ÁÁÖ´Â Æ©ÇÃÀ» ´Ù ±¸ÃàÇßÀ¸¸é, ±×°ÍÀ» Datum·Î º¯È¯ÇÏÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. ÀÌÇϸ¦ »ç¿ëÇØ, HeapTuple¸¦ À¯È¿ÇÑ Datum·Î º¯È¯ÇØ ÁÖ¼¼¿ä.

HeapTupleGetDatum(HeapTuple tuple)

´ÜÀÏÇุÀ» µ¹·ÁÁشٸé, ÀÌ Datum¸¦ Á÷Á¢ µ¹·ÁÁÙ ¼ö°¡ ÀÖ½À´Ï´Ù. ¾Æ´Ï¸é, ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö¿¡ À־ÀÇ ÇöÀçÀÇ ¹Ýȯ°ªÀ¸·Î¼­ »ç¿ëÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù.

´ÙÀ½ ¼½¼Ç¿¡ ¿¹¸¦ ³ªÅ¸³À´Ï´Ù.

33.9.10. ÁýÇÕÀ» µ¹·ÁÁØ´Ù

C¾ð¾î ÇÔ¼ö·ÎºÎÅÍ ÁýÇÕ(º¹¼öÇà)À» µ¹·ÁÁÖ´Â ±â´ÉÀ» À§Çؼ­ Ư¼öÇÑ API°¡ ÁغñµÇ¾î ÀÖ½À´Ï´Ù. ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö´Â, ¹öÀü-1 È£Ã⠱Ծ࿡ µû¸¦ Çʿ䰡 ÀÖ½À´Ï´Ù. ¶Ç, ¼Ò½º ÆÄÀÏÀº »ó¼úÇÑ ´ë·Î funcapi.h¸¦ Æ÷ÇÔ ÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù.

ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼ö(SRF)´Â µ¹·ÁÁÖ¾îÁö´Â Ç׸ñ ¸¶´Ù ºÒ·Á °©´Ï´Ù. ±× ¶§¹®¿¡, SRF´Â, °ú°ÅÀÇ Á¶ÀÛÀ» ±â¾ïÇØ È£ÃâÀÇ ¹ø¿¡ ´ÙÀ½ÀÇ Ç׸ñÀ» µ¹·ÁÁÖ±â À§Çؼ­ ÃæºÐÇÑ »óŸ¦ À¯ÁöÇϰí ÀÖÀ» Çʿ䰡 ÀÖ½À´Ï´Ù. ÀÌ Ã³¸®¸¦ Á¦¾î¸¦ º¸Á¶Çϱâ À§ÇÑ FuncCallContext±¸Á¶°¡ °®ÃçÁö°í ÀÖ½À´Ï´Ù. ÇÔ¼ö³»¿¡¼­´Â, º¹¼öÀÇ È£Ãâ¿¡ °ÉÄ¡´Â FuncCallContext¿¡ÀÇ Æ÷ÀÎÅ͸¦ º¸°ü À¯ÁöÇÏ·Á¸é, fcinfo->flinfo->fn_extra¸¦ »ç¿ëÇÕ´Ï´Ù.

typedef struct
{
    /*
     * ÀÌ¹Ì ÇàÇØÁø È£ÃâÀÇ È¸¼ö.
     * 
     * SRF_FIRSTCALL_INIT()¿¡ ÀÇÇØ call_cntr°¡ 0¿¡ ÃʱâÈ­µÇ¾î
     * SRF_RETURN_NEXT()°¡ ºÒ·Á °¥ ¶§¿¡ ÁõºÐ µË´Ï´Ù.
     */
    uint32 call_cntr;

    /*
     * »ý·« °¡´É : È£ÃâÀÇ ÃÖ´ë¼ö
     *
     * max_calls´Â, ÆíÀÇ»ó ÁغñµÇ¾î ÀÖ´Â °Í¸¸À¸·Î, ¼³Á¤Àº »ý·« °¡´ÉÇÕ´Ï´Ù.
     * ¼³Á¤µÇ¾î ÀÖÁö ¾ÊÀ¸¸é, ÇÔ¼ö°¡ Á¾·áÇÑ °ÍÀ» ¾Ë±â À§ÇÑ ´Ù¸¥ ¹æ¹ýÀ»
     * ÁغñÇÒ Çʿ䰡 ÀÖ½À´Ï´Ù.
     */
    uint32 max_calls;

    /*
     * »ý·« °¡´É : °á°ú ½½·Ô¿¡ÀÇ Æ÷ÀÎÅÍ
     * 
     * À̰ÍÀº ÆóÁöµÇ¾î ÈĹæ ȣȯ¼º, Áï ºñÃßõÀÇ TupleDescGetSlot()¸¦ »ç¿ëÇϰí
     * »ç¿ëÀÚ Á¤ÀÇÀÇ SRF¸¦ À§Çؼ­¸¸ Á¸ÀçÇÕ´Ï´Ù.
     */
    TupleTableSlot *slot;

    /*
     * »ý·« °¡´É : ¿©·¯°¡Áö »ç¿ëÀÚ¿¡ ÀÇÇÑ ¹®¸Æ Á¤º¸¿¡ÀÇ Æ÷ÀÎÅÍ
     * 
     * 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´Â Æ©ÇÃ(Áï º¹ÇÕ µ¥ÀÌÅÍÇü)À» µ¹·ÁÁÖ´Â °æ¿ì¿¡ »ç¿ëµÇ¾î BuildTupleFromCStrings()
     * º¸´Ù´Â heap_form_tuple()¸¦ »ç¿ëÇØ Æ©ÇÃÀ» ÀÛ¼ºÇÏ´Â °æ¿ì¿¡°Ô¸¸ ÇÊ¿äÇÕ´Ï´Ù.
     * Åë»ó ¿©±â¿¡ ÀúÀåµÇ´Â TupleDesc´Â ÃÖÃÊ·Î BlessTupleDesc()¸¦ ÃÖÃÊ·Î ½ÇÇàÇÑ °ÍÀ̾î¾ß ÇÕ´Ï´Ù.
     * ¼±.
    */
    TupleDesc tuple_desc;

} FuncCallContext;

SRF´Â ¸î °³ÀÇ ÇÔ¼ö ¹× ¸ÅÅ©·Î¸¦ »ç¿ëÇØ FuncCallContext±¸Á¶¸¦ ÀÚµ¿ÀûÀ¸·Î Á¶ÀÛÇÕ´Ï´Ù (¶Ç fn_extra·Î °Ë»öÇÏ´Â °ÍÀ» »óÁ¤ÇÕ´Ï´Ù).

SRF_IS_FIRSTCALL()

¸¦ »ç¿ëÇØ, ±× ÇÔ¼ö È£ÃâÀÌ Ã¹ ¹øÂ° °ÍÀÎÁö, µÎ¹øÂ° ÀÌÈÄÀÎÁö¸¦ ÆÇ´ÜÇÕ´Ï´Ù. ÃÖÃÊÀÇ È£Ãâ(¿ÀÁ÷)·Î,

SRF_FIRSTCALL_INIT()

À» »ç¿ëÇØ, FuncCallContext¸¦ ÃʱâÈ­ÇÕ´Ï´Ù. ÃÖÃÊÀÇ È£ÃâÀ» Æ÷ÇÔÇÑ ¸ðµç È£Ãâ·Î,

SRF_PERCALL_SETUP()

¸¦ »ç¿ëÇØ, FuncCallContext¸¦ »ç¿ëÇϱâ À§ÇÑ ÀûÀýÇÑ ¼³Á¤À» ½Ç½ÃÇØ, ÀÌÀüÀÇ °æ·Î·ÎºÎÅÍ ³²¾Æ ÀÖ´Â °á°ú µ¥ÀÌÅ͸¦ ¼Ò°ÅÇÕ´Ï´Ù.

ÇÔ¼ö·Î µ¹·ÁÁÖ¾î¾ß ÇÒ µ¥ÀÌÅͰ¡ ÀÖ´Â °æ¿ì´Â,

SRF_RETURN_NEXT(funcctx, result)

¸¦ »ç¿ëÇØ, ±× µ¥ÀÌÅ͸¦ È£ÃâÇØ Ãø¿¡ µ¹·ÁÁÝ´Ï´Ù (¸ÕÀú ¼³¸íÇÑ ´ë·Î result´Â DatumÇü, Áï 1°³ÀÇ °ª ¶Ç´Â Æ©ÇÃÀÏ Çʿ䰡 ÀÖ½À´Ï´Ù). ¸¶Áö¸·À¸·Î, ÇÔ¼ö°¡ µ¥ÀÌÅ͸¦ ´Ù µ¹·ÁÁÖ¾úÀ¸¸é,

SRF_RETURN_DONE(funcctx)

¸¦ »ç¿ëÇØ SRF¸¦ Ŭ¸° ¾÷ ÇØ Á¾·áÇÕ´Ï´Ù.

SRFÀÇ È£Ãâ½Ã¿¡ ÇöÇàÀÌ µÇ¾î ÀÖ´Â ¸Þ¸ð¸® ÄÁÅØ½ºÆ®´Â ÀϽÃÀûÀÎ ¹®¸ÆÀ¸·Î, °¢ È£Ã⵿¾È¿¡ ¼Ò°ÅµË´Ï´Ù. Áï palloc¸¦ »ç¿ëÇØ ÇÒ´çÇÑ °ÍÀÇ ¸ðµÎ¸¦ pfreeÇÒ ÇÊ¿ä´Â ¾ø½À´Ï´Ù. À̰͵éÀº ¸ÓÁö¾Ê¾Æ ¼Ò°ÅµÇ´Â °ÍÀ̱⠶§¹®ÀÔ´Ï´Ù. ±×·¯³ª, µ¥ÀÌÅÍ ±¸Á¶¸¦ º¹¼öÀÇ È£Ãâ¿¡ °Ç³Ê »ç¿ëÇϵµ·Ï ÇÒ´çÇÏ´Â °æ¿ì´Â, ¾îµò°¡ ´Ù¸¥ Àå¼Ò¿¡ ³õ¾ÆµÑ Çʿ䰡 ÀÖ½À´Ï´Ù. multi_call_memory_ctx¿¡ ÀÇÇØ ÂüÁ¶µÇ´Â ¸Þ¸ð¸® ÄÁÅØ½ºÆ®´Â, SRFÀÇ ½ÇÇàÀÌ ³¡³¯ ¶§±îÁö »ç¿ë °¡´ÉÇÏ°Ô ÇØ¾ß ÇÏ´Â µ¥ÀÌÅÍÀÇ º¸°ü Àå¼Ò·Î¼­ ÀûÇÕÇÕ´Ï´Ù. Áï, ´ëºÎºÐÀÇ °æ¿ì, ÃÖÃÊÀÇ È£ÃâÀÇ ¼Â¾÷Áß¿¡ multi_call_memory_ctx¿¡ ¹Ù²Ü Çʿ䰡 ÀÖ´Ù°í ÇÏ´Â °ÍÀÔ´Ï´Ù.

¿ÏÀüÇÑ À¯»ç ÄÚµåÀÇ ¿¹¸¦ ³ªÅ¸³À´Ï´Ù.

Datum
my_set_returning_function(PG_FUNCTION_ARGS)
{
    FuncCallContext  *funcctx;
    Datum             result;
    MemoryContext     oldcontext;
    
further declarations as needed


    if (SRF_IS_FIRSTCALL())
    {
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        /* ÇÑ ¹øÀÇ ¼Â¾÷ Äڵ尡 ¿©±â¿¡ µé¾î°©´Ï´Ù: */
        
user code

        
if returning composite

            
build TupleDesc, and perhaps AttInMetadata

        
endif returning composite

        
user code

        MemoryContextSwitchTo(oldcontext);
    }

    /* ¸Åȸ ½ÇÇàÇÏ´Â ¼Â¾÷ Äڵ尡 ¿©±â¿¡ µé¾î°©´Ï´Ù: */
    
user code

    funcctx = SRF_PERCALL_SETUP();
    
user code


    /* À̰ÍÀº, Á¾·áÇß´ÂÁö ¾Æ´ÑÁö¸¦ Å×½ºÆ®ÇÏ´Â ¹æ¹ýÀÇ ÇϳªÀÔ´Ï´Ù: */
    {
        /* ¿©±â¼­, ´Ù¸¥ Ç׸ñÀ» µ¹·ÁÁÝ´Ï´Ù: */
        
user code

        
obtain result Datum

        SRF_RETURN_NEXT(funcctx, result);
    }
    else
    {
        /* À̰ÍÀ¸·Î Ç׸ñÀ» ´Ù µ¹·ÁÁÖ¾ú½À´Ï´Ù.  ÈĴ Ŭ¸° ¾÷ ÇÒ »ÓÀÔ´Ï´Ù.  */
        
user code

        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;

     /* ÇÔ¼öÀÇ ÃÖÃÊÀÇ È£Ãâ½Ã¿¡¸¸ ½ÇÇà */
     if (SRF_IS_FIRSTCALL())
     {
        MemoryContext   oldcontext;

        /* È£Ãâ°£¿¡ ¿µ±¸È­ÇÏ´Â ÇÔ¼ö ¹®¸ÆÀ» ÀÛ¼º */
       funcctx = SRF_FIRSTCALL_INIT();

        /* º¹¼ö ÇÔ¼ö È£Ãâ¿¡ ÀûÀýÇÑ ¸Þ¸ð¸® ÄÁÅØ½ºÆ®¿¡ÀÇ º¯È¯ */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /* µ¹·ÁÁÖ¾îÁö´Â Æ©ÇÃÀÇ ÇÕ°è¼ö */
        funcctx->max_calls = PG_GETARG_UINT32(0);

        /*  °á°úÇü¿ëÀÇ Æ©Çà ±â¼ú¾î¸¦ ÀÛ¼º */
        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")));

        /*
         * ´ÙÀ½¿¡ ¹Ì°¡°øÀÇ C¹®ÀÚ¿­À¸·ÎºÎÅÍ Æ©ÇÃÀ» ÀÛ¼ºÇϱâ À§Çؼ­ ÇÊ¿äÇÏ´Ù
         * ¼Ó¼º ¸ÞŸµ¥ÀÌÅÍÀÇ »ý¼º
         */
        attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = attinmeta;

        MemoryContextSwitchTo(oldcontext);
    }

    /* ¸ðµç ÇÔ¼ö È£Ãâ·Î ½ÇÇà */
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    attinmeta = funcctx->attinmeta;
 
    if (call_cntr < max_calls)    /* ±× ¹Û¿¡µµ º¸³»´Â °ÍÀÌ ÀÖ´Â °æ¿ì  */
    {
        char       **values;
        HeapTuple    tuple;
        Datum        result;

        /*
         * µ¹·ÁÁÖ´Â Æ©ÇÃÀ» ±¸ÃàÇϱâ À§ÇÑ °ªÀÇ ¹è¿­À» ÁغñÇÕ´Ï´Ù.
         * À̰ÍÀº, ´ÙÀ½¿¡ ÀûÀýÇÑ ÀÔ·Â ÇÔ¼ö·Î 󸮵ȴÙ
         * C¹®ÀÚ¿­ÀÇ ¹è¿­ÀÌ ¾Æ´Ï¸é ¾ÈµË´Ï´Ù.
         */
        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));

        /* Æ©ÇÃÀÇ ÀÛ¼º */
        tuple = BuildTupleFromCStrings(attinmeta, values);

        /* Æ©ÇÃÀ» datum¿¡ º¯È¯ */
        result = HeapTupleGetDatum(tuple);

        /* Ŭ¸° ¾÷(À̰ÍÀº Çʼö°¡ ¾Æ´Õ´Ï´Ù) */
        pfree(values[0]);
        pfree(values[1]);
        pfree(values[2]);
        pfree(values);

        SRF_RETURN_NEXT(funcctx, result);
    }
    else    /* ¾Æ¹«°Íµµ ³²Áö ¾ÊÀº °æ¿ì */
    {
        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 '
filename
', '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 '
filename
', 'retcomposite'
    LANGUAGE C IMMUTABLE STRICT;

ÀÌ ¹æ¹ý¿¡¼­´Â, ÇÔ¼öÀÇ Ãâ·ÂÇüÀº Çü½Ä»ó À͸íÀÇ recordÇüÀÌ µÇ´Â °Í¿¡ ÁÖÀÇÇØ ÁÖ¼¼¿ä.

¼Ò½º ¹èÆ÷¹°³»ÀÇ contrib/tablefuncµð·ºÅ丮¿¡´Â, ÁýÇÕÀ» µ¹·ÁÁÖ´Â ÇÔ¼öº¸´Ù ¸¹Àº ¿¹°¡ ÀÖ½À´Ï´Ù.

33.9.11. Àμö¿Í ¹Ýȯ°ªÀÇ ´ÙÇ⼺

C¾ð¾î ÇÔ¼ö´Â, anyelement, anyarray, anynonarray ¹× anyenum´ÙÇâÇüÀ» ¹Þ¾ÆµéÀ̰ųª, ¶Ç´Â µ¹·ÁÁÖµµ·Ï ¼±¾ðÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. ´ÙÇâ ÇÔ¼öÀÇ »ó¼¼ÇÑ ¼³¸íÀº Section 33.2.5À» ÂüÁ¶ÇØ ÁÖ¼¼¿ä. ÇÔ¼öÀÇ ÀÎÀÚ È¤Àº ¹Ýȯ°ªÀÌ ´ÙÇâÇüÀ¸·Î¼­ Á¤ÀÇµÉ ¶§, ÇÔ¼öÀÇ ÀÛ¼ºÀÚ´Â ¹Ì¸® È£ÃâÇÔ¿¡ À־ÀÇ µ¥ÀÌÅÍÇüÀ̳ª µ¹·ÁÁÖ¾î¾ß ÇÒ µ¥ÀÌÅÍÇüÀÌ ¹«¾ùÀÎÁö ¾Ë ¼ö ¾ø½À´Ï´Ù. ¹öÀü-1 CÇÔ¼ö·Î ÀÎÀÚÀÇ ¿­¸Å µ¥ÀÌÅÍÇü°ú µ¹·ÁÁÖ¾î¾ß ÇÏ´Â °Í°ú »óÁ¤µÈ ÇüŸ¦ ¹ß°ßÇÒ ¼ö ÀÖ±â À§ÇÑ 2°³ÀÇ ·çƾÀÌ fmgr.h¿¡ ÁغñµÇ¾î ÀÖ½À´Ï´Ù. ÀÌ ·çƾÀº get_fn_expr_rettype(FmgrInfo *flinfo)¿Í get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)¶ó´Â À̸§ÀÔ´Ï´Ù. À̰͵éÀº °á°ú ȤÀº ÀÎÀÚÇüÀÇ OID¸¦ µ¹·ÁÁÝ´Ï´Ù. ´Ù¸¸, ¸¸¾à Á¤º¸¸¦ ÀÌ¿ëÇÒ ¼ö ¾øÀ¸¸é InvalidOid¸¦ µ¹·ÁÁÝ´Ï´Ù. flinfo±¸Á¶´Â Åë»ó fcinfo->flinfo·Î¼­ Á¢¼Ó µË´Ï´Ù. argnum¸Å°³º¯¼ö´Â 0À¸·ÎºÎÅÍ ½ÃÀ۵˴ϴÙ. ¶Ç, get_fn_expr_rettype ´ë½Å¿¡ get_call_result_type¸¦ »ç¿ëÇÒ ¼öµµ ÀÖ½À´Ï´Ù.

¿¹¸¦ µé¸é, ÀÓÀÇÀÇ ÇüÅÂÀÇ ´ÜÀÏ ¿ä¼Ò¸¦ ¹Þ¾Æµé¿© ±× ÇüÅÂÀÇ 1 Â÷¿ø ¹è¿­À» µ¹·ÁÁÖ´Â ÇÔ¼ö¸¦ »ý°¢ÇØ º¸°Ú½À´Ï´Ù.

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);

    /* Â÷¿ø¼ö´Â 1 */
    ndims = 1;
    /* ¿ä¼Ò¸¦ 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);
}

ÀÌÇÏÀÇ ¸í·ÉÀº SQL·Î make_arrayÇÔ¼ö¸¦ ¼±¾ðÇÕ´Ï´Ù.

CREATE FUNCTION make_array(anyelement) RETURNS anyarray
    AS '
DIRECTORY
/funcs', 'make_array'
    LANGUAGE C IMMUTABLE;

33.9.12. °øÀ¯ ¸Þ¸ð¸®¿Í LWLocks

¾Öµå ÀÎ(Add In)´Â LWLocks(°æ·® ¶ô)¿Í ¼­¹ö ±âµ¿½Ã¿¡ °øÀ¯ ¸Þ¸ð¸®ÀÇ ÇÒ´çÀ» º¸°ü À¯ÁöÇÒ ¼ö°¡ ÀÖ½À´Ï´Ù. shared_preload_libraries ·Î ÁöÁ¤ÇØ, ÀÌ·¯ÇÑ ¾Öµå ÀÎ(Add In)ÀÇ °øÀ¯ ¶óÀ̺귯¸®¸¦ »çÀü¿¡ ·ÎµåÇÏÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù. °øÀ¯ ¸Þ¸ð¸®´Â, ±× _PG_initÇÔ¼ö·Î ÀÌÇϸ¦ È£ÃâÇÏ´Â °ÍÀ¸·Î º¸°ü À¯ÁöµË´Ï´Ù.

void RequestAddinShmemSpace(int size)

LWLocks´Â ±× _PG_initÇÔ¼ö·Î ÀÌÇϸ¦ È£ÃâÇÏ´Â °ÍÀ¸·Î º¸°ü À¯ÁöµË´Ï´Ù.

void RequestAddinLWLocks(int n)

°æÇÕ »óÅÂÀÇ °¡´É¼ºÀ» ¹æÁöÇϱâ À§Çؼ­, ÇÒ´çÇÒ ¼ö ÀÖ¾ú´ø °øÀ¯ ¸Þ¸ð¸®¿¡ÀÇ Á¢¼ÓÀ̳ª ±× ÃʱâÈ­½Ã¿¡, ÀÌÇÏ¿Í °°ÀÌ °¢ ¿¬±¸ ÃÖÁ¾ ´Ü°è¿¡ AddinShmemInitLock°æ·® ¶ôÀ» »ç¿ëÇÏÁö ¾ÊÀ¸¸é ¾ÈµË´Ï´Ù.

        static mystruct *ptr = NULL;

        if (!ptr)
        {
                bool    found;

                LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
                ptr = ShmemInitStruct("my struct name", size, &found);
                if (!ptr)
                        elog(ERROR, "out of shared memory");
                if (!found)
                {
                        initialize contents of shmem area;
                        acquire any requested LWLocks using:
                        ptr->mylockid = LWLockAssign();
                }
                LWLockRelease(AddinShmemInitLock);
        }