وظائف لتوثيق قواعد بيانات PostgreSQL. الجزء الثاني

هذا هو الجزء الثاني من المقالة الذي يصف الوظائف المعرفة من قبل المستخدم للعمل مع دلائل النظام: pg_class ، pg_attribute ، pg_constictions ، إلخ.

يناقش هذا الجزء من المقالة الوظائف التي تُرجع خصائص القيود والفهارس .

يقدم النصف الأول من المقالة تعليقات على تنفيذ الوظائف. والثاني هو رمز المصدر للوظائف. بالنسبة للقراء المهتمين فقط بالنصوص المصدر ، نقترح المتابعة الفورية للملحق .

انظر أيضًا
وظائف لتوثيق قواعد بيانات PostgreSQL. الجزء الأول
وظائف لتوثيق قواعد بيانات PostgreSQL. الجزء الثالث .
وظائف لتوثيق قواعد بيانات PostgreSQL. النهاية (الجزء الرابع) .

قائمة admtf_Table_Constraintes لقيود جدول قاعدة البيانات وخصائصها



تعرض الدالة admtf_Table_Constraintes قائمة بالقيود (CONSTRAINT) لجدول قاعدة البيانات وخصائصها. يمكن عرض كود المصدر وتنزيله هنا ، وهنا نسخة من وظيفة لا تستخدم المؤشر .



كمعلمات ، تأخذ الدالة اسم الجدول المصدر ( a_TableName ) واسم المخطط الذي يتم إنشاء الجدول داخله ( a_SchemaName ).

وصف قيد معين هو مزيج من السجل في pg_class يصفه بأنه علاقة مادية والسجل في pg_constraint يحتوي على بيانات عن الخصائص المحددة للقيد .




كود المصدر للعامل في الشكل
SELECT tbl.OID,con.conname,con.contype,con.conkey,reftbl.OID, reftbl.relname,con.confkey,con.consrc FROM pg_constraint con INNER JOIN pg_namespace nsp ON con.connamespace=nsp.oid LEFT OUTER JOIN pg_class tbl ON con.conrelid=tbl.oid LEFT OUTER JOIN pg_class reftbl ON con.confrelid=reftbl.oid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableOID) ORDER BY con.contype DESC,con.conname; 


يتم استرداد البيانات الرئيسية (اسم ونوع التقييد) من إدخال دليل pg_constraint . يتم استخراج خصائص كل قيد من نفس الكتالوج ، والتي يتم تقديمها في شكل جداول OID ( conrelid ، confrelid ) أو صفائف من الأرقام التسلسلية للسمات ( conkey ، confkey ) المشاركة في القيد.



تقوم الدالة بإرجاع خصائص القيد في شكل أسماء الجدول والسمات. في هذه الحالة ، يتم استخراج أسماء الجداول من إدخال كتالوج pg_class حسب المعرف (OID) ، وأسماء السمات من إدخالات كتالوج pg_attribute بواسطة معرف الجدول والرقم التسلسلي للسمة. لأن نظرًا لأنه يتم تخزين الأرقام التسلسلية في الدليل الرئيسي في شكل مصفوفة (قائمة) ، فإن قوائم أسماء السمات يتم تشكيلها داخل الوظيفة باستخدام حلقة.


تقوم الدالة بإرجاع خاصية خاصة واحدة - القاعدة للتحقق من قيم الحقول في إدخالات الجدول (تقييد التحقق). يتم تخزين هذه الخاصية كقيمة نصية في حقل كونك للدليل pg_constraint .


الجدول 7. نتيجة تنفيذ الوظيفة admtf_Table_Constraintes ("public" ، "Street").

نسخة النص من الجدول في الشكل
العنواناكتبسمات جدول المصدراسم الجدول الخارجيسمات الجدول الخارجيقاعدة التحقق
xpkstreetصwcrccode ، localityid ، streetid
fk_street_localityوwcrccode ، localityidمحلةwcrccode ، localityid
fk_street_streettypeوstreettypeacrmنوع الشارعstreettypeacrm
ck_street_streetnameجاسم الشارع((اسم الشارع) :: text! ~ * '[az]' :: text)
ck_street_streettypeacrmجstreettypeacrm((streettypeacrm) :: bpchar! ~ * '[az]' :: text)



إصدار بدون مؤشر


أتوقع أسئلة وتعليقات حول استخدام المؤشر في النسخة الرئيسية من الوظيفة.


لن أجيب - لا يوجد رفاق للطعم واللون. ولكن سأعطي نسخة من الوظيفة بدون مؤشر. يمكن الاطلاع على نسخة تنفيذ الوظيفة بدون استخدام المؤشر وتنزيلها هنا .


وتتمثل الصعوبة الرئيسية في تنظيم الصلة (JOIN) للجداول وفقًا للقيم الموجودة في نوع سمة صفيف أحدها. مثل هذه المصفوفات في هذه الحالة هي كونكي وكونكي .



 SELECT c.conname,c.contype,c.conkey::SMALLINT[], GENERATE_SUBSCRIPTS(c.conkey, 1) as No FROM pg_constraint c WHERE c.conname='fk_street_locality' ORDER BY No; 

لحل هذه المشكلة ، يحتوي PostgrSQL على دالات ترجع جدول قيم المؤشرات إلى عناصر الصفيف. في حالتنا ، سيتم استخدام وظيفة gener_subscripts. فهو لا يولد الكثير من المؤشرات إلى موضع المصفوفة التي تم تمريرها إليه كمعلمة فحسب ، بل يحول أيضًا سجلًا واحدًا يحتوي على المصفوفة إلى عدة عناصر بعدد العناصر في المصفوفة. يحتوي كل سجل لهذا الجدول على قيمة فريدة واحدة - موضع الصفيف.



الجدول 8. نشر السلسلة الأصلية باستخدام gener_subscripts .

اسم التقييداكتبصفيف من أرقام السماتالمؤشر إلى موضع صفيف
fk_street_localityو{1} {2}1
fk_street_localityو{1} {2}2



كود المصدر للعامل في الشكل
 SELECT con.conname AS ConstraintName,con.contype::VARCHAR(2) AS ConstraintType, STRING_AGG(attr.attname, ', 'ORDER BY con.No) AS r_ConstraintKeyNames, reftbl.relname AS RefTableName, STRING_AGG(rattr.attname,', 'ORDER BY con.No) AS r_RefTableKeyNames, con.consrc AS ConstraintSource FROM (SELECT c.oid, c.conrelid,c.confrelid,c.conname,c.contype, c.conkey::SMALLINT[],c.consrc, c.confkey::SMALLINT[], generate_subscripts(c.conkey, 1) as No FROM pg_constraint c) con INNER JOIN pg_class tbl ON con.conrelid=tbl.oid INNER JOIN pg_attribute attr ON attr.attrelid=tbl.oid AND attr.attnum=con.conkey[con.No] INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid LEFT OUTER JOIN pg_class reftbl ON con.confrelid=reftbl.oid LEFT OUTER JOIN pg_attribute rattr ON rattr.attrelid=reftbl.oid AND rattr.attnum=con.confkey[con.No] WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) GROUP BY con.conname,con.contype,reftbl.relname,con.consrc ORDER BY con.contype DESC,con.conname; 


يمكن ربط هذا الجدول بفهرس السمات pg_attribute ، واستخراج أسماء السمات منه بالحالة attr.attrelid = tbl.oid AND attr.attnum = con.conkey [con.No] .
الآن يبقى إزالة السجلات غير الضرورية عن طريق تجميع السجلات ، وإنشاء سلسلة من أسماء السمات.


يتم إنشاء صف باستخدام وظيفة التجميع STRING_AGG ، حيث يجب عليك تحديد خيار الفرز (ORDER BY) ، وإلا قد لا يكون ترتيب السمات وفقًا لترتيب الإعلان عن السمات في الفهرس.



تزامن وقت تنفيذ كلا الإصدارين من الدالات. استغرق الأمر 20 مللي ثانية لإخراج البيانات في جدول النتائج.


قائمة وظائف Admtf_Table_Indexes لفهارس جدول قاعدة البيانات وخصائصها



تعرض الدالة admtf_Table_Indexes قائمة بالفهارس (INDEX) لجدول قاعدة البيانات وخصائصها. يمكن عرض كود المصدر وتنزيله هنا ، وهنا نسخة من وظيفة لا تستخدم المؤشر .


كمعلمات ، تأخذ الدالة اسم الجدول المصدر ( a_TableName ) واسم المخطط الذي يتم إنشاء الجدول داخله ( a_SchemaName ).

كود المصدر للعامل في الشكل
 SELECT tbl.oid,inxcls.relname,inxam.amname,inx.indisunique,inx.indisprimary, inx.indkey::SMALLINT[],inx.indoption::SMALLINT[],inxam.amcanorder FROM pg_index inx INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid INNER JOIN pg_namespace inxnsp ON inxcls.relnamespace=inxnsp.oid INNER JOIN pg_am inxam ON inxcls.relam=inxam.oid INNER JOIN pg_class tbl ON inx.indrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableOID) ORDER BY inxam.amname, inxcls.relname; 


وصف فهرس واحد هو مزيج من سجل في pg_class يصفه بأنه علاقة مادية وسجل في pg_index يحتوي على بيانات عن الخصائص المحددة للفهرس. بالإضافة إلى ذلك ، يتم تخزين المعلومات حول طرق الوصول إلى الفهرس في دليل نظام pg_am.


 CASE inxam.amcanorder WHEN true THEN CASE inx.indoption[inx.No] & 1 WHEN 1 THEN ' DESC' ELSE ' ASC' END ELSE '' END; 

سمة تفرد الفهرس ( indisunique ) ، إشارة إلى أن الفهرس تم إنشاؤه وفقًا لوصف المفتاح الأساسي (غير ضروري ) ، بالإضافة إلى صفائف الأرقام التسلسلية لسمات الجدول ، بناءً على القيم التي يتم استخراج الفهرس ( indkey ) وعلامات ترتيب فرز قيم السمات من إدخال فهرس pg_index ، في الفهرس ( indoption ).


من مدخل الكتالوج الذي يصف طريقة الوصول إلى فهرس pg_am ، يتم استخراج سمة ملاءمة البيانات التي تم فرزها المدرجة في الفهرس ( amcanorder ) واسم أو نوع طريقة الوصول إلى الفهرس ( amname ).

بمعنى آخر ، تشير السمة amcanorder إلى ما إذا كان من الممكن إنشاء ترتيب فرز لقيم السمات المضمنة في الفهرس. إذا كانت amcanorder = true ، فيمكن تحديد ترتيب الفرز ، وإلا فلا. من نفس الشكل ، يكون معنى قيم صفيف indoption مرئيًا - إذا كانت البتة اليمنى للصيغة الثنائية للقيمة تحتوي على 1B ، ثم يتم فرز قيمة السمة المقابلة بترتيب تنازلي ، وإلا - بترتيب تصاعدي.


يتم تكوين قوائم أسماء السمات المضمنة في الفهرس ، بالإضافة إلى علامات ترتيب قيم السمات ، داخل الدالة باستخدام دورة.



الجدول 9. نتيجة تنفيذ الوظيفة admtf_Table_Indexes ("public"، "Street").


نسخة النص من الجدول في الشكل
اسم الفهرسالطريقة؟؟؟ فريد؟؟؟ المفتاح الأساسيالسمات في الفهرس
xie1streetbtreeووwcrccode ASC و localityid ASC و streettypeacrm ASC و streetname ASC
xie2streebtreeووwcrccode ASC و localityid ASC و streetname ASC
xie3streetbtreeوواسم الشارع ASC
xie9streetbtreeووwcrccode ASC و localityid ASC و streetname DESC
xpkstreetbtreeررwcrccode ASC و localityid ASC و streetid ASC
xts1streetالجنووستريتسفيكتور
xts2streetالجنووستريتسفيكتور


إصدار بدون مؤشر


نهج إنشاء نسخة من دالة بدون مؤشر هو بالضبط نفس ما هو موضح في القسم السابق:


  • استنساخ السجلات باستخدام توليد_الاشتراكات ؛
  • تجميع السجلات اللاحقة ؛
  • إنشاء قائمة بسمات الفهرس باستخدام الدالة STRING_AGG مع خيار ORDER BY.


كود المصدر للعامل في الشكل
 SELECT inxcls.relname AS r_IndexName ,inxam.amname AS r_IndexType, inx.indisunique AS r_isUnique,inx.indisprimary AS r_isPrimary, STRING_AGG(attr.attname|| CASE inxam.amcanorder WHEN true THEN CASE inx.indoption[inx.No] & 1 WHEN 1 THEN ' DESC' ELSE ' ASC' END ELSE '' END, c_Delimiter ORDER BY inx.No) FROM (SELECT i.indrelid, i.indexrelid,i.indisunique,i.indisprimary, i.indkey::SMALLINT[],i.indoption::SMALLINT[], generate_subscripts(i.indkey, 1) as No FROM pg_index i) inx INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid INNER JOIN pg_am inxam ON inxcls.relam=inxam.oid INNER JOIN pg_class tbl ON inx.indrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute attr ON attr.attrelid=tbl.OID AND attr.attnum=inx.indkey[inx.No] WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) GROUP BY inxcls.relname,inxam.amname,inx.indisunique,inx.indisprimary ORDER BY inxcls.relname; 



تزامن وقت تنفيذ كلا الإصدارين من الدالات ، واستغرق الأمر 20 مللي ثانية لإخراج البيانات في جدول النتائج.


لذلك ، لن أنتج بعد الآن إصدارات دالة ، مثل بالنسبة لأولئك الذين يرغبون في إعادة تشكيلها كما يحلو لهم أو الاتصال بي ، سأرسل نسخة معدلة مجانًا .

انظر أيضًا الأجزاء الأولى والثالثة والرابعة من المقالة.



الملحق 1. النصوص



إنشاء وظيفة admtf_Table_Constraintes


يمكن العثور على التعليقات على رمز مصدر الوظيفة هنا.
رمز مصدر الوظيفة
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Constraintes (a_SchemaName NAME, a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Constraintes (a_SchemaName name default 'public', /*     */ a_TableName name default NULL /*   */ ) RETURNS TABLE (r_ConstraintName NAME,r_ConstraintType NAME,r_ConstraintKeyNames Text,r_RefTableName NAME,r_RefTableKeyNames Text,r_ConstraintSource Text) AS $BODY$ DECLARE v_Scale INTEGER; /*   */ v_ConstraintRec RECORD; /*   */ v_TableOID INTEGER; /* OID */ v_ConstraintOID INTEGER; /* OID */ v_ConstraintKeyNos SMALLINT[]; /* */ v_ConstraintName name; /*   */ v_ConstraintType name; /*     */ v_isUnique BOOLEAN; /*   */ v_isPrimary BOOLEAN; /*      Primary KEY */ v_AttributeNum INTEGER; /*   */ v_AttributeName name; /*  */ v_ConstraintKeyNames TEXT; /*     */ v_RefTableOID INTEGER; /* OID ,     */ v_RefTableName name;/*  ,     */ v_RefTableKeyNos SMALLINT[]; /* */ v_RefTableKeyNames TEXT; /*     ,    */ v_ConstraintSource TEXT; /*     CHECK*/ c_Delimiter CONSTANT VARCHAR(2):=','; --****************************************************************************************************** BEGIN FOR v_ConstraintRec IN SELECT con.oid AS ConstraintOID ,tbl.OID AS TableOID, con.conname AS ConstraintName, con.contype AS ConstraintType, con.conkey AS ConstraintKeyNos, reftbl.OID AS RefTableOID, reftbl.relname AS RefTableName, con.confkey AS RefTableKeyNos, con.consrc AS ConstraintSource FROM pg_constraint con INNER JOIN pg_class tbl ON con.conrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid LEFT OUTER JOIN pg_class reftbl ON con.confrelid=reftbl.oid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) ORDER BY con.contype DESC,con.conname LOOP v_ConstraintOID:=v_ConstraintRec.ConstraintOID; v_TableOID:=v_ConstraintRec.TableOID; v_ConstraintName:=v_ConstraintRec.ConstraintName; v_ConstraintType:=v_ConstraintRec.ConstraintType; v_ConstraintKeyNos:=v_ConstraintRec.ConstraintKeyNos; v_RefTableOID:=v_ConstraintRec.RefTableOID; v_RefTableName:=v_ConstraintRec.RefTableName; v_RefTableKeyNos:=v_ConstraintRec.RefTableKeyNos; v_ConstraintSource:=v_ConstraintRec.ConstraintSource; v_ConstraintKeyNames:=''; FOREACH v_AttributeNum IN ARRAY v_ConstraintKeyNos LOOP SELECT INTO v_AttributeName attr.attname::VARCHAR(100) AS r_AttributeName FROM pg_attribute attr WHERE attr.attrelid=v_TableOID AND attr.attnum=v_AttributeNum; v_ConstraintKeyNames:=v_ConstraintKeyNames|| CASE WHEN v_ConstraintKeyNames='' THEN '' ELSE c_Delimiter END ||v_AttributeName; END LOOP; v_RefTableKeyNames:=''; IF v_RefTableKeyNos IS NOT NULL THEN FOREACH v_AttributeNum IN ARRAY v_RefTableKeyNos LOOP SELECT INTO v_AttributeName attr.attname::VARCHAR(100) AS r_AttributeName FROM pg_attribute attr WHERE attr.attrelid=v_RefTableOID AND attr.attnum=v_AttributeNum; v_RefTableKeyNames:=v_RefTableKeyNames|| CASE WHEN v_RefTableKeyNames='' THEN '' ELSE c_Delimiter END ||v_AttributeName; END LOOP; END IF; RETURN QUERY SELECT v_ConstraintName,v_ConstraintType,v_ConstraintKeyNames, v_RefTableName,v_RefTableKeyNames, v_ConstraintSource; END LOOP; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Constraintes(a_SchemaName NAME, a_TableName NAME) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Constraintes (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Constraintes (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_ConstraintName VARCHAR(256),r_ConstraintType VARCHAR(256),r_ConstraintKeyNames Text,r_RefTableName VARCHAR(256),r_RefTableKeyNames Text,r_ConstraintSource Text) AS $BODY$ DECLARE --****************************************************************************************************** BEGIN RETURN QUERY SELECT tc.r_ConstraintName::VARCHAR(256), tc.r_ConstraintType::VARCHAR(256),tc.r_ConstraintKeyNames::TEXT, tc.r_RefTableName::VARCHAR(256),tc.r_RefTableKeyNames::TEXT, tc.r_ConstraintSource::TEXT FROM admtf_Table_Constraintes(a_SchemaName::NAME,a_TableName::NAME) tc; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Constraintes(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Constraintes('public'::VARCHAR(256),'Street'::VARCHAR(256)); SELECT * FROM admtf_Table_Constraintes('public'::name,'Street'::name); 



إنشاء نسخة من admtf_Table_Constraintes بدون مؤشر


يمكن العثور على التعليقات على رمز مصدر الوظيفة هنا.
رمز مصدر الوظيفة
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Constraintes (a_SchemaName NAME, a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Constraintes (a_SchemaName name default 'public', /*     */ a_TableName name default NULL /*   */ ) RETURNS TABLE (r_ConstraintName NAME,r_ConstraintType NAME,r_ConstraintKeyNames Text,r_RefTableName NAME,r_RefTableKeyNames Text,r_ConstraintSource Text) AS $BODY$ DECLARE v_Scale INTEGER; /*   */ v_ConstraintRec RECORD; /*   */ v_TableOID INTEGER; /* OID */ v_ConstraintOID INTEGER; /* OID */ v_ConstraintKeyNos SMALLINT[]; /* */ v_ConstraintName name; /*   */ v_ConstraintType name; /*     */ v_isUnique BOOLEAN; /*   */ v_isPrimary BOOLEAN;/*      Primary KEY */ v_AttributeNum INTEGER; /*   */ v_AttributeName name; /*  */ v_ConstraintKeyNames TEXT; /*     */ v_RefTableOID INTEGER; /* OID ,     */ v_RefTableName name;/*  ,     */ v_RefTableKeyNos SMALLINT[]; /* */ v_RefTableKeyNames TEXT;/*     ,    */ v_ConstraintSource TEXT; /*     CHECK*/ c_Delimiter CONSTANT VARCHAR(2):=','; --****************************************************************************************************** BEGIN FOR v_ConstraintRec IN SELECT con.oid AS ConstraintOID , tbl.OID AS TableOID, con.conname AS ConstraintName, con.contype AS ConstraintType, con.conkey AS ConstraintKeyNos, reftbl.OID AS RefTableOID, reftbl.relname AS RefTableName, con.confkey AS RefTableKeyNos, con.consrc AS ConstraintSource FROM pg_constraint con INNER JOIN pg_class tbl ON con.conrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid LEFT OUTER JOIN pg_class reftbl ON con.confrelid=reftbl.oid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) ORDER BY con.contype DESC,con.conname LOOP v_ConstraintOID:=v_ConstraintRec.ConstraintOID; v_TableOID:=v_ConstraintRec.TableOID; v_ConstraintName:=v_ConstraintRec.ConstraintName; v_ConstraintType:=v_ConstraintRec.ConstraintType; v_ConstraintKeyNos:=v_ConstraintRec.ConstraintKeyNos; v_RefTableOID:=v_ConstraintRec.RefTableOID; v_RefTableName:=v_ConstraintRec.RefTableName; v_RefTableKeyNos:=v_ConstraintRec.RefTableKeyNos; v_ConstraintSource:=v_ConstraintRec.ConstraintSource; v_ConstraintKeyNames:=''; FOREACH v_AttributeNum IN ARRAY v_ConstraintKeyNos LOOP SELECT INTO v_AttributeName attr.attname::VARCHAR(100) AS r_AttributeName FROM pg_attribute attr WHERE attr.attrelid=v_TableOID AND attr.attnum=v_AttributeNum; v_ConstraintKeyNames:=v_ConstraintKeyNames|| CASE WHEN v_ConstraintKeyNames='' THEN '' ELSE c_Delimiter END ||v_AttributeName; END LOOP; v_RefTableKeyNames:=''; IF v_RefTableKeyNos IS NOT NULL THEN FOREACH v_AttributeNum IN ARRAY v_RefTableKeyNos LOOP SELECT INTO v_AttributeName attr.attname::VARCHAR(100) AS r_AttributeName FROM pg_attribute attr WHERE attr.attrelid=v_RefTableOID AND attr.attnum=v_AttributeNum; v_RefTableKeyNames:=v_RefTableKeyNames|| CASE WHEN v_RefTableKeyNames='' THEN '' ELSE c_Delimiter END ||v_AttributeName; END LOOP; END IF; RETURN QUERY SELECT v_ConstraintName,v_ConstraintType,v_ConstraintKeyNames, v_RefTableName,v_RefTableKeyNames, v_ConstraintSource; END LOOP; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Constraintes(a_SchemaName NAME, a_TableName NAME) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Constraintes (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Constraintes (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_ConstraintName VARCHAR(256),r_ConstraintType VARCHAR(256),r_ConstraintKeyNames Text,r_RefTableName VARCHAR(256),r_RefTableKeyNames Text,r_ConstraintSource Text) AS $BODY$ DECLARE --****************************************************************************************************** BEGIN RETURN QUERY SELECT tc.r_ConstraintName::VARCHAR(256), tc.r_ConstraintType::VARCHAR(256), tc.r_ConstraintKeyNames::TEXT, tc.r_RefTableName::VARCHAR(256), tc.r_RefTableKeyNames::TEXT, tc.r_ConstraintSource::TEXT FROM admtf_Table_Constraintes(a_SchemaName::NAME,a_TableName::NAME) tc; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Constraintes(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Constraintes('public'::VARCHAR(256),'Street'::VARCHAR(256)); SELECT * FROM admtf_Table_Constraintes('public'::name,'Street'::name); 



إنشاء دالة admtf_Table_Indexes


يمكن العثور على التعليقات على رمز مصدر الوظيفة هنا.
رمز مصدر الوظيفة
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Indexes (a_SchemaName NAME, a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Indexes (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_IndexName NAME,r_IndexType NAME,r_isUnique BOOLEAN,r_isPrimary BOOLEAN, r_IndexKeyNames Text) AS $BODY$ DECLARE c_IndexKind CONSTANT CHAR:='i'; v_IndexRec RECORD; /*   */ v_Scale INTEGER; /*   */ v_TableOID INTEGER; /* OID */ v_IndexOID INTEGER; /* OID */ v_IndexKeyNos SMALLINT[]; /* */ v_IndexName NAME; /*   */ v_IndexAMName NAME; /*    ( ) */ v_isUnique BOOLEAN; /*   */ v_isPrimary BOOLEAN; /*      Primary KEY */ v_AttributeNum INTEGER; /*   */ v_AttributeName NAME; /*  */ v_IndexKeyNames TEXT; /*     */ c_Delimiter CONSTANT VARCHAR(2):=','; --****************************************************************************************************** BEGIN FOR v_IndexRec IN SELECT inxcls.oid AS IndexOID,tbl.oid AS TableOID, inxcls.relname AS IndexName,inxam.amname AS IndexAMName, inx.indisunique AS isUnique,inx.indisprimary isPrimary, inx.indkey::SMALLINT[] AS IndexKeyNos FROM pg_index inx INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid INNER JOIN pg_am inxam ON inxcls.relam=inxam.oid INNER JOIN pg_class tbl ON inx.indrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND inxcls.relkind=c_IndexKind AND tbl.relname=LOWER(a_TableName) ORDER BY inxam.amname, inxcls.relname LOOP v_IndexOID:=v_IndexRec.IndexOID; v_TableOID:=v_IndexRec.TableOID; v_IndexName:=v_IndexRec.IndexName; v_IndexAMName:=v_IndexRec.IndexAMName; v_isUnique:=v_IndexRec.isUnique; v_isPrimary:=v_IndexRec.isPrimary; v_IndexKeyNos:=v_IndexRec.IndexKeyNos; v_IndexKeyNames:=''; FOREACH v_AttributeNum IN ARRAY v_IndexKeyNos LOOP SELECT INTO v_AttributeName attr.attname::VARCHAR(100) AS r_AttributeName FROM pg_attribute attr WHERE attr.attrelid=v_TableOID AND attr.attnum=v_AttributeNum; v_IndexKeyNames:=v_IndexKeyNames|| CASE WHEN v_IndexKeyNames='' THEN '' ELSE c_Delimiter||' ' END || v_AttributeName; END LOOP; RETURN QUERY SELECT v_IndexName,v_IndexAMName,v_isUnique, v_isPrimary,v_IndexKeyNames; END LOOP; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Indexes(a_SchemaName NAME, a_TableName NAME) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Indexes (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Indexes (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_IndexName VARCHAR(256),r_IndexType VARCHAR(256),r_isUnique BOOLEAN,r_isPrimary BOOLEAN, r_IndexKeyNames TEXT) AS $BODY$ DECLARE --****************************************************************************************************** BEGIN RETURN QUERY SELECT ti.r_IndexName::VARCHAR(256), ti.r_IndexType::VARCHAR(256), ti.r_isUnique::BOOLEAN, ti.r_isPrimary::BOOLEAN, ti.r_IndexKeyNames::TEXT FROM admtf_Table_Indexes(a_SchemaName::NAME,a_TableName::NAME) ti; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Indexes(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Indexes('public'::NAME,'Street'::NAME); SELECT * FROM admtf_Table_Indexes('public'::VARCHAR(256),'Street'::VARCHAR(256)); 



إنشاء نسخة من admtf_Table_Indexes بدون مؤشر


.
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Indexes (a_SchemaName NAME, a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Indexes (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_IndexName NAME,r_IndexType NAME,r_isUnique BOOLEAN,r_isPrimary BOOLEAN, r_IndexKeyNames Text) AS $BODY$ DECLARE c_IndexKind CONSTANT CHAR:='i'; c_Delimiter CONSTANT VARCHAR(2):=', '; --****************************************************************************************************** BEGIN RETURN QUERY SELECT inxcls.relname AS r_IndexName, inxam.amname AS r_IndexType, inx.indisunique AS r_isUnique, inx.indisprimary r_isPrimary, STRING_AGG(attr.attname||CASE inxam.amcanorder WHEN true THEN CASE inx.indoption[inx.No] & 1 WHEN 1 THEN ' DESC' ELSE ' ASC' END ELSE '' END, c_Delimiter ORDER BY inx.No) FROM (SELECT i.indrelid, i.indexrelid,i.indisunique, i.indisprimary,i.indkey::SMALLINT[], i.indoption::SMALLINT[], generate_subscripts(i.indkey, 1) as No FROM pg_index i) inx INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid INNER JOIN pg_am inxam ON inxcls.relam=inxam.oid INNER JOIN pg_class tbl ON inx.indrelid=tbl.oid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid INNER JOIN pg_attribute attr ON attr.attrelid=tbl.OID AND attr.attnum=inx.indkey[inx.No] WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND inxcls.relkind=c_IndexKind AND tbl.relname=LOWER(a_TableName) GROUP BY inxcls.relname,inxam.amname,inx.indisunique,inx.indisprimary ORDER BY inxcls.relname; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Indexes(a_SchemaName NAME, a_TableName NAME) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Indexes (a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Indexes (a_SchemaName VARCHAR(256) default 'public', /*    */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_IndexName VARCHAR(256),r_IndexType VARCHAR(256),r_isUnique BOOLEAN,r_isPrimary BOOLEAN, r_IndexKeyNames TEXT) AS $BODY$ DECLARE --****************************************************************************************************** BEGIN RETURN QUERY SELECT ti.r_IndexName::VARCHAR(256), ti.r_IndexType::VARCHAR(256), ti.r_isUnique::BOOLEAN, ti.r_isPrimary::BOOLEAN, ti.r_IndexKeyNames::TEXT FROM admtf_Table_Indexes(a_SchemaName::NAME,a_TableName::NAME) ti; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Indexes(a_SchemaName VARCHAR(256), a_TableName VARCHAR(256)) IS '    '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Indexes('public'::NAME,'Street'::NAME); SELECT * FROM admtf_Table_Indexes('public'::VARCHAR(256),'Street'::VARCHAR(256)); 


انظر أيضًا


PostgreSQL. ;
PostgreSQL. .
PostgreSQL. ( ) .

Source: https://habr.com/ru/post/ar415897/


All Articles