सामान्य एकल में, उद्धरण उन्हें दोगुना करके बच जाते हैं।
अपने वेरिएबल्स को SQL स्ट्रिंग में जोड़ने के लिए, आपको quote_literal()
. का उपयोग करना चाहिए - वह फ़ंक्शन एकल उद्धरण से ठीक से बचने का ख्याल रखता है, जैसे:
quote_literal(temp_row.row_data)
ऐसा कहने के बाद:बेहतर (और सुरक्षित) समाधान format()
. के साथ संयुक्त पैरामीटर का उपयोग करना है :
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', tg_table_name)
using temp_row.action_tstamp_tx, temp_row.action, temp_row.row_data;
%I
प्लेसहोल्डर आमतौर पर पहचानकर्ता से ठीक से बचने का ख्याल रखता है, हालांकि इस मामले में यह काम नहीं करेगा। यदि आप 100% सुनिश्चित होना चाहते हैं कि गैर-मानक तालिका नाम भी ठीक से काम करते हैं, तो आपको पहले लक्ष्य तालिका नाम को एक चर में रखना होगा और उसका उपयोग format()
के लिए करना होगा। समारोह:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
यह हिस्सा:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
पहली पंक्ति के बाद भी विफल होने जा रहा है। execute .. into ...
क्वेरी को एकल . लौटाने की अपेक्षा करता है . आप जिस कथन का उपयोग कर रहे हैं वह सभी लौटाएगा इतिहास तालिका से पंक्तियाँ।
मुझे यह भी समझ में नहीं आता कि आप पहली बार ऐसा क्यों करते हैं।
आपको इतिहास तालिका से बिल्कुल भी चयन करने की आवश्यकता नहीं है।
ऐसा कुछ पर्याप्त होना चाहिए (अप्रयुक्त! ):
IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
temp_row := NEW;
ELSE
RAISE EXCEPTION '[audit.if_modified] - Trigger func added as trigger for unhandled case: %, %',TG_OP, TG_LEVEL;
RETURN NULL;
END IF;
execute format ('insert ... values ($1, $2, $3')
using now(), SUBSTRING(TG_OP,1,1), temp_row;
अंत में:ऑडिट ट्रिगर पहले भी लिखे जा चुके हैं, और इसके लिए बहुत सारे तैयार समाधान हैं: