
हैलो, habracheloveki! आप में से कई को संग्रहीत कार्यों / प्रक्रियाओं के रूप में DBMS में व्यावसायिक तर्क रखने का सामना करना पड़ा है, जिससे ग्राहक के लिए यह आसान हो जाता है। इसके फायदे और नुकसान दोनों हैं। आज मैं आपको बताना चाहता हूं कि सी में लिखे गए
पोस्टग्रेक्सेल में संग्रहीत कार्यों को कैसे बनाया जाए। इस लेख में बहुत मूल बातें शामिल होंगी जिन्हें आपको उनके साथ शुरू करने के लिए जानना होगा।
उपयोगकर्ता कार्यों का विवरण
वर्तमान में
PostgreSQL आपको निम्न प्रकार के उपयोगकर्ता-परिभाषित कार्यों को परिभाषित करने की अनुमति देता है:
- SQL फ़ंक्शन
- C कार्य करता है
- प्रक्रियात्मक भाषाओं में कार्य ( plpgsql , pltcl , plperl , आदि)
SQL फ़ंक्शंस ऐसे फ़ंक्शंस हैं जिनमें बॉडी में एक या एक से अधिक
SQL क्वेरीज़ होती हैं, जिसके साथ अंतिम क्वेरी का परिणाम लौटाया जाता है। इसके अलावा, अगर लौटा हुआ रिजल्ट
शून्य नहीं
है , तो इसे
रेनस्ट्रिंग निर्माण के साथ
INSERT ,
UPDATE , या
DELETE का उपयोग करने की अनुमति है।
सी फ़ंक्शन सांख्यिकीय और गतिशील रूप से लोड किए गए हैं। डेटाबेस क्लस्टर को इनिशियलाइज़ करने पर स्टेटिकली लोडेड (जिसे इंटरनल फंक्शन्स भी कहा जाता है) सर्वर पर बनाए जाते हैं, डायनेमिकली लोडेड सर्वर के द्वारा लोड किए जाते हैं।
प्रक्रियात्मक भाषाओं के कार्यों में उपयुक्त एक्सटेंशन के निर्माण की आवश्यकता होती है, और कुछ भाषाएं दो प्रकार की हो सकती हैं - विश्वसनीय और अविश्वसनीय (बाद के लिए उपयोगकर्ता कार्यों को सीमित करने का कोई तरीका नहीं है)। मूल
PostgreSQL पैकेज में
plpgsql ,
pltcl ,
plperl और
plpython शामिल हैं , अन्य भाषाओं की एक सूची
यहां पाई जा सकती
है ।
SQL के माध्यम से प्रक्रियात्मक भाषाओं के लिए एक्सटेंशन बनाए गए हैं:
CREATE EXTENSION pltcl;
या कंसोल के माध्यम से (प्लिफ़थॉन केवल एक अविश्वसनीय रूप में उपलब्ध है):
createlang plpythonu
C में गतिशील रूप से लोड किए गए कार्य
C में डायनामिक रूप से लोड किए गए फ़ंक्शन गतिशील रूप से लोड किए गए (या साझा किए गए) लाइब्रेरी में समाहित हैं, जो फ़ंक्शन को पहली बार कॉल करने पर लोड होते हैं। इस तरह के एक समारोह बनाने का एक उदाहरण:
CREATE OR REPLACE FUNCTION grayscale ( r double precision, g double precision, b double precision ) RETURNS double precision AS 'utils', 'grayscale' LANGUAGE C STRICT;
यह उदाहरण
ग्रेस्केल फंक्शन (जिसमें तीन
फ्लोट पैरामीटर हैं और एक
फ्लोट लौटाता है)
बनाता है , जो
बर्तन गतिशील पुस्तकालय में स्थित है।
STRIC कीवर्ड का उपयोग इसलिए किया जाता है ताकि फ़ंक्शन
NULL पर लौट आए यदि कम से कम एक तर्क
NULL है। यदि निरपेक्ष पथ निर्दिष्ट नहीं है, तो
डाइनामिक_लॉटर_पैथ चर में निर्दिष्ट निर्देशिका का अर्थ है, जिसका मूल्य इस तरह देखा जा सकता है:
SELECT current_setting ( 'dynamic_library_path' );
यदि डायनेमिक लाइब्रेरी के लिए चर या पथ का मूल्य
$ libdir से शुरू होता है, तो
$ libdir को
PostgreSQL लाइब्रेरी वाले निर्देशिका में पथ के साथ बदल दिया जाता है, जिसे कंसोल कमांड का उपयोग करके पाया जा सकता है:
pg_config --pkglibdir
चूंकि लाइब्रेरी को लोड करना उपयोगकर्ता अधिकारों के साथ किया जाता है जिसके तहत
पोस्टग्रेसीक्यूएल डेमन चल रहा है (आमतौर पर
पोस्टग्रेज ), इस उपयोगकर्ता के पास लाइब्रेरी के एक्सेस अधिकार होने चाहिए।
कार्यों के लिए दो प्रकार के सम्मेलन हैं:
संस्करण 0 (पदावनत) और
संस्करण 1 ।
संस्करण 0 के कार्य पोर्टेबल नहीं
हैं और सीमित कार्यक्षमता है, इसलिए
संस्करण 1 के कार्य आगे निहित हैं। यह इंगित करने के लिए कि हम
संस्करण 1 का उपयोग कर रहे हैं, फ़ंक्शन को परिभाषित करने से पहले एक विशेष मैक्रो के साथ चिह्नित किया जाना चाहिए:
PG_FUNCTION_INFO_V1(grayscale);
गतिशील पुस्तकालय संरचना
प्रत्येक लाइब्रेरी में एक निश्चित मैजिक ब्लॉक (एक, फाइलों की संख्या की परवाह किए बिना) होना चाहिए, ताकि विसंगतियों का पता लगाना संभव हो, उदाहरण के लिए,
पोस्टग्रैसीक्यूएल सर्वर का पुराना संस्करण और
पोस्टग्रैसीक्यूएल का संस्करण जिसके साथ लाइब्रेरी बनाई गई है। इस ब्लॉक को इस तरह घोषित किया जाता है:
#include <fmgr.h> #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif
यदि आवश्यक हो, तो आप
_PG_init आरंभीकरण
फ़ंक्शन (जिसमें कोई पैरामीटर और रिटर्न
शून्य नहीं है ) को परिभाषित कर सकते हैं, जिसे लाइब्रेरी लोड करने के बाद कहा जाता है, और
_PG_fini इनिशियलाइज़ेशन फ़ंक्शन (जिसमें
_PG_init के समान हस्ताक्षर हैं), जिसे लाइब्रेरी अनलोड किए जाने से पहले कहा जाता है। कृपया ध्यान दें कि प्रलेखन में कहा गया है कि पुस्तकालय वर्तमान में अनलोड नहीं हैं, इसलिए
_PG_fini फ़ंक्शन
को कभी भी नहीं बुलाया जाएगा। समारोह का उदाहरण:
void _PG_init() { createLog(); } void _PG_fini() { destroyLog(); }
पुस्तकालय में कार्यों के लिए एक निश्चित प्रकार है, मैक्रोज़ के लिए, तर्क प्राप्त करना, परिणाम वापस करना और कुछ अन्य संचालन, विशेष मैक्रोज़ प्रदान किए जाते हैं (नीचे अधिक विवरण में वर्णित है):
Datum grayscale(PG_FUNCTION_ARGS) { float8 r = PG_GETARG_FLOAT8(0); float8 g = PG_GETARG_FLOAT8(1); float8 b = PG_GETARG_FLOAT8(2); PG_RETURN_FLOAT8(0.299 * r + 0.587 * g + 0.114 * b); }
डेटा प्रकार
कार्यों में उपयोग किए जाने वाले मूल डेटा प्रकारों को तीन प्रकारों में विभाजित किया जाता है:
- मूल्य द्वारा प्रेषित निश्चित लंबाई
- निश्चित-लंबाई, साइनपोस्टेड
- चर लंबाई सूचक द्वारा पारित कर दिया
पहले प्रकार के प्रकारों का आकार 1, 2 या 4 बाइट्स (या 8 हो सकता है यदि आपके प्लेटफ़ॉर्म पर
आकार (डेटाम) 8 है)। अपने स्वयं के प्रकारों को परिभाषित करते समय (उदाहरण के लिए,
टाइपडिफ के माध्यम से), आपको यह सुनिश्चित करना चाहिए कि सभी आर्किटेक्चर पर उनका आकार समान है।
सूचक द्वारा पारित निश्चित-लंबाई प्रकार संरचनाएं हैं। उनके लिए मेमोरी
आवंटित करना (और तीसरे प्रकार के प्रकार) का उपयोग करना आवश्यक है, उदाहरण के लिए:
typedef struct { float r, g, b, a; } Color; Color *color = (Color*)palloc(sizeof(Color));
तीसरे प्रकार के प्रकारों के लिए, पूरे क्षेत्र के आकार (डेटा आकार + फ़ील्ड आकार) के भंडारण के लिए एक फ़ील्ड (4 बाइट्स) को परिभाषित करना आवश्यक है और वास्तव में, डेटा स्वयं, लगातार इस क्षेत्र के पीछे स्थित है। यह फ़ॉर्म की संरचना का उपयोग करके किया जा सकता है:
typedef struct { int32 length; char data[1]; } text;
प्रकार के साथ फ़ील्ड का मान
SET_VARSIZE मैक्रो का उपयोग करके स्पष्ट रूप से सेट किया गया है। सूचक द्वारा पारित चर-लंबाई प्रकारों के साथ काम करने के लिए अन्य मैक्रोज़:
char data[10]; ... text *string = (text*)palloc(VARHDRSZ + 20);
C और
SQL में फ़ंक्शन के प्रकारों के बीच पत्राचार को
इस तालिका में दर्शाया गया है।
पॉइंटर द्वारा स्थानांतरित किए गए प्रकारों के बारे में, यह ध्यान दिया जाना चाहिए कि इस पॉइंटर द्वारा इंगित किए गए डेटा को बदला नहीं जा सकता है, क्योंकि यह सीधे डिस्क पर स्थित डेटा हो सकता है, जिससे उनकी क्षति हो सकती है। परिणाम पूरी तरह से हर्षित नहीं होंगे।
कार्य संरचना
फ़ंक्शन के हस्ताक्षर इस तरह दिखना चाहिए:
Datum grayscale(PG_FUNCTION_ARGS);
डैटम एक फ़ंक्शन के वापसी मूल्य के लिए एक विशेष प्रकार है, जो अनिवार्य रूप
से एक पॉइंटर
का एक प्रकार है । मैक्रो
PG_FUNCTION_ARGS फ़ंक्शन के मापदंडों के बारे में मेटा-जानकारी युक्त संरचना में एक संकेतक में विस्तारित होता है: कॉल का संदर्भ, चाहे मूल्य
NULL और इसी तरह। फ़ंक्शन तर्क
PG_GETARG_ * मैक्रो का उपयोग करके एक्सेस किए जाते हैं:
float8 r = PG_GETARG_FLOAT8(0);
यदि
SQL फ़ंक्शन STRICT के बिना घोषित किया गया है, तो आप तर्क का मान
NULL है या नहीं, यह जांचने के लिए PG_ARGISNULL का उपयोग कर सकते हैं। आप फ़ंक्शन का परिणाम
NULL के माध्यम से
PG_RETURN_NULL के माध्यम से वापस कर सकते हैं। एक उदाहरण के रूप में, आइए देखें कि बिना
STRICT के एक फ़ंक्शन कार्यान्वयन कैसा दिखता है:
Datum grayscale(PG_FUNCTION_ARGS) { if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) { PG_RETURN_NULL(); } float8 r = PG_GETARG_FLOAT8(0); float8 g = PG_GETARG_FLOAT8(1); float8 b = PG_GETARG_FLOAT8(2); PG_RETURN_FLOAT8(0.299 * r + 0.587 * g + 0.114 * b); }
उदाहरण उदाहरण

अब, सी में एक संग्रहीत फ़ंक्शन लिखने का तरीका जानने के बाद, आइए संक्षेप में देखें और एक उदाहरण देखें। हमारे पास जो पर्यावरण होगा:
- ऑपरेटिंग सिस्टम: Ubuntu 12.10
- PostgreSQL संस्करण: 9.3
- संकलक: gcc 4.7.2
निम्नलिखित सामग्री के साथ एक utils.c फ़ाइल बनाएँ:
#include <postgres.h> #include <fmgr.h> #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(grayscale); Datum grayscale(PG_FUNCTION_ARGS) { float8 r = PG_GETARG_FLOAT8(0); float8 g = PG_GETARG_FLOAT8(1); float8 b = PG_GETARG_FLOAT8(2); PG_RETURN_FLOAT8(0.299 * r + 0.587 * g + 0.114 * b); }
अगला, एक फ़ाइल में utils.c संकलित करें, और यह
स्थिति-स्वतंत्र कोड (
gcc के लिए , यह
fpic विकल्प है) के साथ होना चाहिए:
cc -I/usr/local/pgsql/include/server -fpic -c utils.c
Pg_config --includedir-server कमांड आपको शीर्ष लेख फ़ाइलों के साथ निर्देशिका का स्थान बताएगा। ऑब्जेक्ट फ़ाइल को डायनेमिक लाइब्रेरी के रूप में लिंक करें (यदि सब कुछ क्रम में है, तो हमारे पास
utils.so डायनामिक लाइब्रेरी होनी चाहिए, इसे कॉपी करें
/ usr / local / pgsql / lib ):
cc -shared -L/usr/local/pgsql/lib -lpq -o utils.so utils.o
अब, हमारे डेटाबेस से कनेक्ट करें और इसमें
ग्रेस्केल_ सी फ़ंक्शन बनाएं, कुछ विकल्पों का संकेत देते हुए:
CREATE OR REPLACE FUNCTION grayscale_c ( r double precision, g double precision, b double precision ) RETURNS double precision AS 'utils', 'grayscale' LANGUAGE C STRICT VOLATILE COST 100;;
इसके प्रदर्शन की जाँच करें:
SELECT grayscale_c ( 0.6, 0.5, 0.5 );
लेकिन यह सब नहीं है। इस फ़ंक्शन की तुलना एक समान के साथ करें, लेकिन plpgsql पर।
आइए इसे
ग्रेस्केल_प्लेग्स्कल कहें:
CREATE OR REPLACE FUNCTION grayscale_plpgsql ( r double precision, g double precision, b double precision ) RETURNS double precision AS $BODY$ BEGIN RETURN 0.299 * r + 0.587 * g + 0.114 * b; END $BODY$ LANGUAGE plpgsql STRICT VOLATILE COST 100;
और कुछ परीक्षण करते हैं:
CREATE TABLE color AS SELECT random () AS r, random () AS g, random () AS b FROM generate_series ( 1, 1000000 ); SELECT grayscale_c ( r, g, b ) FROM color;
थोड़ा सा चेक:
SELECT * FROM color WHERE grayscale_c ( r, g, b ) != grayscale_plpgsql ( r, g, b );
एक बहुत अच्छा परिणाम।
जैसा कि हमने देखा है, सी में गतिशील रूप से लोड किए गए फ़ंक्शन बनाना ऐसी कोई मुश्किल बात नहीं है। एक नियम के रूप में कठिनाइयाँ, उनके कार्यान्वयन में दुबक जाती हैं।
पुनश्च आपका ध्यान के लिए धन्यवाद।
संदर्भ: