Функции для документирования баз данных PostgreSQL. Окончание

    Это четвертая и последняя часть статьи, которая описывает пользовательские функции для работы с системными каталогами: pg_class, pg_attribute, pg_constraints и т.д. Первая, вторая и третья части статьи опубликованы ранее.


    Предчувствую, что должен заранее извиниться перед теми из читателей, кого интересовали только устройство системных каталогов PostgrSQL, а также приемы извлечения данных из них. Функции, которые описываются в этой части статьи, не обращаются к еще не рассмотренным системным каталогам, да и приемы извлечения данных ничем не отличаются от тех, что изложены в предыдущих частях. Такие читатели могут завершить просмотр статьи прямо здесь.



    Всем тем, кто решил продолжить чтение, сообщаю, что в этой части статьи рассматриваются функции, возвращающие расширенные характеристики первичных и внешних ключей, а также индексов таблиц. И конечно приведено краткое описание и код функции admtf_Table_ComplexFeatures, которая была заявлена как цель публикации в первой части статьи.


    В первой половине статьи изложены комментарии к реализации функций. Во второй- исходные тексты функций. Тем из читателей, кого интересуют только исходные тексты, предлагаем сразу перейти к Приложению.

    Структура функции, возвращающей список характеристик первичного ключа таблицы



    Рис. 4. Функции, которые вызывает admtf_PrimaryKey_ComplexFeatures.
    Таблица 20. Назначение функций.



    Текстовая версия таблицы на рисунке
    Название Назначение
    1 admtf_PrimaryKey_Features Функция возвращает характеристики первичного ключа (PRIMARY KEY) таблицы
    2 admtf_PrimaryKey_Attributes Функция возвращает список атрибутов первичного ключа (PRIMARY KEY) и их характеристик.
    3 admtf_PrimaryKey_ComplexFeatures Функция возвращает характеристики первичного ключа (PRIMARY KEY) таблицы, а также список составляющих ключ атрибутов.



    Функция admtf_PrimaryKey_ComplexFeatures – комплексный список характеристик первичного ключа таблицы


    Таблица 21. Результат выполнения функции admtf_PrimaryKey_ComplexFeatures ('public',' xpkstreet').



    Текстовая версия таблицы на рисунке
    Категория Название Комментарий тип Базовый тип ? not NULL
    pkl 0 xpkstreet Первичный ключ таблицы street
    pkatt 1 wcrccode Код страны wcrccode smallint t
    pkatt 2 localityid ИД населенного пункта localityid integer t
    pkatt 3 streetid ИД улицы населенного пункта streetid smallint t


    В качестве обязательных параметров функция принимает название первичного ключа (a_PrimaryKeyName) и название схемы, в пределах которой создана таблица (a_SchemaName). Код функции представляет собой последовательный вызов двух табличных функций.


    Исходный код можно посмотреть и скачать здесь.



    Первая функция (admtf_PrimaryKey_Features) подготавливает и выполняет SELECT, возвращающий характеристики первичного ключа.





    исходный код оператора на рисунке
    SELECT con.conname, 
                  COALESCE(dsc.description,'Первичный ключ таблицы '|| tbl.relname) 
                FROM pg_constraint con 
                    INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
                    INNER JOIN pg_class tbl ON con.conrelid=tbl.oid
                    LEFT OUTER JOIN pg_Description dsc ON con.oid=dsc.objoid
                                                    AND dsc.objsubid=0 
               WHERE con.contype ='p' AND nspc.nspname=LOWER(a_SchemaName)
                   AND con.conname =LOWER(a_PrimaryKeyName);
    
    



    Вторая функция (admtf_PrimaryKey_Attributes) возвращает характеристики атрибутов, составляющих первичный ключ.





    исходный код оператора на рисунке
    SELECT (rank() OVER (PARTITION BY con.conrelid ORDER BY con.No)) ::SMALLINT,
          attr.attnum,attr.attname::NAME,
          CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::VARCHAR(100) ELSE '' END,
          FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                     COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::VARCHAR(256),
           attr.attnotnull
        FROM (SELECT c.oid, c.conrelid,c.connamespace,c.confrelid,c.conname, c.contype,
                          c.conkey::SMALLINT[],generate_subscripts(c.conkey, 1) as No 
                     FROM pg_constraint c) con
                        INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid
                         INNER JOIN pg_attribute attr ON attr.attrelid=con.conrelid
                                AND attr.attnum=con.conkey[con.No]
                         LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid
                         LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
        WHERE con.contype ='p' AND nspc.nspname=LOWER(a_SchemaName)
                               AND con.conname =LOWER(a_PrimaryKeyName)
        ORDER BY con.No;
    


    Здесь следует обратить внимание на порядок вывода записей об атрибутах первичного ключа. Они выводятся в порядке описания в первичном ключе (con.No), а не в порядке их описания в таблице (attr.attnum).


    Особенности соединения записей, используемых системных каталогов, подробно рассмотрены в разделе «Функция admtf_Table_Constraintes список ограничений таблицы базы данных и их характеристик».


    Структура функции, возвращающей список характеристик внешнего ключа таблицы



    Рис. 5. Функции, которые вызывает admtf_ForeignKey_ComplexFeatures.

    Таблица 22. Назначение функций.



    Текстовая версия таблицы на рисунке
    Название Назначение
    1 admtf_ ForeignKey _Features Функция возвращает характеристики внешнего ключа (FOREIGN KEY) таблицы.
    2 admtf_ ForeignKey_Attributes Функция возвращает список атрибутов внешнего ключа таблицы и их характеристик.
    3 admtf_ForeignKey_ReferenceTableFeatures Функция возвращает список характеристик таблицы базы данных, на которую ссылается внешний ключ.
    4 admtf_ForeignKey_ReferenceTableAttributes Функция возвращает список атрибутов таблицы базы данных, на которую ссылается внешний ключ, и их характеристик.
    5 admtf_ForeignKey_ReferenceTableComplexFeatures Функция возвращает полный (расширенный) список характеристик таблицы базы данных, на которую ссылается внешний ключ.
    6 admtf_ForeignKey_ComplexFeatures Функция возвращает характеристики внешнего ключа (FOREIGN KEY) таблицы, а также список атрибутов, включенных в индекс.


    Функция admtf_ForeignKey_ComplexFeatures – комплексный список характеристик внешнего ключа таблицы


    Функции admtf_ForeignKey_ComplexFeatures возвращает список следующих характеристик внешнего ключа таблицы.


    <strongТаблица 23. Результат выполнения функции admtf_ForeignKey_ComplexFeatures ('public','fk_street_locality',3).



    Текстовая версия таблицы на рисунке
    Категория Название Комментарий тип Базовый тип ? not NULL
    fk03 3 fk_street_locality Внешний ключ таблицы street
    fk03att 1 wcrccode Код страны wcrccode smallint t
    fk03att 2 localityid ИД населенного пункта localityid integer t
    fk03rtbl 0 locality Список населенных пунктов
    fk03ratt 1 wcrccode Код страны wcrccode smallint t
    fk03ratt 2 localityid ИД населенного пункта localityid integer t


    В качестве параметров функция принимает название внешнего ключа (a_ ForeignKey) и название схемы, в пределах которой создан внешний ключ (a_SchemaName).


    Исходный код можно посмотреть и скачать здесь.


    У функции есть еще одни необязательный параметр — порядковый номер индекса таблицы (a_ForeignKeyNo). Этот параметр нужен для того, чтобы в значения категории добавлять порядковый номер внешнего ключа таблицы. В частности, в приведенном примере функция выполнялась со значением этого параметра равным 3. Поэтому запись с характеристиками внешнего ключа помечена значением «fk03», записи с характеристиками атрибутов — «fk03att», запись о внешней таблице — «fk03rtbl», а записи об атрибутах внешней таблицы — «fk03ratt». Если при вызове функции опустить этот параметр, то значения категорий в записях были бы «fk», «fkatt», «fkrtbl» и «fkratt» соответственно. По этой же причине значение категории формируется внутри функции admtf_ForeignKey_ComplexFeatures, а не в коде вызывающей ее функции.


    Подробнее смотри в разделе «О каких расширенных характеристиках идет речь?»

    .

    Код функция представляет собой последовательный вызов трех табличных функций.



    Первая функция (admtf_ForeignKey_Features) подготавливает и выполняет SELECT, возвращающий характеристики внешнего ключа.





    исходный код оператора на рисунке
    SELECT con.conname, COALESCE(dsc.description,'Внешний ключ таблицы '|| tbl.relname)  
        FROM pg_constraint con 
                   INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
                   INNER JOIN pg_class tbl ON con.conrelid=tbl.oid
                   LEFT OUTER JOIN pg_Description dsc ON con.oid=dsc.objoid AND dsc.objsubid=0
        WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype='f'
    					AND con.conname =LOWER(a_ForeignKeyName);
    
    



    Вторая функция (admtf_ForeignKey_Attributes) возвращает характеристики атрибутов внешнего ключа.


    Здесь следует обратить внимание на порядок вывода записей об атрибутах внешнего ключа. Они выводятся в порядке описания во внешнем ключе (con.No), а не в порядке их описания в таблице (attr.attnum).


    Особенности соединения записей, используемых системных каталогов, подробно рассмотрены в разделе «Функция admtf_Table_Constraintes — список ограничений таблицы базы данных и их характеристик».



    исходный код оператора на рисунке
    SELECT (rank() OVER (PARTITION BY con.conrelid ORDER BY con.No))::SMALLINT AS r_ForeingKeyNo,
                   attr.attnum AS r_AttributeNumber,attr.attname::NAME AS r_AttributeName,
                  CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME ELSE '' END AS r_UserTypeName,
                  FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME AS r_TypeName,
                  attr.attnotnull AS r_isNotNULL,TRIM(dsc.description) AS r_Description 
        FROM (SELECT c.oid, c.conrelid,c.confrelid,c.conname,c.connamespace,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_namespace nspc ON con.connamespace = nspc.oid
                   INNER JOIN pg_attribute attr ON attr.attrelid=con.conrelid AND attr.attnum=con.conkey[con.No]
                   INNER JOIN  pg_type typ ON attr.atttypid=typ.oid
                   LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
                   LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum
        WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype ='f' AND con.conname =LOWER(a_ForeignKeyName)
        ORDER BY con.No;	
    


    Третья функция (admtf_ForeignKey_ReferenceTableComplexFeatures) возвращает характеристики таблицы, на которую ссылается внешний ключ. Для решения своей задачи она последовательно вызывает две дополнительные функции.



    Функция admtf_ForeignKey_ReferenceTableComplexFeatures – комплексный список характеристик таблицы, на которую ссылается внешний ключ


    В качестве параметров функция принимает название внешнего ключа (a_ForeignKey) и название схемы, в пределах которой создан внешний ключ (a_SchemaName).


    У функции есть еще одни необязательный параметр — порядковый номер индекса таблицы (a_ForeignKeyNo). Этот параметр нужен для того, чтобы в значениях категории замещать порядковым номером символ '%' в «fk%rtbl» и «fk%ratt» соответственно.


    Функция последовательно вызывает две дополнительные функции.



    Первая admtf_ForeignKey_ReferenceTableFeatures возвращает непосредственно характеристики таблицы, на которую ссылается внешний ключ, и представляет собой упрощенную версию функции admtf_Table_Features.



    Вторая admtf_ForeignKey_ReferenceTableAttributes – характеристики атрибутов внешней таблицы, соответствующие атрибутам внешнего ключа. Она почти полностью повторяет код функции admtf_ForeignKey_Attributes. Только в некоторых местах вместо идентификатора con.conrelid используется con.confrelid, и вместо массива con.conkey используется con.confkey.





    исходный код оператора на рисунке
    SELECT (rank() OVER (PARTITION BY con.confrelid ORDER BY con.No))::SMALLINT,
                   attr.attnum AS r_AttributeNumber,attr.attname::NAME AS r_AttributeName,
                   CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME ELSE ''END,
                   FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                                     COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME,
                   attr.attnotnull AS r_isNotNULL,TRIM(dsc.description) AS r_Description 
        FROM (SELECT c.oid, c.conrelid,c.confrelid,c.conname,c.connamespace,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_namespace nspc ON con.connamespace = nspc.oid
              INNER JOIN pg_attribute attr ON attr.attrelid=con.confrelid 
                               AND attr.attnum=con.confkey[con.No]
              INNER JOIN  pg_type typ ON attr.atttypid=typ.oid
              LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
              LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid 
                               AND dsc.objsubid=attr.attnum
        WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype ='f' 
                              AND con.conname =LOWER(a_ForeignKeyName)
        ORDER BY con.No;	
    



    Структура функции, возвращающей список характеристик индекса таблицы



    Рис. 6. Функции, которые вызывает admtf_Index_ComplexFeatures.

    Таблица 24. Назначение функций.



    Текстовая версия таблицы на рисунке
    Название Назначение
    1 admtf_Index_Features Функция возвращает характеристики индекса таблицы.
    2 admtf_Index_Attributes Функция возвращает список атрибутов таблицы, включенных в индекс, и их характеристик.
    3 admtf_Index_ComplexFeatures Функция возвращает характеристики индекса таблицы, а также список атрибутов, включенных в индекс.


    Функция admtf_Index_ComplexFeatures – комплексный список характеристик индекса таблицы


    Функции admtf_Index_ComplexFeatures возвращает список следующих характеристик индекса таблицы.



    Таблица 25. Результат выполнения функции admtf_Index_ComplexFeatures ('public','xie9street',7).



    Текстовая версия таблицы на рисунке
    Категория Название Порядок Комментарий тип Базовый тип ? not NULL
    idx07 7 xie9street Индекс по названию улицы населенного пункта в убывающем порядке
    idx07att 1 wcrccode ASC Код страны wcrccode smallint t
    idx07att 2 localityid ASC ИД населенного пункта localityid integer t
    idx07att 3 streetname DESC Наименование улицы населенного пункта VARCHAR(150) t


    В качестве параметров функция принимает название индекса (a_ Index) и название схемы, в пределах которой создан индекс (a_SchemaName).


    Исходный код можно посмотреть и скачать здесь.


    У функции есть еще одни необязательный параметр — порядковый номер индекса таблицы (a_IndexNo). Этот параметр нужен для того, чтобы в значения категории добавлять порядковый номер индекса таблицы. В частности, в приведенном примере функция выполнялась со значением этого параметра равным 7. Поэтому запись с характеристиками индекса помечена значением «idx07», а записи с характеристиками атрибутов — «idx07att». Если при вызове функции опустить этот параметр, то значения категорий в записях были бы «idx» и «idxatt» соответственно.


    Подробнее смотри в разделе «О каких расширенных характеристиках идет речь?». По этой же причине значение категории формируется внутри функции admtf_Index_ComplexFeatures, а не в коде вызывающей ее функции.


    Код функции представляет собой последовательный вызов двух табличных функций.



    Первая функция (admtf_Index_Features) подготавливает и выполняет SELECT, возвращающий характеристики индекса.





    исходный код оператора на рисунке
    SELECT inxcls.relname, 
          CASE WHEN COALESCE(TRIM(dsc.description),'')='' THEN 
              'Индекс'  || CASE WHEN inx.indisunique THEN ' уникальный' 
              || CASE WHEN inx.indisprimary THEN '(первичный ключ)' ELSE '' END ELSE '' END
              ||CASE WHEN inxam.amname='gist' THEN ' пространственный' ELSE '' END ||' таблицы '
              ||tbl.relname
                    ELSE dsc.description END	
         FROM pg_index inx 
                    INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid
                    INNER JOIN pg_namespace nsp ON inxcls.relnamespace=nsp.oid 
                    LEFT OUTER JOIN pg_Description dsc ON inxcls.oid=dsc.objoid
                                                    AND dsc.objsubid=0 
                    LEFT OUTER JOIN pg_am inxam ON inxcls.relam=inxam.oid
                    LEFT OUTER JOIN pg_class tbl ON inx.indrelid=tbl.oid
         WHERE inxcls.relkind='i' AND nsp.nspname =LOWER(a_SchemaName)
                   AND inxcls.relname=LOWER(a_IndexName);
    



    Вторая функция (admtf_ Index_Attributes) возвращает характеристики атрибутов, включенных в состав индекса. Обратите внимание, что порядок записей об атрибутах определяется порядком их описания в индексе (inx.No), а не порядком физического следования в таблице (attr.attnum).





    исходный код оператора на рисунке
    SELECT (inx.No+1)::SMALLINT,attr.attnum::SMALLINT, attr.attname::NAME,
                  CASE WHEN NOT inxam.amcanorder THEN NULL 
                                              ELSE 
                  CASE WHEN inx.indoption[inx.No] & 1=1 THEN 'DESC'
                                               ELSE 'ASC' END END::VARCHAR(10),
                  CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME ELSE '' END,
                  FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                                   COALESCE(NULLIF(typ.typtypmod,-),attr.atttypmod))::NAME,
                  attr.attnotnull,dsc.description 
        FROM (SELECT i.indrelid, i.indexrelid,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_namespace nsp ON inxcls.relnamespace=nsp.oid 
               LEFT OUTER JOIN pg_am inxam ON inxcls.relam=inxam.oid
               LEFT OUTER JOIN pg_class tbl ON inx.indrelid=tbl.oid
               INNER JOIN pg_attribute attr ON attr.attrelid=tbl.oid AND attr.attnum=inx.indkey[inx.No]
               LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid
               LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
               LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid
                                              AND dsc.objsubid=attr.attnum
        WHERE nsp.nspname=LOWER(a_SchemaName) AND inxcls.relkind='i'
                                               AND inxcls.relname =LOWER(a_IndexName)
        ORDER BY nsp.nspname,inxcls.relname,inx.No;
    


    Особенности соединения записей, используемых системных каталогов, подробно рассмотрены в разделе «Функция admtf_Table_Indexes список индексов таблицы базы данных и их характеристик.


    Создание функции admtf_Table_ComplexFeatures


    Функция admtf_Table_ComplexFeatures возвращает комплексный список характеристик таблицы базы данных, который включает в себя характеристики, возвращаемые описанными в статье функциями. В качестве параметров функция принимает название исходной таблицы (a_TableName) и название схемы, в пределах которой создана таблица (a_SchemaName).


    Исходный код можно посмотреть и скачать здесь.



    Таблица 26. Результат выполнения функции admtf_Table_ComplexFeatures('public', 'street').



    Текстовая версия таблицы на рисунке
    Категория Название Комментарий тип Базовый тип ? not NULL
    tbl 0 street Список улиц в населенных пунктах
    att 1 wcrccode Код страны wcrccode smallint t
    att 2 localityid ИД населенного пункта localityid integer t
    att 3 streetid ИД улицы населенного пункта streetid smallint t
    att 4 streettypeacrm Акроним типа улицы streettypeacrm character(8) f
    att 5 streetname Наименование улицы streettypeacrm varchar(150) t
    pk 0 xpkstreet Первичный ключ таблицы street
    pkatt 1 wcrccode Код страны wcrccode smallint t
    fk01 1 fk_street_locality Внешний ключ таблицы
    fk02 2 fk_street_streettype Внешний ключ таблицы
    idx01 1 xie1street Индекс по типу и названию улицы населенного пункта
    idx02 2 xie2street Индекс по названию улицы населенного пункта
    idx03 3 xie3street Индекс по названиям улиц всех населенных пунктов
    idx04 4 xpkstreet Индекс уникальный (первичный ключ) таблицы street


    В процессе своего выполнения функция последовательно вызывает 9 дополнительных функций, список которых приведен в разделе «Структура головной функции».


    Совместное выполнение головной и дополнительных функций приводит в результате к созданию таблицы с расширенными характеристиками таблицы.



    Где использовались функции?


    leftОписанные в статье функции были созданы в процессе подготовки заявки на государственную регистрацию базы данных. Порядок подачи заявки и требования ее оформлению изложены в документе «Правила оформления заявки на государственную регистрацию программы для электронных вычислительных машин или базы данных», утвержденном приказом Минэкономразвития России от 5 апреля 2016 года N 211 (далее Правила).


    Обязательной частью заявки является документ «Материалы, идентифицирующие базу данных». Правила трактуют содержание этого документа следующим образом.

    «Материалы, идентифицирующие базу данных, должны отражать объективную форму представления совокупности содержащихся в ней самостоятельных материалов в виде примеров реального наполнения и принципы их систематизации (структуру базы данных), позволяющие осуществить нахождение и обработку этих материалов с помощью ЭВМ.»

    Другими словами, документ должен содержать описание структуры базы данных и примеры ее реального наполнения.





    Как видно из рисунка, при подготовке заявки на регистрацию базы данных использовались не только функции, описанные в этой статье. Дополнительно были созданы 3- 4 функции для преобразования описаний таблиц базы данных в формат PlantUML.Точнее, эти функции создают код в формате плагина для системы управления проектами TRAC, поэтому если вам захочется проверить созданный этими функциями код, то не забудьте убрать две строчки сверху перед @startuml и все строчки снизу после @enduml.



    Созданный при помощи функций код PlantUML скрипта
    {{{
    #!plantuml
    @startuml
    object public.ID_DISTRICTS{
    id_np : integer NOT NULL (PK1)(FK1 id_nps(id_np))
    id_district : integer NOT NULL (PK2)
    name_district : character varying(25) NULL 
    type_district : character varying(25) NULL 
    okato : character varying(11) NULL 
    oktmo : character varying(11) NULL 
    }
    object public.ID_NPS{
    id_region : integer NOT NULL (FK1 id_regions(id_region))
    id_atu : integer NULL (FK1 id_rayons(id_atu))
    id_selsov : integer NULL (FK1 id_selsovs(id_selsov))
    id_np : integer NOT NULL (PK1)
    name_np : character varying(25) NULL 
    type_np : character varying(25) NULL (FK1 type_np(scname))
    okato : character varying(11) NULL 
    oktmo : character varying(11) NULL 
    }
    public.ID_DISTRICTS *-- public.ID_NPS
    legend center
    <b><i><u>ТАБЛИЦЫ</u></i></b>
     
    <b>ID_DISTRICTS</b>- Справочник - список городских районов 
    <b>ID_NPS</b>- Справочник - список населенных пунктов 
    endlegend
    @enduml
    }}}
     
    ----
    
    


    P.S. Почему здесь не приведены дополнительные функции преобразования описания таблиц базы данных в формат плагина PlantUML для системы управления проектами TRAC? Во-первых, они не вписывались в заявленную тему. Во-вторых, похоже, я утомил читателей текстами функций. Но если кто-то заинтересуется этими функциями, то пишите мне, и я вышлю их тексты.


    Смотрите также
    Функции для документирования баз данных PostgreSQL. Часть первая;
    Функции для документирования баз данных PostgreSQL. Часть вторая;
    Функции для документирования баз данных PostgreSQL. Часть третья.

    ПРИЛОЖЕНИЕ 1. Скрипты


    Создание функции admtf_PrimaryKey_ComplexFeatures


    Комментарии к исходному коду функции можно посмотреть здесь.
    код функции

    Создание функции admtf_PrimaryKey_Features


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_Features (a_SchemaName NAME,a_PrimaryKeyName NAME);
    /******************************************************************************/
    /*  Функция возвращает список характеристик первичного ключа таблицы, принадлежащего  */
    /* схеме                                                                                                                                 */
    /******************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_Features
       (a_SchemaName NAME default 'public',  /* название схемы базы данных */
        a_PrimaryKeyName NAME default NULL /* Название первичного ключа таблицы */
     )
    RETURNS TABLE (rs_PrimaryKeyName NAME,rs_PrimaryKeyDescription TEXT) AS
    $BODY$
    DECLARE c_PrimaryKeyKind CONSTANT CHAR:='p';
            v_PrimaryKeyOID    OID;   /* ИД первичного ключа таблицы */
            v_PrimaryKeyName NAME; /* Название первичного ключа таблицы */
            v_PrimaryKeyDescription TEXT; /* Описание первичного ключа таблицы */
            v_MasterTableName NAME;	/* Название таблицы, которой принадлежит первичный ключ */
    --*******************************************************************		
    BEGIN		
           SELECT INTO rs_PrimaryKeyName,rs_PrimaryKeyDescription
                       con.conname,COALESCE(dsc.description,'Первичный ключ таблицы '|| tbl.relname)  
               FROM pg_constraint con 
                          INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
                          INNER JOIN pg_class tbl ON con.conrelid=tbl.oid
                          LEFT OUTER JOIN pg_Description dsc ON con.oid=dsc.objoid
                                                                      AND dsc.objsubid=0
               WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype =c_PrimaryKeyKind
                          AND con.conname =LOWER(a_PrimaryKeyName);
           RETURN QUERY SELECT rs_PrimaryKeyName,rs_PrimaryKeyDescription;	
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_Features(a_SchemaName NAME,a_PrimaryKeyName NAME) IS 'Возвращает список характеристик первичного ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_Features (a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256));
    /******************************************************************************/
    /*  Функция возвращает список характеристик первичного ключа таблицы, принадлежащего */ /*  схеме                                                                                                                               */
    /******************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_Features
         (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_PrimaryKeyName VARCHAR(256) default NULL   /* Название первичного ключа таблицы */
     )
    RETURNS  TABLE (rs_PrimaryKeyName VARCHAR(256),rs_PrimaryKeyDescription TEXT) AS
    $BODY$
    DECLARE	c_PrimaryKeyKind	CONSTANT CHAR:='p';
    --******************************************************************		
    BEGIN		
       RETURN QUERY SELECT pkf.rs_PrimaryKeyName::VARCHAR(256),
                                           pkf.rs_PrimaryKeyDescription::TEXT
            FROM admtf_PrimaryKey_Features(a_SchemaName::NAME,a_PrimaryKeyName::NAME) pkf;	
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_Features(a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256)) IS 'Возвращает список характеристик первичного ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_PrimaryKey_Features('public'::NAME,'xpkstreet'::NAME);
    SELECt * FROM admtf_PrimaryKey_Features('public'::VARCHAR(256),'xpkstreet'::VARCHAR(256));
    


    Создание функции admtf_PrimaryKey_Attributes


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_Attributes (a_SchemaName NAME,a_PrimaryKeyName NAME);
    /********************************************************************/
    /*  Функция возвращает список атрибутов первичного ключа и их характеристик */
    /********************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_Attributes
         (a_SchemaName	NAME default 'public',	/* название схемы базы данных		*/
           a_PrimaryKeyName	NAME default NULL	/* Название первичного ключа таблицы */
     )										 
    RETURNS  TABLE (r_PrimaryKeyNo SMALLINT,r_AttributeNumber SMALLINT,
         r_AttributeName NAME,r_UserTypeName NAME,r_TypeName NAME,
         r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE	
         c_PrimaryKeyKind	CONSTANT CHAR:='p';
         v_PrimaryKeyOID OID; /* ИД первичного ключа таблицы */
         v_PrimaryKeyName NAME;        /* Название первичного ключа таблицы */
         v_PrimaryKeyDescription TEXT; /* Описание первичного ключа таблицы */
         v_MasterTableName NAME; /* Название таблицы, которой принадлежит первичный ключ */
         v_PrimaryKeyArray SMALLINT[]; /* Массив порядновых номеров в таблице */
         v_MasterTableOID OID; /* ИД таблицы, которой принадлежит первичный ключ */
         v_AttributeNumber SMALLINT; /* Номер аттрибута в таблице */
         v_PKAttributeCount SMALLINT; /* Счетчик атрибутов первичного ключа*/
         v_AttNo SMALLINT; /* Порядковый номер атрибута первичного ключа*/
    --**********************************************************************		
    BEGIN		
    	RETURN QUERY SELECT (rank() OVER (PARTITION BY con.conrelid ORDER BY
                                                          attr.attnum))::SMALLINT AS r_PrimaryKeyNo,
                 attr.attnum AS r_AttributeNumber,attr.attname::NAME AS r_AttributeName,
                 CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME 
                                                          ELSE ''::NAME END AS r_UserTypeName,
                 FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                              COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME AS r_TypeName,
                 attr.attnotnull AS r_isNotNULL,
                TRIM(dsc.description) AS r_Description
            FROM (SELECT c.oid, c.conrelid,c.connamespace,c.confrelid,c.conname,
                              c.contype,c.conkey::SMALLINT[],
    			  consrc, c.confkey::SMALLINT[],generate_subscripts(c.conkey, 1) as No 
                         FROM pg_constraint c) con 
                             INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
                             INNER JOIN pg_attribute attr ON attr.attrelid=con.conrelid
                                            AND attr.attnum=con.conkey[con.No]
                              LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid
                              LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
                              LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid
                                           AND dsc.objsubid=attr.attnum
             WHERE con.contype=c_PrimaryKeyKind
                       AND LOWER(nspc.nspname)=LOWER(a_SchemaName) 
                      AND LOWER(con.conname)=LOWER(a_PrimaryKeyName)
              ORDER BY attr.attnum;
    	RETURN;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_Attributes(a_SchemaName NAME,a_PrimaryKeyName NAME) IS 'Функция возвращает список атрибутов первичного ключа и их характеристик ';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_Attributes (a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256));
    /********************************************************************/
    /*  Функция возвращает список атрибутов первичного ключа и их характеристик */
    /********************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_Attributes
        (a_SchemaName VARCHAR(256) default 'public',  /* название схемы базы данных */
         a_PrimaryKeyName VARCHAR(256) default NULL /* Название первичного ключа таблицы */
     )
    RETURNS  TABLE (r_PrimaryKeyNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN,r_Description TEXT) AS
    $BODY$
    DECLARE	
        c_PrimaryKeyKind	CONSTANT CHAR:='p';
    --*******************************************************************		
    BEGIN		
        RETURN QUERY SELECT pka.r_PrimaryKeyNo::SMALLINT,pka.r_AttributeNumber::SMALLINT,
                                 pka.r_AttributeName::VARCHAR(256),pka.r_UserTypeName::VARCHAR(256),
                                 pka.r_TypeName::VARCHAR(256),pka.r_isNotNULL::BOOLEAN,
                                 pka.r_Description::TEXT
             FROM admtf_PrimaryKey_Attributes(a_SchemaName::NAME,a_PrimaryKeyName::NAME) pka;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_Attributes(a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256)) IS 'Функция возвращает список атрибутов первичного ключа и их характеристик';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    
    SELECt * FROM admtf_PrimaryKey_Attributes('public'::NAME,'xpkstreet'::NAME);
    SELECt * FROM admtf_PrimaryKey_Attributes('public'::VARCHAR(256),'xpkstreet'::VARCHAR(256));
    


    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_ComplexFeatures (a_SchemaName NAME,a_PrimaryKeyName NAME);
    /*****************************************************************************/
    /*  Функция возвращает список характеристик первичного ключа таблицы, принадлежащей */
    /*  схеме, а также список характеристик его атрибутов	                                                   */
    /*****************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_ComplexFeatures
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_PrimaryKeyName NAME default NULL /* Название первичного ключа таблицы */
     )				 
    RETURNS  TABLE (rpk_FeatureCategory VARCHAR(10),rpk_FeatureNumber SMALLINT,rpk_FeatureName NAME,rpk_FeatureDescription TEXT,
    rpk_UserTypeName NAME,rpk_TypeName NAME,rpk_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE
        c_PrimaryKeyCategory CONSTANT VARCHAR(10):='pk';	/* Категория характеристик  */
                                                                   /* первичного ключа таблицы */
        c_AttributeCategory CONSTANT VARCHAR(10):='pkatt'; /* Категория характеристик атрибутов*/
                                                                   /* первичного ключа таблицы */
        v_PrimaryKeyOID OID;		    /* ИД первичного ключа таблицы */
        v_PrimaryKeyName NAME;         /* Название первичного ключа таблицы */
        v_PrimaryKeyDescription TEXT;  /* Описание первичного ключа таблицы */
        v_FeatureCategory VARCHAR(10); /* Категория текущей характеристики */
        v_FeatureNumber SMALLINT; /* Порядковый номер характеристики заданной категории*/	
    --***********************************************************************		
    BEGIN	
        v_FeatureCategory:=c_PrimaryKeyCategory;
        v_FeatureNumber:=0;
        SELECT INTO v_PrimaryKeyName,v_PrimaryKeyDescription
                          rs_PrimaryKeyName,rs_PrimaryKeyDescription
            FROM admtf_PrimaryKey_Features(a_SchemaName,a_PrimaryKeyName);
        IF FOUND AND v_PrimaryKeyName IS NOT NULL THEN		
            RETURN QUERY SELECT v_FeatureCategory,v_FeatureNumber,v_PrimaryKeyName,
                           v_PrimaryKeyDescription,
                           NULL::NAME AS rpk_UserTypeName, NULL::NAME AS rpk_TypeName,
                           NULL::BOOLEAN AS rpk_isNotNULL;
            v_FeatureCategory:=c_AttributeCategory;
            v_FeatureNumber:=0;
            RETURN QUERY SELECT v_FeatureCategory,r_PrimaryKeyNo,r_AttributeName,r_Description,
                          r_UserTypeName,r_TypeName,r_isNotNULL
                 FROM  admtf_PrimaryKey_Attributes(a_SchemaName,a_PrimaryKeyName);
         END IF;			
         RETURN;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_ComplexFeatures(a_SchemaName NAME,a_PrimaryKeyName NAME) IS 'Возвращает список характеристик первичного ключа таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_PrimaryKey_ComplexFeatures (a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256));
    /******************************************************************************/
    /*  Функция возвращает список характеристик первичного ключа таблицы, принадлежащей  */
    /* схеме, а также список характеристик его атрибутов                                                           */
    /******************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_PrimaryKey_ComplexFeatures
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_PrimaryKeyName VARCHAR(256) default NULL /* Название первичного ключа таблицы */
     )
    RETURNS  TABLE (rpk_FeatureCategory VARCHAR(10),rpk_FeatureNumber SMALLINT,rpk_FeatureName VARCHAR(256),rpk_FeatureDescription TEXT,
    rpk_UserTypeName VARCHAR(256),rpk_TypeName VARCHAR(256),rpk_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE
        c_PrimaryKeyCategory CONSTANT VARCHAR(10):='pk'; /* Категория характеристик */
                                                                              /* первичного ключа таблицы */
    --*************************************************************************		
    BEGIN	
    	RETURN QUERY SELECT pk.rpk_FeatureCategory::VARCHAR(10),
                        pk.rpk_FeatureNumber::SMALLINT,
                        pk.rpk_FeatureName::VARCHAR(256),pk.rpk_FeatureDescription::TEXT,
                        pk.rpk_UserTypeName::VARCHAR(256),pk.rpk_TypeName::VARCHAR(256),
                        pk.rpk_isNotNULL::BOOLEAN
               FROM  admtf_PrimaryKey_ComplexFeatures(a_SchemaName::NAME,
                                                             a_PrimaryKeyName::NAME) pk;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_PrimaryKey_ComplexFeatures(a_SchemaName VARCHAR(256),a_PrimaryKeyName VARCHAR(256)) IS 'Возвращает список характеристик первичного ключа таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    
    SELECt * FROM admtf_PrimaryKey_ComplexFeatures('public'::NAME,'xpkstreet'::NAME);
    SELECt * FROM admtf_PrimaryKey_ComplexFeatures('public'::VARCHAR(256),'xpkstreet'::VARCHAR(256));
    



    Создание функции admtf_ForeignKey_ComplexFeatures


    Комментарии к исходному коду функции можно посмотреть здесь.
    код функции

    Создание функции admtf_ForeignKey_Features


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_Features (a_SchemaName NAME,a_ForeignKeyName NAME);
    /**************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, */
    /*  принадлежащего схеме                                                                       */
    /**************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_Features
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_ForeignKeyName NAME default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (rs_ForeignKeyName NAME,rs_ForeignKeyDescription TEXT) AS
    $BODY$
    DECLARE	c_ForeignKeyKind	CONSTANT CHAR:='f';
        v_ForeignKeyOID OID;            /* ИД внешнего ключа таблицы */
        v_ForeignKeyName  NAME;      /* Название внешнего ключа таблицы */
        v_ForeignKeyDescription TEXT; /* Описание внешнего ключа таблицы */
        v_MasterTableName NAME; /* Название таблицы, которой принадлежит первичный ключ */
    --************************************************************************		
    BEGIN		
        SELECT INTO rs_ForeignKeyName,rs_ForeignKeyDescription 
                       con.conname,COALESCE(dsc.description,'Внешний ключ таблицы '|| tbl.relname)  
          FROM pg_constraint con 
             INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
             INNER JOIN pg_class tbl ON con.conrelid=tbl.oid
             LEFT OUTER JOIN pg_Description dsc ON con.oid=dsc.objoid
                                  AND dsc.objsubid=0
          WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype =c_ForeignKeyKind
                               AND con.conname =LOWER(a_ForeignKeyName);
       RETURN QUERY SELECT rs_ForeignKeyName,rs_ForeignKeyDescription;	
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_Features(a_SchemaName NAME,a_ForeignKeyName NAME) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_Features (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256));
    /********************************************************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, принадлежащего схеме				*/
    /********************************************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_Features
       (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
       a_ForeignKeyName VARCHAR(256) default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (rs_ForeignKeyName VARCHAR(256),rs_ForeignKeyDescription TEXT) AS
    $BODY$
    DECLARE c_ForeignKeyKind CONSTANT CHAR:='f';
    	--*******************************************************************		
    BEGIN		
       RETURN QUERY SELECT fkf.rs_ForeignKeyName::VARCHAR(256),
                                     fkf.rs_ForeignKeyDescription::TEXT
                                  FROM admtf_ForeignKey_Features
                                                 (a_SchemaName::NAME,a_ForeignKeyName::NAME) fkf;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_Features(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256)) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_Features('public'::VARCHAR(256),'fk_street_locality'::VARCHAR(256));
    SELECt * FROM admtf_ForeignKey_Features('public'::NAME,'fk_street_locality'::NAME);
    


    Создание функции admtf_ForeignKey_Attributes


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_Attributes (a_SchemaName NAME,a_ForeignKeyName NAME);
    /**************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, */
    /*  принадлежащего схеме                                                                       */
    /**************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_Attributes
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
        a_ForeignKeyName	 NAME default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (r_ForeignKeyNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName NAME,r_UserTypeName NAME,r_TypeName NAME,r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE c_ForeignKeyKind CONSTANT CHAR:='f';
    --****************************************************************		
    BEGIN		
        RETURN QUERY SELECT (rank() OVER (PARTITION BY con.conrelid ORDER BY con.No))::SMALLINT
                                                                                    AS r_ForeingKeyNo,
                                    attr.attnum AS r_AttributeNumber,attr.attname::NAME AS r_AttributeName,
                                    CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME
                                              ELSE ''END AS r_UserTypeName,
    				FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                                                COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME
                                                                                      AS r_TypeName,				
                                    attr.attnotnull AS r_isNotNULL,TRIM(dsc.description) AS r_Description
                        FROM (SELECT c.oid, c.conrelid,c.confrelid,c.conname,c.connamespace,
                                            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_namespace nspc ON con.connamespace = nspc.oid
                                INNER JOIN pg_attribute attr ON attr.attrelid=con.conrelid
                                        AND attr.attnum=con.conkey[con.No]
                                INNER JOIN  pg_type typ ON attr.atttypid=typ.oid
                                LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
                                LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid
                                        AND dsc.objsubid=attr.attnum
                        WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype =c_ForeignKeyKind
                                        AND con.conname =LOWER(a_ForeignKeyName)
                        ORDER BY con.No;			
        RETURN;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_Attributes(a_SchemaName NAME,a_ForeignKeyName NAME) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_Attributes (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256));
    /**************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, */
    /* принадлежащего схеме                                                                        */
    /**************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_Attributes
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_ForeignKeyName VARCHAR(256) default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (r_ForeignKeyNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE c_ForeignKeyKind	 CONSTANT CHAR:='f';
    --*****************************************************************		
    BEGIN		
        RETURN QUERY SELECT fka.r_ForeignKeyNo::SMALLINT,fka.r_AttributeNumber::SMALLINT,
                                    fka.r_AttributeName::VARCHAR(256),
                                    fka.r_UserTypeName::VARCHAR(256),fka.r_TypeName::VARCHAR(256),
                                    fka.r_isNotNULL::BOOLEAN,fka.r_Description::TEXT
        FROM admtf_ForeignKey_Attributes(a_SchemaName::NAME,a_ForeignKeyName::NAME) fka;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_Attributes(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256)) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_Attributes('public'::NAME,'fk_mapHouse_MapStreet'::NAME);
    SELECt * FROM admtf_ForeignKey_Attributes('public'::NAME,'fk_street_locality'::NAME);
    SELECt * FROM admtf_ForeignKey_Attributes('public'::NAME,'fk_street_streettype'::NAME);
    SELECt * FROM admtf_ForeignKey_Attributes('public'::VARCHAR(256),'fk_street_locality'::VARCHAR(256));
    SELECt * FROM admtf_ForeignKey_Attributes('public'::VARCHAR(256),'fk_street_streettype'::VARCHAR(256));
    


    Создание функции admtf_ForeignKey_ReferenceTableComplexFeatures


    Комментарии к исходному коду функции можно посмотреть здесь.
    код функции

    Создание функции admtf_ForeignKey_ReferenceTableFeatures


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableFeatures (a_SchemaName NAME,a_ForeignKeyName NAME);
    /*******************************************************************/
    /*  Функция возвращает список характеристик таблицы, на которую ссылается */
    /*   внешний ключ                                                                                            */
    /*******************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableFeatures
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_ForeignKeyName NAME default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (rfkrt_ReferenceTableName NAME,rfkrt_ReferenceTableDescription TEXT) AS
    $BODY$
    DECLARE c_ForeignKeyKind	CONSTANT CHAR:='f';
     v_ReferenceTableOID OID; /* ИД таблицы, на которую ссылается внешний ключ */
     v_ReferenceTableName NAME; /* Название таблицы, на которую ссылается внешний ключ*/
     v_ReferenceTableDescription TEXT; /*Описание таблицы, на которую ссылается внешний ключ */
     v_MasterTableName NAME; /* Название таблицы, которой принадлежит внешний  ключ */
    --*******************************************************************		
    BEGIN		
        SELECT INTO v_ReferenceTableName rtbl.relname
            FROM pg_constraint con 
                INNER JOIN pg_namespace nspc ON con.connamespace = nspc.oid 
                INNER JOIN pg_class rtbl ON con.confrelid=rtbl.oid
            WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype =c_ForeignKeyKind
                    AND con.conname =LOWER(a_ForeignKeyName);
        IF FOUND THEN				
            RETURN QUERY SELECT rs_TableName,rs_TableDescription FROM
                    admtf_Table_Features(a_SchemaName,v_ReferenceTableName);	
        END IF;	
        RETURN;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableFeatures(a_SchemaName NAME,a_ForeignKeyName NAME) IS 'Возвращает список характеристик таблицы, на которую ссылается внешний ключ';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableFeatures (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256));
    /*******************************************************************/
    /*  Функция возвращает список характеристик таблицы, на которую ссылается */
    /*   внешний ключ                                                                                            */
    /******************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableFeatures
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_ForeignKeyName VARCHAR(256) default NULL /* Название внешнего ключа таблицы */
     )
    RETURNS  TABLE (rfkrt_ReferenceTableName VARCHAR(256),rfkrt_ReferenceTableDescription TEXT) AS
    $BODY$
    DECLARE c_ForeignKeyKind CONSTANT CHAR:='f';
    --*********************************************************************		
    BEGIN		
         RETURN QUERY SELECT fkrt.rfkrt_ReferenceTableName::VARCHAR(256),
                                    fkrt.rfkrt_ReferenceTableDescription::TEXT
        FROM admtf_ForeignKey_ReferenceTableFeatures(a_SchemaName::NAME,
                                    a_ForeignKeyName::NAME) fkrt;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableFeatures(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256)) IS 'Возвращает список характеристик таблицы, на которую ссылается внешний ключ';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_ReferenceTableFeatures('public'::VARCHAR(256),'fk_street_locality'::VARCHAR(256));
    SELECt * FROM admtf_ForeignKey_ReferenceTableFeatures('public'::NAME,'fk_street_locality'::NAME);
    


    Создание функции admtf_ForeignKey_ReferenceTableAttributes


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableAttributes (a_SchemaName NAME,a_ForeignKeyName NAME);
    /******************************************************************/
    /*  Функция возвращает список характеристик атрибутов таблицы, на которую */
    /*  сылается внешний ключ                                                                              */
    /******************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableAttributes
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_ForeignKeyName NAME default NULL /* Название внешнего ключа таблицы */
     )		 
    RETURNS TABLE(r_ReferenceTableKeyNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName NAME,r_UserTypeName NAME,r_TypeName NAME,r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE c_ForeignKeyKind	 CONSTANT CHAR:='f';
    v_ForeignKeyName NAME;/* Название внешнего ключа таблицы */
    v_ForeignKeyDescription TEXT;/* Описание внешнего ключа таблицы */
    v_ReferenceTableKeyArray SMALLINT[];/* Массив порядновых номеров в таблице, */
                                                      /* на которую сылается внешний ключ */
    v_ReferenceTableName NAME;/* Наименование таблицы, на которую ссылается внешний ключ */
    v_ReferenceTableDescription TEXT;/* Описание таблицы, на которую ссылается внешний ключ */
    v_ReferenceTableOID OID; /* ИД таблицы, которой принадлежит внешний ключ */
    v_AttributeNumber SMALLINT;	/* Номер аттрибута в таблице */
    v_FKAttributeCount INTEGER;    /* Счетчик атрибутов внешнего ключа*/
    v_AttNo SMALLINT;                   /* Порядковый номер атрибута внешнего ключа*/
    	--******************************************************************************************************		
    BEGIN		
        RETURN QUERY SELECT (rank() OVER (PARTITION BY con.confrelid 
                                                ORDER BY con.No))::SMALLINT AS r_ReferenceTableKeyNo,
                                attr.attnum AS r_AttributeNumber,attr.attname::NAME AS r_AttributeName,
                                CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME
                                        ELSE ''END AS r_UserTypeName,
                                FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                                                COALESCE(NULLIF(typ.typtypmod,-1),
                                                        attr.atttypmod))::NAME AS r_TypeName,				
                                attr.attnotnull AS r_isNotNULL,TRIM(dsc.description) AS r_Description 
        FROM (SELECT c.oid, c.conrelid,c.confrelid,c.conname,c.connamespace,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_namespace nspc ON con.connamespace = nspc.oid
            INNER JOIN pg_attribute attr ON attr.attrelid=con.confrelid
                                        AND attr.attnum=con.confkey[con.No]
            INNER JOIN  pg_type typ ON attr.atttypid=typ.oid
            LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
            LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid
                                        AND dsc.objsubid=attr.attnum
            WHERE nspc.nspname=LOWER(a_SchemaName) AND con.contype =c_ForeignKeyKind
                    AND con.conname =LOWER(a_ForeignKeyName)
            ORDER BY con.No;			
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableAttributes(a_SchemaName NAME,a_ForeignKeyName NAME) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableAttributes (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256));
    /*********************************************************/
    /*  Функция возвращает список характеристик атрибутов таблицы, */
    /*   на которую сылается внешний ключ                                         */
    /********************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableAttributes
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
        a_ForeignKeyName VARCHAR(256) default NULL /* Название внешнего ключа таблицы */
     )										 
    RETURNS  TABLE (r_ReferenceTableKeyNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN,r_Description TEXT) AS
    $BODY$
    DECLARE c_ForeignKeyKind CONSTANT CHAR:='f';
    --****************************************************************		
    BEGIN		
        RETURN QUERY SELECT fkra.r_ReferenceTableKeyNo::SMALLINT,
                                fkra.r_AttributeNumber::SMALLINT,fkra.r_AttributeName::VARCHAR(256),
                                fkra.r_UserTypeName::VARCHAR(256),fkra.r_TypeName::VARCHAR(256),
                                fkra.r_isNotNULL::BOOLEAN,fkra.r_Description::TEXT
        FROM admtf_ForeignKey_ReferenceTableAttributes(a_SchemaName::NAME,
                                            a_ForeignKeyName::NAME) fkra;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableAttributes(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256)) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_ReferenceTableAttributes('public'::VARCHAR(256),'fk_street_locality'::VARCHAR(256));
    SELECt * FROM admtf_ForeignKey_ReferenceTableAttributes('public'::NAME,'fk_street_locality'::NAME);
    


    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableComplexFeatures (a_SchemaName NAME,a_ForeignKeyName NAME,a_ForeignKeyNo SMALLINT);
    /*************************************************************/
    /*  Функция возвращает список характеристик таблицы, которую            */
    /* ссылается внешний ключ, а также список характеристик ее атрибутов */
    /*************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableComplexFeatures
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_ForeignKeyName NAME default NULL, /* Название внешнего ключа таблицы */
         a_ForeignKeyNo SMALLINT default NULL /* Порядковый номер внешнего ключа таблицы*/	
    )										 
    RETURNS  TABLE (fkrt_FeatureCategory VARCHAR(10),fkrt_FeatureNumber SMALLINT,fkrt_FeatureName NAME,fkrt_FeatureDescription TEXT,fkrt_UserTypeName NAME,fkrt_TypeName NAME,fkrt_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_WildChar CONSTANT VARCHAR(1):='%';	
    c_ForeignKeyCategory CONSTANT VARCHAR(10):='fk'||c_WildChar||'rtbl'; /* Категория */ 
                                     /* характеристик таблицы, на которую ссылается внешний ключ */
    c_AttributeCategory CONSTANT VARCHAR(10):='fk'||c_WildChar||'ratt';	/* Категория */
                            /* характеристик атрибутов таблицы, на которую ссылается внешний ключ */
    v_ForeignKeyCharNo VARCHAR(2); /* Порядковый номер внешнего ключа таблицы*/	
    v_ForeignKeyOID OID;                  /* ИД внешнего ключа таблицы */
    v_ForeignKeyName NAME;             /* Название внешнего ключа таблицы */
    v_ForeignKeyDescription TEXT;      /* Описание внешнего ключа таблицы */
    v_FeatureCategory VARCHAR(10); /* Категория текущей характеристики */
    v_FeatureNumber SMALLINT;      /* Порядковый номер характеристики заданной категории*/	
    --*********************************************************************		
    BEGIN	
        v_ForeignKeyCharNo:=COALESCE(TRIM(TO_CHAR(a_ForeignKeyNo,'09')),'');
        v_FeatureCategory:=REPLACE(c_ForeignKeyCategory,c_WildChar, v_ForeignKeyCharNo);
        v_FeatureNumber:=0;
        SELECT INTO v_ForeignKeyName,v_ForeignKeyDescription
                    rfkrt_ReferenceTableName,rfkrt_ReferenceTableDescription
            FROM admtf_ForeignKey_ReferenceTableFeatures(a_SchemaName,a_ForeignKeyName);
        IF FOUND AND v_ForeignKeyName IS NOT NULL THEN		
            RETURN QUERY SELECT 
                    v_FeatureCategory,v_FeatureNumber,v_ForeignKeyName,
                    v_ForeignKeyDescription,NULL::NAME AS fkrt_UserTypeName, 
                    NULL::NAME AS fkrt_TypeName, NULL::BOOLEAN AS fkrt_isNotNULL ;
        END IF;			
        v_FeatureCategory:=REPLACE(c_AttributeCategory,c_WildChar, v_ForeignKeyCharNo);
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,r_ReferenceTableKeyNo,r_AttributeName,
                    r_Description,r_UserTypeName,r_TypeName,r_isNotNULL
            FROM  admtf_ForeignKey_ReferenceTableAttributes(a_SchemaName,a_ForeignKeyName);
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableComplexFeatures(a_SchemaName NAME,a_ForeignKeyName NAME,a_ForeignKeyNo SMALLINT) IS 'Возвращает список характеристик таблицы, которую ссылается внешний ключ, а также список характеристик ее атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ReferenceTableComplexFeatures (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256),a_ForeignKeyNo SMALLINT);
    /*************************************************************/
    /*  Функция возвращает список характеристик таблицы, которую            */
    /* ссылается внешний ключ, а также список характеристик ее атрибутов */
    /*************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ReferenceTableComplexFeatures
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
        a_ForeignKeyName	 VARCHAR(256) default NULL,/* Название внешнего ключа таблицы 	*/
        a_ForeignKeyNo SMALLINT default NULL /* Порядковый номер внешнего ключа таблицы*/	
    )										 
    RETURNS  TABLE (fkrt_FeatureCategory VARCHAR(10),fkrt_FeatureNumber SMALLINT,fkrt_FeatureName VARCHAR(256),fkrt_FeatureDescription TEXT,
    fkrt_UserTypeName VARCHAR(256),fkrt_TypeName VARCHAR(256),fkrt_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_WildChar CONSTANT VARCHAR(1):='%';/* Категория характеристик */
                                                             /* внешнего ключа таблицы */		
    --******************************************************************		
    BEGIN	
        RETURN QUERY SELECT fkrt.fkrt_FeatureCategory::VARCHAR(10),
                                fkrt.fkrt_FeatureNumber::SMALLINT,
                                fkrt.fkrt_FeatureName::VARCHAR(256),fkrt.fkrt_FeatureDescription::TEXT,
                                fkrt.fkrt_UserTypeName::VARCHAR(256),
                                fkrt.fkrt_TypeName::VARCHAR(256),fkrt.fkrt_isNotNULL::BOOLEAN
        FROM  admtf_ForeignKey_ReferenceTableComplexFeatures(a_SchemaName::NAME,
                                        a_ForeignKeyName::NAME,a_ForeignKeyNo::SMALLINT ) fkrt;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ReferenceTableComplexFeatures(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256),a_ForeignKeyNo SMALLINT) IS 'Возвращает список характеристик таблицы, которую ссылается внешний ключ, а также список характеристик ее атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_ReferenceTableComplexFeatures('public'::NAME,'fk_street_locality'::NAME);
    SELECt * FROM admtf_ForeignKey_ReferenceTableComplexFeatures('public'::NAME,'fk_street_locality'::NAME,10::SMALLINT);
    SELECt * FROM admtf_ForeignKey_ReferenceTableComplexFeatures('public'::VARCHAR(256),'fk_street_locality'::VARCHAR(256),10::SMALLINT);
    


    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ComplexFeatures (a_SchemaName NAME,a_ForeignKeyName NAME,a_ForeignKeyNo SMALLINT);
    /**************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, */
    /*  принадлежащей схеме, а также список характеристик его атрибутов   */
    /**************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ComplexFeatures
        (a_SchemaName NAME default 'public', /* название схемы базы данных		*/
         a_ForeignKeyName NAME default NULL,	/* Название внешнего ключа таблицы */
         a_ForeignKeyNo SMALLINT default NULL /* Порядковый номер внешнего ключа таблицы*/	
     )										 
    RETURNS  TABLE (rfk_FeatureCategory VARCHAR(10),rfk_FeatureNumber SMALLINT,rfk_FeatureName NAME,rfk_FeatureDescription TEXT,
    rfk_UserTypeName NAME,rfk_TypeName NAME,rfk_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_WildChar CONSTANT VARCHAR(1):='%';
    c_ForeignKeyCategory CONSTANT VARCHAR(10):='fk'||c_WildChar; /* Категория характеристик */ 
                                                                                  /* внешнего ключа таблицы */
    c_AttributeCategory CONSTANT VARCHAR(10):='fk'||c_WildChar||'att'; /* Категория */
                                                                                 /* характеристик */ 
                                                                                  /* атрибутов внешнего ключа таблицы */
    v_ForeignKeyOID OID; /* ИД внешнего ключа таблицы */
    v_ForeignKeyName NAME; /* Название внешнего ключа таблицы */
    v_ForeignKeyCharNo VARCHAR(2); /* Порядковый номер внешнего ключа таблицы*/	
    v_ForeignKeyDescription TEXT; /* Описание внешнего ключа таблицы */
    v_FeatureCategory VARCHAR(10); /* Категория текущей характеристики */
    v_FeatureNumber SMALLINT; /* Порядковый номер характеристики заданной категории*/	
    --************************************************************************		
    BEGIN
        v_ForeignKeyCharNo:=COALESCE(TRIM(TO_CHAR(a_ForeignKeyNo,'09')),'');
        v_FeatureCategory:=REPLACE(c_ForeignKeyCategory,c_WildChar, v_ForeignKeyCharNo);
        v_FeatureNumber:=0;
        SELECT INTO v_ForeignKeyName,v_ForeignKeyDescription
                rs_ForeignKeyName,rs_ForeignKeyDescription
            FROM admtf_ForeignKey_Features(a_SchemaName,a_ForeignKeyName);
        IF FOUND AND v_ForeignKeyName IS NOT NULL THEN		
            RETURN QUERY SELECT v_FeatureCategory,COALESCE(a_ForeignKeyNo,v_FeatureNumber),
                        v_ForeignKeyName,v_ForeignKeyDescription,
                        NULL::NAME AS rfk_UserTypeName, NULL::NAME AS rfk_TypeName, 
                        NULL::BOOLEAN AS rfk_isNotNULL;
    	END IF;			
        v_FeatureCategory:=REPLACE(c_AttributeCategory,c_WildChar, v_ForeignKeyCharNo);
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,r_ForeignKeyNo,r_AttributeName,r_Description,
                            r_UserTypeName,r_TypeName,r_isNotNULL 
                FROM  admtf_ForeignKey_Attributes(a_SchemaName,a_ForeignKeyName);
        RETURN QUERY SELECT fkrt_FeatureCategory,fkrt_FeatureNumber,fkrt_FeatureName,
                            fkrt_FeatureDescription,fkrt_UserTypeName,fkrt_TypeName, 
                            fkrt_isNotNULL AS rfk_isNotNULL
                FROM  admtf_ForeignKey_ReferenceTableComplexFeatures(a_SchemaName,
                                a_ForeignKeyName,a_ForeignKeyNo);			
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ComplexFeatures(a_SchemaName NAME,a_ForeignKeyName NAME,a_ForeignKeyNo SMALLINT) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_ForeignKey_ComplexFeatures (a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256),a_ForeignKeyNo SMALLINT);
    /**************************************************************/
    /*  Функция возвращает список характеристик внешнего ключа таблицы, */
    /*  принадлежащей схеме, а также список характеристик его атрибутов   */
    /**************************************************************/
    CREATE OR REPLACE FUNCTION admtf_ForeignKey_ComplexFeatures
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_ForeignKeyName VARCHAR(256) default NULL, /* Название внешнего ключа таблицы */
         a_ForeignKeyNo SMALLINT default NULL /* Порядковый номер внешнего ключа таблицы*/	
     )										 
    RETURNS  TABLE (rfk_FeatureCategory VARCHAR(10),rfk_FeatureNumber SMALLINT,rfk_FeatureName VARCHAR(256),rfk_FeatureDescription TEXT,
    rfk_UserTypeName VARCHAR(256),rfk_TypeName VARCHAR(256),rfk_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_WildChar CONSTANT VARCHAR(1):='%'; 
    --********************************************************************		
    BEGIN
        RETURN QUERY SELECT fkcf.rfk_FeatureCategory::VARCHAR(10),
                       fkcf.rfk_FeatureNumber::SMALLINT,
                        fkcf.rfk_FeatureName::VARCHAR(256),fkcf.rfk_FeatureDescription::TEXT,
                        fkcf.rfk_UserTypeName::VARCHAR(256),fkcf.rfk_TypeName::VARCHAR(256),
                        fkcf.rfk_isNotNULL::BOOLEAN
                FROM  admtf_ForeignKey_ComplexFeatures(a_SchemaName::NAME,
                                        a_ForeignKeyName::NAME,a_ForeignKeyNo::SMALLINT) fkcf;			
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_ForeignKey_ComplexFeatures(a_SchemaName VARCHAR(256),a_ForeignKeyName VARCHAR(256),a_ForeignKeyNo SMALLINT) IS 'Возвращает список характеристик внешнего ключа таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_ForeignKey_ComplexFeatures('public'::NAME,'fk_street_locality'::NAME);
    SELECt * FROM admtf_ForeignKey_ComplexFeatures('public'::NAME,'fk_street_locality'::NAME,1::SMALLINT);
    SELECt * FROM admtf_ForeignKey_ComplexFeatures('public'::VARCHAR,'fk_street_locality'::VARCHAR,3::SMALLINT);
    



    Создание функции admtf_Index_ComplexFeatures


    Комментарии к исходному коду функции можно посмотреть здесь.
    код функции

    Создание функции admtf_Index_Features


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_Features (a_SchemaName NAME,a_IndexName NAME);
    /*******************************************************/
    /*  Функция возвращает список характеристик индекса таблицы, */
    /*   принадлежащей схеме                                                           */
    /*******************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_Features
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_IndexName NAME default NULL /* Название индекса таблицы */
     )										 
    RETURNS  TABLE (rs_IndexName NAME,rs_IndexDescription TEXT) AS
    $BODY$
    DECLARE c_IndexKind CONSTANT CHAR:='i';
     v_IndexOID OID; /* ИД индекса таблицы */
    v_IndexName NAME; /* Название индекса таблицы */
    v_IndexDescription TEXT; /* Описание индекса таблицы */
    --***************************************************		
    BEGIN		
        SELECT INTO rs_IndexName,rs_IndexDescription 
                            inxcls.relname,
                            CASE WHEN COALESCE(TRIM(dsc.description),'')='' 
                                THEN 'Индекс' || CASE WHEN inx.indisunique 
                                        THEN ' уникальный' || 
                                            CASE WHEN inx.indisprimary 
                                                THEN '(первичный ключ)' ELSE '' END 
                                        ELSE '' END || 
                                CASE WHEN inxam.amname='gist' 
                                        THEN ' пространственный' ELSE '' END ||
    					' таблицы '||tbl.relname
                                ELSE dsc.description END	
            FROM pg_index inx 
                INNER JOIN pg_class inxcls ON inx.indexrelid=inxcls.oid 
                INNER JOIN pg_namespace nsp ON inxcls.relnamespace=nsp.oid 
                LEFT OUTER JOIN pg_Description dsc ON inxcls.oid=dsc.objoid
                                AND dsc.objsubid=0
                LEFT OUTER JOIN pg_am inxam ON inxcls.relam=inxam.oid
                LEFT OUTER JOIN pg_class tbl ON inx.indrelid=tbl.oid
            WHERE nsp.nspname=LOWER(a_SchemaName) 
                                AND inxcls.relkind=c_IndexKind
                                AND inxcls.relname =LOWER(a_IndexName);
    	RETURN QUERY SELECT rs_IndexName,rs_IndexDescription;	
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_Features(a_SchemaName NAME,a_IndexName NAME) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_Features (a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256));
    /*******************************************************/
    /*  Функция возвращает список характеристик индекса таблицы, */
    /*   принадлежащей схеме                                                           */
    /*******************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_Features
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_IndexName VARCHAR(256) default NULL /* Название индекса таблицы */
     )										 
    RETURNS  TABLE (rs_IndexName VARCHAR(256),rs_IndexDescription TEXT) AS
    $BODY$
    DECLARE c_IndexKind CONSTANT CHAR:='i';
    --***********************************************************		
    BEGIN		
        RETURN QUERY SELECT ixf.rs_IndexName::VARCHAR(256),
                        ixf.rs_IndexDescription::TEXT
            FROM admtf_Index_Features(a_SchemaName::NAME,a_IndexName::NAME) ixf;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_Features(a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256)) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_Index_Features('public'::NAME,'xie1street'::NAME);
    SELECt * FROM admtf_Index_Features('public'::VARCHAR(256),'xie1street'::VARCHAR(256));
    SELECt * FROM admtf_Index_Features('public'::VARCHAR(256),'xie9street'::VARCHAR(256));
    


    Создание функции admtf_Index_Attributes


    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_Attributes (a_SchemaName NAME,a_IndexName NAME);
    /*******************************************************/
    /*  Функция возвращает список характеристик индекса таблицы, */
    /*   принадлежащего схеме                                                          */
    /*******************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_Attributes
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
         a_IndexName NAME default NULL /* Название индекса таблицы */
     )										 
    RETURNS  TABLE (r_IndexNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName NAME,r_OrderDirect VARCHAR(10), r_UserTypeName NAME,r_TypeName NAME,r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE cursor_IndexNoOfAttribute  refcursor;  /* номера атрибутов индекса*/
    c_IndexKind CONSTANT CHAR:='i';
    v_IndexOID OID; /* ИД индекса таблицы */
    v_IndexName NAME;	/* Название индекса таблицы */
    v_IndexDescription TEXT; /* Описание индекса таблицы */
    v_MasterTableName NAME; /* Название таблицы, которой принадлежит индекс */
    v_IndexArray SMALLINT[]; /* Массив порядновых номеров в таблице */
    v_IndexKeyOps SMALLINT[]; /* Массив опций атрибутов индекса*/
    v_AmCanOrder BOOLEAN; /* Поддерживает ли метод доступа */
                                           /* упорядоченное сканирование */
                                       /*по значению индексируемого столбца?*/
    v_MasterTableOID	OID;		/* ИД таблицы, которой принадлежит индекс */
    v_AttributeNumber	SMALLINT;	/* Номер аттрибута в таблице */
    v_AttributeOrderCode	INTEGER;		/* Признак упорядоченности атрибута*/
    v_IndexAttributeCount	INTEGER;	/* Счетчик атрибутов индекса*/
    v_AttNo			SMALLINT;	/* Порядковый номер атрибута индекса*/
    --*************************************************************************		
    BEGIN		
        RETURN QUERY SELECT (inx.No+1)::SMALLINT AS r_IndexNo,
                                attr.attnum::SMALLINT AS r_AttributeNumber, 
                                attr.attname::NAME AS r_AttributeName,
                                CASE WHEN NOT inxam.amcanorder 
                                        THEN NULL 
                                        ELSE CASE WHEN inx.indoption[inx.No] & 1=1 
                                                    THEN 'DESC' 
                                                    ELSE 'ASC' END 
                                        END::VARCHAR(10) AS r_OrderDirect,
                                CASE WHEN COALESCE(typ.typbasetype,0)>0 
                                        THEN typ.typname::NAME 
                                        ELSE ''END AS r_UserTypeName,
                                    FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid),
                                        COALESCE(NULLIF(typ.typtypmod,-1),
                                                              attr.atttypmod))::NAME AS r_TypeName,				
    				attr.attnotnull AS r_isNotNULL,				
    				dsc.description AS r_Description 
            FROM (SELECT i.indrelid, i.indexrelid,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_namespace nsp ON inxcls.relnamespace=nsp.oid 
                LEFT OUTER JOIN pg_am inxam ON inxcls.relam=inxam.oid
                LEFT OUTER JOIN pg_class tbl ON inx.indrelid=tbl.oid
                INNER JOIN pg_attribute attr ON attr.attrelid=tbl.oid 
                    AND attr.attnum=inx.indkey[inx.No]
                LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid
                LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid
                LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid
                    AND dsc.objsubid=attr.attnum
            WHERE nsp.nspname=LOWER(a_SchemaName) 
                    AND inxcls.relkind=c_IndexKind
                    AND inxcls.relname =LOWER(a_IndexName)
            ORDER BY nsp.nspname,inxcls.relname,inx.No;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_Attributes(a_SchemaName NAME,a_IndexName NAME) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_Attributes (a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256));
    /*******************************************************/
    /*  Функция возвращает список характеристик индекса таблицы, */
    /*  принадлежащего схеме                                                          */
    /******************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_Attributes
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
        a_IndexName	 VARCHAR(256) default NULL /* Название индекса таблицы */
     )										 
    RETURNS  TABLE (r_IndexNo SMALLINT,r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_OrderDirect VARCHAR(10),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN,r_Description Text) AS
    $BODY$
    DECLARE c_IndexKind CONSTANT CHAR:='i';
    --*******************************************************************		
    BEGIN		
        RETURN QUERY SELECT ia.r_IndexNo::SMALLINT,
                            ia.r_AttributeNumber::SMALLINT,
                            ia.r_AttributeName::VARCHAR(256),
                            ia.r_OrderDirect::VARCHAR(10),
                            ia.r_UserTypeName::VARCHAR(256),
                            ia.r_TypeName::VARCHAR(256),
                            ia.r_isNotNULL::BOOLEAN,
                            ia.r_Description::TEXT
                FROM admtf_Index_Attributes(a_SchemaName::NAME,a_IndexName::NAME) ia;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_Attributes(a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256)) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECt * FROM admtf_Index_Attributes('public'::NAME,'xie1street'::NAME);
    SELECt * FROM admtf_Index_Attributes('public'::VARCHAR(256),'xie1street'::VARCHAR(256));
    SELECt * FROM admtf_Index_Attributes('public'::VARCHAR(256),'xie9street'::VARCHAR(256));
    


    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_ComplexFeatures (a_SchemaName NAME,a_IndexName NAME,a_IndexNo SMALLINT);
    /************************************************************/
    /*  Функция возвращает список характеристик индекса таблицы,           */
    /*  принадлежащей схеме, а также список характеристик его атрибутов */
    /************************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_ComplexFeatures
        (a_SchemaName NAME default 'public', /* название схемы базы данных */
        a_IndexName NAME default NULL, /* Название индекса таблицы */
        a_IndexNo SMALLINT default NULL /* Порядковый индекса таблицы*/	
    )										 
    
    RETURNS  TABLE (rix_FeatureCategory VARCHAR(10),rix_FeatureNumber SMALLINT,rix_FeatureName NAME,rix_OrderDirect VARCHAR(10), rix_FeatureDescription TEXT,
    rix_UserTypeName NAME,rix_TypeName NAME,rix_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE
    c_WildChar CONSTANT VARCHAR(1):='%';
    c_IndexCategory CONSTANT VARCHAR(10):='idx'||c_WildChar;/* Категория */
                                /* характеристик индекса таблицы */
    c_AttributeCategory CONSTANT VARCHAR(10):='idx'||c_WildChar||'att';/* Категория */
                                /* характеристик атрибутов индекса таблицы */
    v_IndexOID OID; /* ИД индекса таблицы */
    v_IndexName NAME; /* Название индекса таблицы */
    v_IndexCharNo VARCHAR(2); /* Порядковый номер индекса таблицы*/	
    v_IndexDescription TEXT; /* Описание индекса таблицы */
    v_FeatureCategory VARCHAR(10); /* Категория текущей характеристики */
    v_FeatureNumber SMALLINT; /* Порядковый номер характеристики заданной категории*/	
    --***************************************************************************		
    BEGIN	
        v_IndexCharNo:=COALESCE(TRIM(TO_CHAR(a_IndexNo,'09')),'');
        v_FeatureCategory:=REPLACE(c_IndexCategory,c_WildChar, v_IndexCharNo);
        v_FeatureNumber:=0;
        SELECT INTO v_IndexName,v_IndexDescription  rs_IndexName,rs_IndexDescription
            FROM admtf_Index_Features(a_SchemaName,a_IndexName);
        IF FOUND AND v_IndexName IS NOT NULL THEN		
            RETURN QUERY SELECT v_FeatureCategory,
                        COALESCE(a_IndexNo,v_FeatureNumber),
                        v_IndexName,NULL::VARCHAR(10),
                        v_IndexDescription,
                        NULL::NAME AS rix_UserTypeName, 
                        NULL::NAME AS rix_TypeName, 
                        NULL::BOOLEAN AS rix_isNotNULL;
        END IF;			
        v_FeatureCategory:=REPLACE(c_AttributeCategory,c_WildChar, v_IndexCharNo);
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,r_IndexNo,
                        r_AttributeName,r_OrderDirect,r_Description,
                        r_UserTypeName,r_TypeName,r_isNotNULL
                FROM  admtf_Index_Attributes(a_SchemaName,a_IndexName);
        RETURN;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_ComplexFeatures(a_SchemaName NAME,a_IndexName NAME,a_IndexNo SMALLINT) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Index_ComplexFeatures (a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256),a_IndexNo SMALLINT);
    /************************************************************/
    /*  Функция возвращает список характеристик индекса таблицы,          */ 
    /* принадлежащей схеме, а также список характеристик его атрибутов */
    /************************************************************************************************************************/
    CREATE OR REPLACE FUNCTION admtf_Index_ComplexFeatures
        (a_SchemaName VARCHAR(256) default 'public', /* название схемы базы данных */
         a_IndexName VARCHAR(256) default NULL, /* Название индекса таблицы */
         a_IndexNo SMALLINT default NULL /* Порядковый номер индекса таблицы*/	
    )										 
    
    RETURNS  TABLE (rix_FeatureCategory VARCHAR(10),rix_FeatureNumber SMALLINT,
    rix_FeatureName VARCHAR(256),rix_OrderDirect VARCHAR(10),rix_FeatureDescription TEXT,
    rix_UserTypeName VARCHAR(256),rix_TypeName VARCHAR(256),rix_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_WildChar CONSTANT VARCHAR(1):='%';
    --********************************************************************		
    BEGIN	
        RETURN QUERY SELECT icf.rix_FeatureCategory::VARCHAR(10),
                                        icf.rix_FeatureNumber::SMALLINT,
                                        icf.rix_FeatureName::VARCHAR(256),
                                        icf.rix_OrderDirect::VARCHAR(10), 
                                        icf.rix_FeatureDescription::TEXT,
                                        icf.rix_UserTypeName::VARCHAR(256),
                                        icf.rix_TypeName::VARCHAR(256),
                                        icf.rix_isNotNULL::BOOLEAN
            FROM  admtf_Index_ComplexFeatures(a_SchemaName::NAME,
                                a_IndexName::NAME,a_IndexNo::SMALLINT) icf;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Index_ComplexFeatures(a_SchemaName VARCHAR(256),a_IndexName VARCHAR(256),a_IndexNo SMALLINT) IS 'Возвращает список характеристик индекса таблицы, принадлежащей схеме, а также список характеристик его атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECT * FROM admtf_Index_ComplexFeatures('public'::NAME,'xie1street'::NAME,7::SMALLINT);
    SELECT * FROM admtf_Index_ComplexFeatures('public'::VARCHAR(256),'xie1street'::VARCHAR(256),7::SMALLINT);
    SELECT * FROM admtf_Index_ComplexFeatures('public'::VARCHAR(256),'xie9street'::VARCHAR(256),7::SMALLINT);
    



    Создание функции admtf_Table_ComplexFeatures


    Комментарии к исходному коду функции можно посмотреть здесь, а также в первой части статьи в разделах «Структура головной функции» и «О каких расширенных характеристиках идет речь?».

    код функции
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Table_ComplexFeatures (a_SchemaName NAME,a_TableName NAME);
    /*******************************************************************/
    /*  Функция возвращает список характеристик таблицы, принадлежащей схеме, */
    /*   а также список характеристик ее атрибутов	                                                  */
    /********************************************************************/
    CREATE OR REPLACE FUNCTION admtf_Table_ComplexFeatures
        (a_SchemaName NAME default 'public',	/* название схемы базы данных */
         a_TableName NAME default NULL /* Название таблицы */
     )										 
    RETURNS  TABLE (rr_FeatureCategory VARCHAR(12),rr_FeatureNumber SMALLINT,rr_FeatureName NAME,rr_FeatureDescription TEXT,rr_UserTypeName NAME,rr_TypeName NAME,rr_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE cursor_ForeignKeys refcursor;  /* внешние ключи таблицы*/
    cursor_Indexes refcursor; /* индексы таблицы*/
    c_WildChar CONSTANT VARCHAR(1):='%';	
    c_TableCategory CONSTANT VARCHAR(10):='tbl'; /* Категория */
                                                /* характеристик таблицы */
    c_SequenceCategory	CONSTANT VARCHAR(10):='seq'||c_WildChar; /* Категория */
                                               /* характеристик последовательности таблицы */
    c_InheritanceTableCategory CONSTANT VARCHAR(10):='inhtbl'; /* Категория */
                                                 /* характеристик порожденной таблицы */
    c_AttributeCategory CONSTANT VARCHAR(10):='att'; /* Категория */
                                                  /* характеристик атрибутов таблицы */
    c_PrimaryKeyCategory CONSTANT VARCHAR(10):='pk'; /* Категория */
                                                   /* характеристик первичного ключа таблицы */
    c_ForeignKeyCategory CONSTANT VARCHAR(10):='fk';	/* Категория */
                                                    /* характеристик внешнего ключа таблицы */
    c_IndexCategory CONSTANT VARCHAR(10):='idx'; /* Категория */
                                                    /* характеристик индекса таблицы */
    c_PrimaryKeyKind CONSTANT CHAR:='p';
    c_ForeignKeyKind CONSTANT CHAR:='f';
    v_TableOID OID; /* ИД таблицы */
    v_TableName NAME; /* Название таблицы */
    v_TableDescription TEXT; /* Описание таблицы */
    v_FeatureCategory VARCHAR(12); /* Категория текущего аргумета */
    v_FeatureNumber SMALLINT; /* Порядковый номер характеристики заданной категории*/	
    v_PrimaryKeyName NAME; /* Название первичного ключа таблицы */
    v_ForeignKeyName NAME; /* Название внешнего ключа таблицы */
    v_FKeyCount INTEGER; /* Счетчик внешних ключей таблицы*/
    v_IndexName NAME; /* Название индекса таблицы */
    v_IndexCount INTEGER; /* Счетчик индексаов таблицы*/
    --*******************************************************************		
    BEGIN	
        v_FeatureCategory:=c_TableCategory;
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,v_FeatureNumber,rs_TableName,
                    rs_TableDescription,NULL::NAME AS rr_UserTypeName, 
                    NULL::NAME AS rr_TypeName,NULL::BOOLEAN AS rr_isNotNULL   
            FROM admtf_Table_Features(a_SchemaName,a_TableName);
        v_FeatureCategory:=c_AttributeCategory;
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,r_AttributeNumber,r_AttributeName,r_Description,
                            r_UserTypeName,r_TypeName,r_isNotNULL 
                FROM  admtf_Table_Attributes(a_SchemaName,a_TableName);
        v_FeatureCategory:=c_SequenceCategory;
        v_FeatureNumber:=0;
        RETURN QUERY SELECT REPLACE(c_SequenceCategory,c_WildChar,
                        COALESCE(TRIM(TO_CHAR(r_SequenceNumber,'09')),'')):: VARCHAR(12) 
                                                                            AS rr_FeatureCategory,
                        r_SequenceNumber,r_SequenceName,r_SequenceDescription,
                        NULL::NAME AS rr_UserTypeName, NULL::NAME AS rr_TypeName,
                        NULL::BOOLEAN AS rr_isNotNULL   
                FROM  admtf_Table_Sequences(a_SchemaName,a_TableName);
        v_FeatureCategory:=c_PrimaryKeyCategory;
        v_FeatureNumber:=0;
        SELECT INTO v_PrimaryKeyName r_ConstraintName 
            FROM admtf_Table_Constraintes(a_SchemaName,a_TableName)
            WHERE r_ConstraintType=c_PrimaryKeyKind;
        IF FOUND THEN	
            RETURN QUERY SELECT rpk_FeatureCategory ,rpk_FeatureNumber,
                    rpk_FeatureName,rpk_FeatureDescription,rpk_UserTypeName,
                    rpk_TypeName, rpk_isNotNULL 
                FROM admtf_PrimaryKey_ComplexFeatures(a_SchemaName,v_PrimaryKeyName);
        END IF;
        OPEN cursor_ForeignKeys  FOR SELECT r_ConstraintName 
            FROM admtf_Table_Constraintes(a_SchemaName,a_TableName) 
            WHERE r_ConstraintType=c_ForeignKeyKind 
            ORDER BY r_ConstraintName;
        v_FeatureCategory:=c_ForeignKeyCategory;
        v_FKeyCount:=0;
        FETCH FIRST FROM cursor_ForeignKeys  INTO v_ForeignKeyName;
        WHILE FOUND
        LOOP
            v_FKeyCount:=v_FKeyCount+1;
            RETURN QUERY SELECT rfk_FeatureCategory ,
                    CASE WHEN rfk_FeatureCategory  = c_ForeignKeyCategory 
                            THEN v_FKeyCount::SMALLINT ELSE  rfk_FeatureNumber END,
                    rfk_FeatureName,rfk_FeatureDescription,
                    rfk_UserTypeName,rfk_TypeName, rfk_isNotNULL 
                FROM admtf_ForeignKey_ComplexFeatures(a_SchemaName,
                            v_ForeignKeyName,v_FKeyCount::SMALLINT);
            FETCH NEXT  FROM cursor_ForeignKeys  INTO  v_ForeignKeyName;
        END LOOP;
        CLOSE cursor_ForeignKeys ;
        OPEN cursor_Indexes  FOR SELECT r_IndexName 
            FROM admtf_Table_Indexes(a_SchemaName,a_TableName) 
            ORDER BY r_IndexName ;
        v_FeatureCategory:=c_IndexCategory;
        v_IndexCount:=0;
        FETCH FIRST FROM cursor_Indexes  INTO v_IndexName;
        WHILE FOUND
        LOOP
            v_IndexCount:=v_IndexCount+1;
            RETURN QUERY SELECT rix_FeatureCategory ,
                    CASE WHEN rix_FeatureCategory  = c_IndexCategory 
                            THEN v_IndexCount::SMALLINT ELSE  rix_FeatureNumber END,
                    rix_FeatureName,rix_FeatureDescription,
                    rix_UserTypeName,rix_TypeName, rix_isNotNULL 
                FROM admtf_Index_ComplexFeatures(a_SchemaName,v_IndexName,
                                    v_IndexCount::SMALLINT);
            FETCH NEXT  FROM cursor_Indexes  INTO  v_IndexName;
        END LOOP;
        CLOSE cursor_Indexes ;
        v_FeatureCategory:=c_InheritanceTableCategory;
        v_FeatureNumber:=0;
        RETURN QUERY SELECT v_FeatureCategory,RANK() 
                        OVER(PARTITION BY v_FeatureCategory ORDER BY rs_TableName )::SMALLINT,
                rs_TableName,rs_TableDescription,
                NULL::NAME AS rr_UserTypeName, NULL::NAME AS rr_TypeName,
                NULL::BOOLEAN rr_isNotNULL   
            FROM admtf_Table_InheritanceChildrens(a_SchemaName,a_TableName);
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Table_ComplexFeatures(a_SchemaName NAME,a_TableName NAME) IS 'Возвращает список характеристик таблицы, принадлежащей схеме, а также список характеристик ее атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    BEGIN TRANSACTION;
    DROP FUNCTION IF EXISTS admtf_Table_ComplexFeatures (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256));
    /********************************************************************/
    /*  Функция возвращает список характеристик таблицы, принадлежащей схеме, */
    /*  а также список характеристик ее атрибутов                                                   */
    /*******************************************************************/
    CREATE OR REPLACE FUNCTION admtf_Table_ComplexFeatures
        (a_SchemaName VARCHAR(256) default 'public',/* название схемы базы данных*/
         a_TableName VARCHAR(256) default NULL /* Название таблицы */
     )										 
    RETURNS  TABLE (rr_FeatureCategory VARCHAR(12),rr_FeatureNumber SMALLINT,rr_FeatureName VARCHAR(256),rr_FeatureDescription TEXT,	rr_UserTypeName VARCHAR(256),rr_TypeName VARCHAR(256),rr_isNotNULL BOOLEAN) AS
    $BODY$
    DECLARE c_TableCategory CONSTANT VARCHAR(10):='tbl';	/* Категория */
                                                    /* характеристик таблицы */
    --***********************************************************		
    BEGIN	
        RETURN QUERY SELECT tcf.rr_FeatureCategory::VARCHAR(12),
                                tcf.rr_FeatureNumber::SMALLINT,
                                tcf.rr_FeatureName::VARCHAR(256),
                                tcf.rr_FeatureDescription::TEXT,
                                tcf.rr_UserTypeName::VARCHAR(256),
                                tcf.rr_TypeName::VARCHAR(256),
                                tcf.rr_isNotNULL::BOOLEAN  
        FROM admtf_Table_ComplexFeatures(a_SchemaName::NAME,a_TableName::NAME) tcf;
    END
    $BODY$
    LANGUAGE plpgsql;
    COMMENT ON FUNCTION admtf_Table_ComplexFeatures(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)) IS 'Возвращает список характеристик таблицы, принадлежащей схеме, а также список характеристик ее атрибутов';
    --ROLLBACK TRANSACTION;
    COMMIT TRANSACTION;
    SELECT * FROM admtf_Table_ComplexFeatures('public'::NAME,'Street'::NAME);
    


    Смотрите также
    Функции для документирования баз данных PostgreSQL. Часть первая;
    Функции для документирования баз данных PostgreSQL. Часть вторая;
    Функции для документирования баз данных PostgreSQL. Часть третья.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 0

    Only users with full accounts can post comments. Log in, please.