Статья продолжает знакомить с функциями для документирования баз данных PostgreSQL. Но на этот раз речь пойдет о специальных функциях, подготавливающих описания диаграмм классов на языке PlantUML.

В качестве основного средства документирования выбрана система управления проектами TRAC с подключенным плагином plantuml.

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

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

Все тексты на PLpgSQL написаны в для версии PosthgreSQL 9.6.

Содержание

  1. Назначение функций

  2. Общая структура функций

  3. Процедура umlpr_TablesScipt_FromArray — Выгрузка из списка таблиц

  4. Процедура umlpr_TablesScipt_ByWhereOption —Выгрузка по условию

  5. Функция umlfn_Table_fromArray —PlantUML-скрипт из списка таблиц

  6. Функция umlfn_Table_AllGroupScript —PlantUML-скрипт по условию

  7. Функция umlfn_Table_Script — PlantUML-скрипт таблицы с атрибутами

  8. Функция umlfn_Attribute_String —PlantUML-скрипт атрибута таблицы

  9. Функция umlfn_Table_LinksFromArray —PlantUML-скрипт связей

  10. ПРИЛОЖЕНИЕ 1.

    1. Создание процедуры umlpr_TablesScipt_FromArray

    2. Создание процедуры umlpr_TablesScipt_ByWhereOption

    3. Создание функции umlfn_Table_fromArray

    4. Создание функции umlfn_Table_AllGroupScript

    5. Создание функции umlfn_Table_Script

    6. Создание функции umlfn_Attribute_String

    7. Создание функции umlfn_Table_LinksFromArray

  11. ПРИЛОЖЕНИЕ 2. Дополнительные материалы

    1. Пошаговая инструкция просмотра диаграмм классов

    2. Пошаговая инструкция создания карточки TRAC

Назначение функций

PlantTest UML class diagram
Рис. 1. Пример диаграммы классов, созданной на языке PlantUML

Функции, описанные в предыдущих статьях, возвращали сведения об объектах баз данных (отношениях(таблицах), атрибутах таблиц, ограничениях (constraints), индексах и т.д.) в форме списков. Эти списки можно включать в документ, описывающий базу данных проекта, в виде таблиц. Но для документирования связей между таблицами списковая форма не слишком наглядна. Другое дело ER-диаграммы или диаграммы классов UML, такие как показана на Рис. 1. Обычно такие диаграммы создаются специальными графическими средствами, такими, например, как ERwin Data Modeler[*1] , Microsoft Visio[*2] , к недостаткам которых можно отнести отсутствие или сложность связи с существующей базой данных. Альтернативой графическим редакторам стала технология создания диаграмм из их текстовых описаний, которые создаются на на языке PlantUML. Эта технология предполагает создание UML за два шага — сначала создается описание или PlantUML-скрипт, который затем загружается в среду, преобразующую его в диаграмму.

Описываемые в этом документе функции предназначены для создания PlantUML-скриптов из данных системных каталогов PostgreSQL. Основной формат создаваемых PlantUML-скриптов соответствует требованиям плагина plantuml для системы управления проектами TRAC[*3] . Дополнительно описываемые функции могут создавать скрипты классической формы без дополнительной обёртки, необходимой для TRAC.

Общая структура функций

Головной функцией, создающей PlantUML-скрипты является umlfn_Table_fromArray. Она преобразует массив названий таблиц (отношений) в PlantUML-скрипт для последующего отображения в форме диаграммы классов UML.

Table_FromArrayUMLStructure
Рис. 2. Структура вызовов функций в процессе создания PlantUML— скрипта

Дополнительно PlantUML-скрипты могут быть созданы функцией umlfn_Table_AllGroupScript, которая по заданному условию формирует массив таблиц из каталога pg_class и вызывает головную функцию umlfn_Table_fromArray.

На Рис. 2 показана схема взаимодействия функций в процессе создания PlantUML-скрипты. На ней основные функции имеют префикс umlfn_или umltf. Остальные функции — вспомогательные, предназначены для доступа и обработки данных из системных каталогов.

Таблица 1 содержит список и краткое назначение основных функций.

FunStructure_Tbl001
Таблица 1. Назначение основных функций

Таблица 2 содержит список и краткое назначение только тех вспомогательных функций, которые не описаны в следующих статьях "Функции для документирования баз данных PostgreSQL":

В основном, эти функции создавались для удобства преобразования данных системных каталогов к формату PlantUML-скриптов.

FunStructure_Tbl002
Таблица 2. Назначение вспомогательных функций

Созданные PlantUML-скрипты могут быть выгружены в текстовый файл.

PlantUML procedures
Рис. 3. Схема взаимодействия основных функций и процедур

Для выгрузки PlantUML-скриптов используются хранимые процедуры, которые вызывают головную или дополнительную функции, а их результат сохраняют в текстовом файле с помощью оператора COPY TO. Схема взаимодействия основных функций и процедур приведена на Рис. 3.

Таблица 3 содержит список и краткое назначение основных процедур.

FunStructure_Tbl003
Таблица 3. Назначение основных процедур

Процедура umlpr_TablesScipt_FromArray

Процедура umlpr_TablesScipt_FromArray выгружает в текстовый файл PlantUML-скрипт, созданный из массива с названиями таблиц функцией umlfn_Table_fromArray.

В качестве основных параметров процедура принимает массив названий таблиц (a_TableNameArray), путь к папке, к которую должен быть выгружен PlantUML-скрипт (a_OutputFolder) и название схемы, в пределах которой они находятся таблицы (a_SchemaName). Дополнительными параметрами являются: «Признак необходимости включения комментария атрибута» (a_NeedAttrDesc) и «Формат возвращаемого PlantUML-скрипта: 'Trac' или 'PlantTest'» (a_Mode).

Название выгружаемого файла имеет один из следующих двух видов:

  1. plantuml_YYYY-MM-DD;

  2. plantuml_YYYY-MM-DD_classic

Файлы с именем второго вида создаются, если параметр a_Mode имеет значение 'PlantTest'. На месте шаблона 'YYYY-MM-DD' в названии указывается дата создания файла, в которой 'YYYY' — год, 'MM' — порядковый номер месяца в году, 'DD' — день в месяце.

COPY_umlpr_Tables_fA_inside001
Скрытый текст
COPY (SELECT unnest FROM unnest(ARRAY[umlfn_Table_FromArray(a_SchemaName::VARCHAR, a_TableNameArray, FALSE,a_Mode)]))
	TO  ''' || a_OutputFile||'plantuml_'||TO_CHAR(current_date, 'YYYY-MM-DD')||
					CASE a_Mode WHEN 'PlantTest' THEN '_classic' ELSE '' END||'.txt''';

Рисунок, содержащий оператор COPY выгружающий в текстовый файл PlantUML-скрипт, представляет собой принципиальную схему того, как результат выполнения функции umlfn_Table_fromArray. Но из-за особенностей оператора COPY в формат PlantUML-скрипта приходится внести изменения. Дело в том, что umlfn_Table_fromArray возвращает текстовую переменную, состоящую из не заключённых в кавычки подстрок, а для нормального выполнения оператора COPY наоборот каждая подстрока должна быть заключена в кавычки. При этом, после преобразования исходного формата в массив строк, в выходной файл строки выгружаются уже без кавычек.

COPY_umlpr_Tables_fA_inside002
Скрытый текст
v_PlantUML_Script:= umlfn_Table_FromArray(a_SchemaName::VARCHAR, a_TableNameArray, FALSE,a_Mode);
v_PlantUML_Script:= ''''||REPLACE(v_PlantUML_Script,CHR(13)||CHR(10),''', ''')||'''';
COPY (SELECT unnest FROM unnest(ARRAY[v_PlantUML_Script]))
	TO  ''' || a_OutputFile||'plantuml_'||TO_CHAR(current_date, 'YYYY-MM-DD')||
					CASE a_Mode WHEN 'PlantTest' THEN '_classic' ELSE '' END||'.txt''';

В новой версии рисунка учтена необходимость предварительного заключения всех подстрок PlantUML-скрипта в кавычки. Это преобразование выполняется во второй строке.

PlantUML Scripts
Рис. 4. Пример папки с выгруженными файлами, содержащими PlantUML-скрипты

Рис. 4 демонстрирует вариант папки с файлами, выгруженными процедурой umlpr_TablesScipt_FromArray. Содержание файлов подробно описано в разделе «Функция umlfn_Table_fromArray…»

Процедура umlpr_TablesScipt_ByWhereOption

Процедура umlpr_TablesScipt_ByWhereOption выгружает в текстовый файл PlantUML-скрипт, созданный из массива с названиями таблиц, найденных по заданному параметром условию. Непосредственно PlantUML-скрипт создаётся функцией umlfn_Table_fromArray.

В качестве основных параметров принимает условие поиска таблиц (a_WHEREoption), которое не содержит ключевое слово WHERE, путь к папке, к которую должен быть выгружен PlantUML-скрипт (a_OutputFolder) и название схемы, в пределах которой они находятся таблицы (a_SchemaName). Дополнительными параметрами являются: «Признак необходимости включения комментария атрибута» (a_NeedAttrDesc) и «Формат возвращаемого PlantUML-скрипта: 'Trac' или 'PlantTest'» (a_Mode).

Выполнение процедуры сводится к получению списка (массива) функций по заданному условию с помощью функции admfn_Table_TableNameArray, с последующим вызовом процедуры umlfn_Table_fromArray.

SELECT_uml_Tables_bC_inside
Скрытый текст
SELECT umlpr_TablesScipt_FromArray (admfn_Table_TableNameArray(a_SchemaName,a_WHEREoption), a_OutputFolder, a_SchemaName,v_Mode);

При описании условия выбора таблиц следует учесть названия псевдонимов (aliases) каталогов, которые используются в функции. Так для каталога pg_class используется псевдоним (alias) «tbl», а для каталога pg_namespace — «nsp».

Функция umlfn_Table_fromArray

Функция umlfn_Table_fromArray возвращает PlantUML-скрипт, созданный из массива с названиями таблиц.

В качестве основных параметров функция принимает массив названий таблиц (a_TableNameArray) и название схемы, в пределах которой они созданы (a_SchemaName). Дополнительными параметрами являются: «Признак необходимости включения комментария атрибута» (a_NeedAttrDesc) и «Формат возвращаемого PlantUML-скрипта: 'Trac' или 'PlantTest'» (a_Mode).

SELECT_uml_Tables_fA_inside v2
Скрытый текст
SELECT INTO v_TableGroupScript, v_TableGroupLegendScript
STRING_AGG (umlfn_Table_Script(a_SchemaName,tbl.relname,FALSE,cnfn_Table_LowerName(a_TableNameArray),'') AS v_TableGroupScript

'''legend center'''||CHR(13)||CHR(10)||'''<b><i><u>ТАБЛИЦЫ</u></i></b>'''|| CHR(13)||CHR(10)||''' '''|| CHR(13)||CHR(10)||
STRING_AGG (quote_literal('<b>'||UPPER(ftbl.relname)||'</b>'||'- '||COALESCE(dsc.description,''))|| CHR(13)||CHR(10),'')||
'''endlegend'''|| CHR(13)||CHR(10) AS v_TableGroupLegendScript
FROM pg_class tbl 
		INNER JOIN pg_namespace nsp ON tbl.relnamespace = nsp.oid 
		LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid
							AND dsc.objsubid=0
WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND tbl.relkind='r'
		AND tbl.relname !~* E'(raster_|spatial_|geometry_|geography_)' 
		AND ARRAY[LOWER(tbl.relname)::TEXT] <@ cnfn_Array_LowerCase(a_TableNameArray)::TEXT[]

Основные данные функция извлекает из записи каталога pg_class, содержащего кроме записей о таблицах еще и, записи о последовательностях, представлениях, материализованных представлениях, составных типах. Поэтому для выбора таблиц используется условие relkind='r'.

Дополнительно функция обращается к данным каталогов pg_namespace и pg_description. Первый содержит названия схем базы данных, а второй - комментарии ко всем объектам БД.

Здесь важно обратить внимание на условие objsubid=0. Оно определяет комментарий к таблице, т к. значение поля objoid одинаково как для таблицы, так и для ее атрибутов. Комментарий к атрибуту таблицы содержится в записи, в которой objsubid совпадает с номером этого атрибута.

Кроме того, в условии выбора исключаются таблицы PostgreSQL-расширения (EXTENSION) postgis, а также все элементы исходного массива названий функций переводятся в нижний регистр при помощи вспомогательной функции cnfn_Array_LowerCase.

С помощью оператора SELECT из данных исходных таблиц группируются две части PlantUML-скрипта: v_TableLinksScript— список таблиц с их атрибутами, v_TableGroupLegendScript — легенда предыдущего списка, т.е. названия таблиц с комментариями к ним.

SELECT_uml_Tables_fA_inside 002
Скрытый текст
v_TableLinksScript:=umlfn_Table_LinksFromArray(a_SchemaName, a_TableNameArray);
v_TableGroupScript:=v_TableGroupScript ||COALESCE(v_TableLinksScript,'') ||v_TableGroupLegendScript||v_TableGroupScriptSuffix;

Для описания связей заданных таблиц вызывается функция umlfn_Table_LinksFromArray, которая анализирует внешние ключи заданных таблиц, устанавливает обнаруженные связи, а также обозначает характер этих связей: «*-» — многие к одному, «-*»— один ко многим, «1-1» — один к одному. Таблица 4 содержит описаниие символов связи таблиц из руководства по языку PlantUML.

uml_Tables_fA_Tbl004
Таблица 4. Описание символов связи в документации к PlantUML

Последним оператором все части PlantUML-скрипта соединяются в нужной последовательности. При этом, в начало строки добавляется признак, идентифицирующий PlantUML-скрипт, а в конец полученной строки признак PlantUML-скрипта.

Таблица 5 позволяет представить результат выполнения функции umlfn_Table_fromArray, а также состав его частей.

uml_Tables_fA_Tbl005
Таблица 5. Результат выполнения функции umlfn_Table_FromArray('public'::VARCHAR, '{Street, StreetType, StreetType, STREETSYNONYM}'::VARCHAR(256)[])
Скрытый текст

Таблица 5 демонстрирует PlantUML-скрипт как набор подстрок, расположенных сверху вниз. В тоже время, в теле хранимых функций и процедур эти подстроки образуют значение одной текстовой (TEXT) переменной, в которой они разделены символами конца строки (CHR(13) — «Возврат каретки» и CHR(10) — «перевод строки»). Иногда текст PlantUML-скрипта необходимо преобразовать в массив подстрок. Этим объясняется то, что каждая отдельная подстрока заключена в одиночные кавычки.

SELECT_uml_Tables_fA_inside 003
v_TableGroupScript:=ARRAY_TO_STRING(cnfn_Array_QuotesWrapperWithout(STRING_TO_ARRAY(v_TableGroupScript, CHR(13)||CHR(10))), CHR(13)||CHR(10));

Но на выходе из umlfn_Table_fromArray одиночные кавычки не нужны. Поэтому текст временно преобразуется в массив, в каждом элементе которого убираются начальная и замыкающая кавычки. А затем массив снова преобразуется в строку, помещённую в тестовой переменной.

Обычно функция возвращает PlantUML-скрипт в формате плагина plantuml для системы управления проектами TRAC, но если дополнительный параметр a_Mode имеет значение 'PlantTest'», то обёртка скрипта ограничивается «@startuml...@enduml». Где @startuml — оператор начала скрипта, @enduml—окончания.

Исходный код функции можно посмотреть здесь.

Функция umlfn_Table_AllGroupScript

Функция umlfn_Table_AllGroupScript возвращает PlantUML-скрипт, созданный таблиц, найденных по заданному параметром условию.

В качестве основных параметров функция принимает условие поиска таблиц (a_WHEREoption), которое не содержит ключевое слово WHERE, и название схемы, в пределах которой будет вестись поиск (a_SchemaName). Дополнительными параметрами являются: «Признак необходимости включения комментария аттрибута» (a_NeedAttrDesc) и «Формат возвращаемого PlantUML-скрипта:'Trac' или 'PlantTest'» (a_Mode).

В теле функции для преобразования условия выборки в массив названий таблиц вызывается функция admfn_Table_TableNameArray и этот массив затем передается в качестве параметра функции umlfn_Table_fromArray, которая уже непосредственно создает PlantUML-скрипт.

SELECT_uml_Tables_AGS_inside
Скрытый текст
v_TableGroupScript:=umlfn_Table_FromArray(a_SchemaName, admfn_Table_TableNameArray(a_SchemaName,a_WHEREoption),a_NeedAttrDesc,v_Mode);

При описании условия выбора таблиц следует учесть названия псевдонимов (aliases) каталогов, которые используются в функции. Так для каталога pg_class используется псевдоним (alias) «tbl», а для каталога pg_namespace«nsp».

Таблица 6 показывает пример результата, возвращаемого функцией при корректном значении параметра a_WHEREoption, в режиме a_Mode='PlantTest'.

Таблица 6. Результат выполнения функции umlfn_Table_AllGroupScript('public','tbl.relname ~* E''^Street''', FALSE, 'PlantTest')

uml_Tables_AGS_Tbl006
Таблица 6. Результат выполнения функции umlfn_Table_AllGroupScript('public','tbl.relname ~* E''^Street''', FALSE, 'PlantTest')

Исходный код функции можно посмотреть здесь.

Функция umlfn_Table_Script

Функция umlfn_Table_fromArray возвращает часть PlantUML-скрипта по названию одной таблицы с её атрибутами.

В качестве основных параметров функция принимает названиие таблицы (a_TableName) и название схемы, в пределах которой они созданы (a_SchemaName). Дополнительными параметрами являются: «Признак необходимости включения комментария аттрибута» (a_NeedAttrDesc) и «Массив таблиц допустимых для поиска внешних ключей таблиц» (a_AllowedTableName).

SELECT_uml_Table_S_inside
Скрытый текст
SELECT '''object '|| a_SchemaName ||'.'||a_TableName||'{'''|| CHR(13)||CHR(10)||
STRING_AGG (umlfn_Attribute_String(oattr.oid, oattr.attnum,a_NeedAttrDesc,a_AllowedTableName),'')||
'''}'''|| CHR(13)||CHR(10)
FROM (SELECT tbl.oid, attr.attnum
		FROM pg_attribute attr 
		WHERE attr.attrelid=( a_SchemaName ||'.'|| a_TableName)::regclass AND attr.attnum>0
		ORDER BY tbl.relname,attr.attnum) oattr;

Основные данные функция извлекает из записи каталога pg_attribute, который содержит записи с данными об атрибутах таблиц, представлений, материализованных представлений, составных типов и даже функций.

Явное обращение к данным каталогов pg_namespace и pg_class отсутствует благодаря использованию псевдонима regclass, преобразующего квалифицированное имя таблицы в её системный ИД (OID).

Здесь важно обратить внимание на условие attnum>0. Оно определяет наличие типа атрибута в каталоге pg_type типов данных.

С помощью оператора SELECT из данных исходных атрибутов группируется часть PlantUML-скрипта: v_TableScript —таблица со списком её атрибутов. Описание каждого атрибута выполняется функцией umlfn_Attribute_String.

Таблица 7 позволяет представить результат выполния функции umlfn_Table_fromArray, а также состав его частей.

uml_Table_S_Tbl007
Таблица 7. Результат выполнения функции umlfn_Table_Script('public','Street',TRUE)

Исходный код функции можно посмотреть здесь.

Функция umlfn_Attribute_String

Функция umlfn_Attribute_String возвращает часть PlantUML-скрипта для одного атрибута по его названию.

В качестве основных параметров функция принимает системный идентификатор (OID) таблицы (a_TableOID) и порядковый номер атрибута в этой таблице (a_AttributeNo). Дополнительными параметрами являются: «Признак необходимости включения комментария атрибута» (a_NeedAttrDesc) и «Массив таблиц допустимых для поиска внешних ключей таблиц» (a_AllowedTableName). При этом значение последнего параметра (a_AllowedTableName) не используется. Как говорится, создан в расчёте на будущее усовершенствование функции.

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

SELECT_uml_Attribute_S_inside
Скрытый текст
SELECT ass.AttString||STRING_AGG(ass.FKString,'')
FROM (SELECT TRIM(af.rsa_AttributeName)||':'||
		' '||CASE WHEN af.rsa_Description IS NULL OR NOT a_NeedAttrDesc THEN '' ELSE '(<i>'||af.rsa_Description||'</i>)' END||
		' '||af.rsa_TypeName||
		' '||CASE WHEN af.rsa_isNotNULL THEN 'NOT' ELSE '' END || 'NULL' || ''||
		CASE WHEN af.rsa_isAttributePK THEN '(PK'||TRIM(COALESCE(TO_CHAR(af.rsa_ColumnPKNo,'999'),''))||')' 
				ELSE '' END AS AttString,
		'(FK'||TRIM(COALESCE(TO_CHAR(af.rsa_ColumnFKNo[af.fkInx],'999'),''))||' '||COALESCE(af.rsa_FKTableName[af.fkInx],'')||
		'('||COALESCE(af.rsa_FKTableColumnName[af.fkInx],'')||')'||')' FKString
	FROM (SELECT iaf.rsa_AttributeName,iaf.rsa_Description,iaf.rsa_TypeName,iaf.rsa_isNotNULL,iaf.rsa_isAttributePK,iaf.rsa_ColumnPKNo,
				iaf.rsa_isAttributeFK,iaf.rsa_ColumnFKNo,iaf.rsa_FKTableName,iaf.rsa_FKTableColumnName,
				GENERATE_SUBSCRIPTSs(iaf.rsa_ColumnFKNo, 1) fkInx
		FROM admtf_Attribute_Features(a_TableOID , a_AttributeNo) iaf) af
		ORDER BY fkInx) ass
GROUP BY  ass AttString;

Некоторая громоздкость приведенного оператора SELECT вызвана тем, что функция admtf_Attribute_Features, как показывает Таблица 8, возвращает характеристики внешних ключей в виде массивов. Отсюда возникла необходимость использования функции GENERATE_SUBSCRIPTS и последующей группировкой данных о внешнем ключе. Хотя, возможно, от такой группировки следует отказаться в будущем.

uml_Attribute_S_Tbl008
Таблица 8. Характеристики внешнего ключа, возвращаемые функцией admtf_Attribute_Features

Кроме того, при формировании строки с описанием атрибута учитывается значение параметра a_NeedAttrDesc, который указывает на то, добавлять ли в него комментарий к названию атрибута или нет.Остальные данные атрибута просто соединяются в порядке и формате, которые указаны в требования к языку PlantUML.

Таблица 9 содержит пример выполнения функции umlfn_Attribute_String, особенность которого в том, что параметр a_NeedAttrDesc='TRUE', а параметр a_TableOID задан при помощи псевдонима regclass, что более надёжно, чем использовать явное значение OID таблицы, т.к. последний может быть изменён в процессе эксплуатации базы данных.

uml_Attribute_S_Tbl009
Таблица 9. Результат выполнения функции umlfn_Attribute_String('public.Street'::REGCLASS, 2::SMALLINT, TRUE)

Исходный код функции можно посмотреть здесь.

Функция umlfn_Table_LinksFromArray

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

Основные данные функция извлекает из записей каталога pg_constraint. Каталог pg_constraint при условии contype='f' содержит записи с характеристиками внешних ключей таблиц, которые связывают записи из каталога pg_class, принадлежащие к типу relkind='r'. Для преобразования названия внешний ключей к характеристикам, соответствующей связи таблиц ('N:1','1:1') используется функция admfn_Table_LinkSign.

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

SELECT_uml_Table_LfA_inside
Скрытый текст
SELECT STRING_AGG(''''||LOWER(nsp.nspname)||'.'||UPPER(tbl.relname)||' '||
		CASE LEFT(ls.*,1) WHEN 'N' THEN '*' ELSE '' END || '--' || CASE  RIGHT(ls.*,1) WHEN 'N' THEN '*' ELSE '' END||
		' '||LOWER(nsp.nspname)||'.'||UPPER(Ftbl.relname)||''''||CHR(13)||CHR(10),'')
FROM pg_class tbl 
	INNER JOIN pg_namespace nsp ON tbl.relnamespace = nsp.oid 
	INNER JOIN pg_constraint lcon ON lcon.conrelid=tbl.oid
	INNER JOIN pg_class ftbl ON lcon.confrelid=ftbl.oid
	INNER JOIN pg_namespace fnsp ON ftbl.relnamespace=fnsp.oid,
	LATERAL admfn_Table_LinkSign(nsp.nspname,tbl.relname:: VARCHAR(256),lcon.conname:: VARCHAR(256)) ls
WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND tbl.relkind='r' 
	LOWER(fnsp.nspname)=LOWER(a_SchemaName) AND ftbl.relkind='r' 
	AND lcon.contype ='f'
	AND ARRAY[tbl.relname::VARCHAR(256)] <@ admfn_Table_LowerName(a_TableNameArray) 
	AND ARRAY[ftbl.relname::VARCHAR(256)] <@ admfn_Table_LowerName(a_TableNameArray);

Как видно из приведённого оператора, характеристики связи, возвращаемые функцией admfn_Table_LinkSign, преобразуются так:

  • символ 'N' заменяется на '*';

  • '1' — на '' (пустую строку);

  • ':' — на '--'.

Связываемые таблицы просто соединяются в порядке, которые указаны в требованиях к языку PlantUML.

Таблица 10 содержит пример выполнения функции umlfn_Table_LinksFromArray.

uml_Table_LfA_Tbl010
Таблица 10. Результат выполнения функции umlfn_Table_LinksFromArray('public', '{Street, StreetType, StreetSynonym, StreetTypeSynonym}')

Исходный код функции можно посмотреть здесь.

ПРИЛОЖЕНИЕ

Создание процедуры umlpr_TablesScipt_FromArray

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlpr_TablesScipt_FromArray(a_TableNameArray VARCHAR(256)[],a_OutputFolder TEXT,a_Schema VARCHAR(256),
							a_Mode VARCHAR(20));

/****************************************************************************************************************/
/* Создание файла с описанием таблиц из исходного массива в формате плагина (plantuml)                          */
/****************************************************************************************************************/
CREATE OR REPLACE FUNCTION umlpr_TablesScipt_FromArray
			(a_TableNameArray	VARCHAR(256)[], 		/* Исходный массив  таблиц  */
			a_OutputFolder 	TEXT, 				/* Папка создаваемого файла*/
			a_Schema		VARCHAR(256) DEFAULT 'public',/*Схема исходных таблиц*/
			a_Mode			VARCHAR(20) default 'Trac'	/* Формат возвращаемой строки:*/
										/* 'Trac' -для  средства управления проектам; */
										/*'PlantTest' - для тестирования на сайте*/
										/* https://www.planttext.com/  */
) 
RETURNS INTEGER
AS
$BODY$
DECLARE
	c_Schema		CONSTANT name:='public';
	c_NeedAttrDesc		CONSTANT BOOLEAN:=FALSE;		/* Признак необходимости включения комментария аттрибута  */
	c_TracMode		CONSTANT VARCHAR(50):='Trac'; /*для  средства управления проектам*/
	c_PlantTestMode	CONSTANT VARCHAR(50):='PlantTest'; /*для тестирования на сайте "https://www.planttext.com/" */

	v_Schema		VARCHAR(256); 	/*Схема исходных таблиц*/
	v_Mode			VARCHAR(20); 	/* Формат возвращаемой строки: 'Trac' -для  средства управления проектам;*/
						/* 'PlantTest' - для тестирования на сайте https://www.planttext.com/  */
	v_Return_Error 	Integer := 0; 	/* Код возврата*/
	v_OutputFile 		TEXT; 		/* Путь и название создаваемого файла*/
	v_COPY_Statement	TEXT; 		/* Оператор копирования скрипта в файл*/
	v_PlantUML_Script	TEXT; 		/* Сгенерированный скрипт*/
	v_TableNameArray	VARCHAR(256)[];/* Исходный массив  таблиц  */
	
BEGIN
	v_Mode:=COALESCE(a_Mode,c_TracMode);
	v_Schema:=COALESCE(a_Schema,c_Schema);
	v_TableNameArray:=a_TableNameArray;
	v_OutputFile:=TRIM(a_OutputFolder)||'plantuml_'||current_date||CASE v_Mode WHEN c_PlantTestMode THEN '_classic' ELSE '' END||'.txt';
	v_PlantUML_Script:= umlfn_Table_FromArray(v_Schema::VARCHAR,v_TableNameArray,c_NeedAttrDesc,v_Mode);
	v_PlantUML_Script:=''''||REPLACE(v_PlantUML_Script,CHR(13)||CHR(10),''', ''')||'''';
	v_COPY_Statement='COPY (SELECT unnest FROM unnest(ARRAY['|| v_PlantUML_Script || '])) TO  ''' || v_OutputFile||'''';
	BEGIN
	    EXECUTE v_COPY_Statement;
	EXCEPTION
		WHEN OTHERS THEN
		RAISE NOTICE 'ОШИБКА ПУТИ  к папке создаваемого файла. Проверьте правильность значений параметров.
		              ПАРАМЕТРЫ создания: ********************************************************************
					Путь            - "%"
					Массив таблиц   - "%"
					Схема           - "%"
                                        ***********************************************************',
                                       v_OutputFile,v_TableNameArray,v_Schema;
                 RETURN -2;                       
        END;
	RETURN v_Return_Error;
 
END
  $BODY$
 LANGUAGE plpgsql;
COMMENT ON FUNCTION umlpr_TablesScipt_FromArray(a_TableNameArray VARCHAR(256)[],a_OutputFolder TEXT,a_Schema VARCHAR(256),a_Mode VARCHAR(20)) IS 
			'Создание файла с описанием таблиц из исходного массива в формате плагина (plantuml)';

--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT umlpr_TablesScipt_FromArray('{Street,StreetType,StreetTypeSynonym,STREETSYNONYM}'::VARCHAR(256)[],
					'D:\plantuml\Scripts\','public','PlantTest' ); SELECT umlpr_TablesScipt_FromArray('{Street,StreetType,StreetTypeSynonym,STREETSYNONYM}'::VARCHAR(256)[],
					'D:\plantuml\Scripts\','public');

Создание процедуры umlpr_TablesScipt_ByWhereOption

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlpr_TablesScipt_ByWhereOption(a_WHEREoption VARCHAR(1000),a_OutputFolder TEXT,a_Schema VARCHAR(256),
								a_Mode VARCHAR(20));

/********************************************************************************************************************/
/* Создание файла с описанием таблиц по условию выбора таблиц из системного каталога в формате плагина (plantuml)   */
/********************************************************************************************************************/
CREATE OR REPLACE FUNCTION umlpr_TablesScipt_ByWhereOption
			(a_WHEREoption	VARCHAR(1000), 		/* условие запроса на выбор таблиц из системного каталога  */
			a_OutputFolder	TEXT, 				/* Папка создаваемого файла*/
			a_Schema	VARCHAR(256) DEFAULT 'public',/*Схема исходных таблиц*/
			a_Mode		VARCHAR(20) default 'Trac'	/* Формат возвращаемой строки: */
									/* 'Trac' -для  средства управления проектам;*/
									/*'PlantTest' - для тестирования на сайте */
									/*https://www.planttext.com/  */
) 
RETURNS INTEGER
AS
$BODY$
DECLARE
	v_TableNameArray	VARCHAR(256)[]; 	/* Массив выбранных таблиц  */
	v_Return_Error 	Integer := 0; 		/* Код возврата */
	
BEGIN
	v_TableNameArray:=admfn_Table_TableNameArray(a_Schema,a_WHEREoption);
	v_Return_Error:=umlpr_TablesScipt_FromArray(v_TableNameArray,a_OutputFolder,a_Schema,a_Mode);
	RETURN v_Return_Error;
END
  $BODY$
 LANGUAGE plpgsql;
COMMENT ON FUNCTION umlpr_TablesScipt_ByWhereOption(a_WHEREoption VARCHAR(1000),a_OutputFolder TEXT,a_Schema VARCHAR(256),a_Mode VARCHAR(20)) 			IS 'Создание файла с описанием таблиц по условию выбора таблиц из системного каталога в формате плагина (plantuml) ';

--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
/*SELECT umlpr_TablesScipt_ByWhereOption('tbl.relname LIKE ''id_districts'' OR tbl.relname LIKE ''id_nps'''::VARCHAR(1000),
					'D:\Projects\Enisey GIS\DB\PLpgSQL\Common\DBAdministrate\plantuml\NONScripts\' );
SELECT umlpr_TablesScipt_ByWhereOption('tbl.relname LIKE ''id_districts'' OR tbl.relname LIKE ''id_nps'''::VARCHAR(1000),
					'D:\Projects\Enisey GIS\DB\PLpgSQL\Common\DBAdministrate\plantuml\Scripts\' ,'public','Trac');
SELECT umlpr_TablesScipt_ByWhereOption('tbl.relname LIKE ''id_districts'' OR tbl.relname LIKE ''id_nps'''::VARCHAR(1000),
					'D:\Projects\Enisey GIS\DB\PLpgSQL\Common\DBAdministrate\plantuml\Scripts\','public','PlantTest');
*/
SELECT umlpr_TablesScipt_ByWhereOption('tbl.relname ~* E''^street''',
					'D:\Projects\Enisey GIS\DB\PLpgSQL\Common\DBAdministrate\plantuml\Scripts\','public','PlantTest'); 
SELECT umlpr_TablesScipt_ByWhereOption('tbl.relname ~* E''^street''',
					'D:\Projects\Enisey GIS\DB\PLpgSQL\Common\DBAdministrate\plantuml\Scripts\','public','PlantTest');

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

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlfn_Table_FromArray (a_SchemaName VARCHAR(100),a_TableNameArray VARCHAR(256)[],a_NeedAttrDesc BOOLEAN,a_Mode VARCHAR(20));
/********************************************************************************************************/
/*  Функция возвращает строку с описанием таблиц из исходного массива в формате плагина (plantuml) 	 */
/* к Trac — средству управления проектами и отсслеживания ошибок в программном обеспечении.		 */
/*------------------------------------------------------------------------------------------------------*/
/*	ПРИМЕР:	umlfn_Table_FromArray('public','{kmed__adres1,kmed_adres,kmed_adreskladr,kmed_adreskladr_temp,kmed_peoplebyidadreshome,kmed_radres,kmed_sadres,kmed_tadres}');				*/
/*------------------------------------------------------------------------------------------------------*/
/*	{{{												*/
/*	#!plantuml											*/
/*	@startuml											*/
/*	object public.KMED__ADRES1{									*/
/*	id_adres1 :  (<i>Уникальный код записи в оглавлении </i>) integer NOT NULL (PK1)		*/
/*	idadres :  (<i>Уникальный код записи адресного элемента (Код адреса) в kmed_ADRES</i>) integer NULL 	*/
/*	idparent :  (<i (...)										*/
/*													*/
/********************************************************************************************************/
CREATE OR REPLACE FUNCTION umlfn_Table_FromArray
			(a_SchemaName	VARCHAR(100) default 'public',	/* название схемы базы данных		*/
			a_TableNameArray	VARCHAR(256)[]	default '{}',		/* Исходный массив  таблиц  */
			a_NeedAttrDesc		BOOLEAN default false,		/* Признак необходимости включения комментария аттрибута  */
			a_Mode		        VARCHAR(20) default 'Trac'	/* Формат возвращаемого PlantUML-скрипта: 'Trac' -для  средства*/
										/* управления проектом; 'PlantTest' - для тестирования на сайте */
										/* https://www.planttext.com/  */
)
RETURNS  TEXT AS
$BODY$
DECLARE	
	c_SchemaName                        CONSTANT VARCHAR(256):='public';	/* название схемы базы данных		*/
	c_TableKind                         CONSTANT CHAR:='r';
	c_ForeignKeyKind                    CONSTANT CHAR:='f';
	c_TracMode                          CONSTANT VARCHAR(50):='Trac'; /*для  средства управления проектам*/
	c_PlantTestMode                     CONSTANT VARCHAR(50):='PlantTest'; /*для тестирования на сайте "https://www.planttext.com/" */
	c_TracTableGroupScriptPrefix        CONSTANT VARCHAR(50):='''{{{'''||CHR(13)||CHR(10)||'''#!plantuml'''||CHR(13)||CHR(10)||'''@startuml'''||CHR(13)||CHR(10);
										/* Начало скрипта описания группы таблиц в режиме 'Trac'*/
	c_TracTableGroupScriptSuffix	    CONSTANT VARCHAR(50):='''@enduml'''||CHR(13)||CHR(10)||'''}}}'''||CHR(13)||CHR(10)||''' '''||CHR(13)||CHR(10)||'''----'''||CHR(13)||CHR(10);
										/* Конец скрипта описания группы таблиц  в режиме 'Trac'*/
	c_PlantTestTableGroupScriptPrefix	CONSTANT VARCHAR(50):='''@startuml'''||CHR(13)||CHR(10);
										/* Начало скрипта описания группы таблиц  в режиме 'PlantTest'*/
	c_PlantTestTableGroupScriptSuffix	CONSTANT VARCHAR(50):='''@enduml''';
										/* Конец скрипта описания группы таблиц  в режиме 'PlantTest'*/



	c_TableGroupLegendPrefix            CONSTANT VARCHAR(100):='''legend center'''||CHR(13)||CHR(10)||'''<b><i><u>ТАБЛИЦЫ</u></i></b>'''||CHR(13)||CHR(10)||''' '''||CHR(13)||CHR(10);
										/* Начало раздела комментарии к таблицам группы */
	c_TableGroupLegendSuffix            CONSTANT VARCHAR(100):='''endlegend'''||CHR(13)||CHR(10);
										/* Конец раздела комментарии к таблицам группы */
 	c_TableNameLegendPrefix             CONSTANT VARCHAR(10):='<b>';	/* Начало наименования таблицы в комментариях*/
 	c_TableNameLegendSuffix             CONSTANT VARCHAR(10):='</b>';	/* Окончание наименования таблицы в комментариях*/
 	c_TableDescriptionLegendPrefix  	CONSTANT VARCHAR(10):='- ';	/* Начало описания таблицы в комментариях*/
  	c_TableDescriptionLegendSuffix  	CONSTANT VARCHAR(10):=CHR(13)||CHR(10);	/* Окончание описания таблицы в комментариях*/
 	c_TableNameDelimiter                CONSTANT VARCHAR(5):='.';  	/* Символ-разделитель имени таблицы	*/
	c_Blank                             CONSTANT VARCHAR(5):=' ';  	/* Символ пробела	*/
	v_Mode                              VARCHAR(20);    		/* Формат возвращаемой строки: 'Trac' -для  средства управления*/
										/* проектом; 'PlantTest' - для тестирования на сайте */
										/* https://www.planttext.com/  */
	v_SchemaName                VARCHAR(256);   /* название схемы базы данных		*/
	v_TableGroupScriptPrefix	VARCHAR(50);	/* Начало скрипта описания группы таблиц */
	v_TableGroupScriptSuffix	VARCHAR(50);    /* Конец скрипта описания группы таблиц*/
	v_TableGroupScript          TEXT;           /* Формируемый скрипт*/
	v_TableLinksScript          TEXT;           /* Формируемый раздел связей таблиц */
	v_TableGroupLegendScript	TEXT;           /* Формируемый раздел комментириев к таблицам группы*/
	v_TableCount                INTEGER;        /* Счетчик таблиц группы*/
	v_TableNameArray            TEXT[];         /* Массив таблиц  */
	v_AloneTableName            VARCHAR(256);   /* Название одной из таблиц группы*/
	v_TableDescription          TEXT;           /* Описание одной из таблиц группы*/
	v_TablesRecord              RECORD;         /* Запись с данными таблицы */
	v_TableOID                  OID;            /* ИД таблицы */
	v_ProcessedTableNameArray   TEXT[];         /* Массив обработанных таблиц  */
	v_TableNameArrayRemainder   TEXT[];         /* Массив необработанных таблиц  */
	v_Return_Error              INTEGER := 0;   /* Код возврата*/
--******************************************************************************************************		
BEGIN
    v_Mode:=COALESCE(a_Mode,c_TracMode);
    v_TableGroupScriptPrefix:=CASE v_Mode WHEN c_PlantTestMode THEN  c_PlantTestTableGroupScriptPrefix ELSE c_TracTableGroupScriptPrefix END;
    v_TableGroupScriptSuffix:=CASE v_Mode WHEN c_PlantTestMode THEN  c_PlantTestTableGroupScriptSuffix ELSE c_TracTableGroupScriptSuffix END;

	v_SchemaName:=COALESCE(a_SchemaName,c_SchemaName);
	v_TableNameArray:=a_TableNameArray;
	v_TableNameArray:=cnfn_Array_LowerCase(a_TableNameArray);
	v_TableNameArray:=string_to_array(REPLACE(REPLACE(array_to_string(v_TableNameArray,','),'''',''),'"',''),',');
	v_TableGroupScript:='';
	v_TableGroupLegendScript:='';
	IF COALESCE(v_TableNameArray,'{}')<>'{}' THEN
		v_TableCount:=0;
		v_TableGroupScript:=v_TableGroupScriptPrefix;
		v_TableGroupLegendScript:=c_TableGroupLegendPrefix;
		FOR v_TablesRecord IN SELECT ftbl.oid AS TableOID,ftbl.relname:: VARCHAR(256)
							FROM pg_class ftbl 
								INNER JOIN pg_namespace fnsp ON ftbl.relnamespace = fnsp.oid 
								LEFT OUTER JOIN pg_Description fdsc ON ftbl.oid=fdsc.objoid
												AND fdsc.objsubid=0
					WHERE LOWER(fnsp.nspname)=LOWER(v_SchemaName) AND ftbl.relkind=c_TableKind
						AND ftbl.relname !~ '(raster_|spatial_|geometry_|geography_)' 
						AND ARRAY[LOWER(ftbl.relname)::TEXT] <@ v_TableNameArray
					 ORDER BY fnsp.nspname,ftbl.relname
		LOOP
			v_AloneTableName:=LOWER(v_TablesRecord.relname);
			v_AloneTableName:=v_TablesRecord.relname;
    			v_TableCount:=v_TableCount+1;	
			v_TableGroupScript:=v_TableGroupScript||
					umlfn_Table_Script(a_SchemaName,v_AloneTableName,a_NeedAttrDesc,v_TableNameArray);
			SELECT INTO v_TableDescription rs_TableDescription  FROM admtf_Table_Features (a_SchemaName,v_AloneTableName);
			v_TableGroupLegendScript:=v_TableGroupLegendScript||
					quote_literal(c_TableNameLegendPrefix||UPPER(v_AloneTableName)||c_TableNameLegendSuffix||
					c_TableDescriptionLegendPrefix||COALESCE(v_TableDescription,''))||c_TableDescriptionLegendSuffix; 
			v_ProcessedTableNameArray:=array_append(v_ProcessedTableNameArray, v_AloneTableName::TEXT);
		END LOOP;
		v_TableGroupLegendScript:=v_TableGroupLegendScript||c_TableGroupLegendSuffix ;
		v_TableLinksScript:=cnfn_Array_LowerCase(a_SchemaName,v_TableNameArray);
		v_TableGroupScript:=v_TableGroupScript ||COALESCE(v_TableLinksScript,'') ||v_TableGroupLegendScript||v_TableGroupScriptSuffix;	END IF;	
	RETURN v_TableGroupScript;
END
$BODY$
LANGUAGE plpgsql;
COMMENT ON FUNCTION umlfn_Table_FromArray(a_SchemaName VARCHAR(100),a_TableNameArray VARCHAR(256)[],a_NeedAttrDesc BOOLEAN,a_Mode VARCHAR(20)) IS 'Возвращает строку с описанием таблиц массива в формате плагина (plantuml) к Trac';
--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT umlfn_Table_FromArray('public'::VARCHAR,'{ Street,StreetType, STREETSYNONYM }'::VARCHAR(256)[]);

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

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlfn_Table_AllGroupScript (a_SchemaName VARCHAR(100),a_WHEREoption VARCHAR(1000),a_NeedAttrDesc BOOLEAN,a_Mode VARCHAR(20));
/********************************************************************************************************/
/*  Функция возвращает строку с описанием группы таблиц в формате плагина (plantuml) к Trac — средству 	*/
/*  управления проектами и отслеживания ошибок в программном обеспечении.				*/
/*------------------------------------------------------------------------------------------------------*/
/*	ПРИМЕР:	umlfn_Table_AllGroupScript('public','tbl.relname ~* E''^Street''',FALSE,'Trac');            */
/*------------------------------------------------------------------------------------------------------*/
/*	{{{                                                                                                 */
/*	#!plantuml                                                                                          */
/*	@startuml                                                                                           */
/*	object public.STREET{                                                                               */
/*	wcrccode : smallint NOT NULL (PK1)                                                                  */
/*	localityid : integer NOT NULL (PK2)                                                                 */
/*	streetid : smallint NOT NULL (PK3)                                                                  */
/*	streettypeacrm : character(8) NULL (FK1 streettype(streettypeacrm))                                 */
/*	streetname : character varying(150) NOT NULL                                                        */
/*	streettsvector : tsvector NULL                                                                      */
/*	streettslitevector : tsvector NULL                                                                  */
/*	}                                                                                                   */
/*	object public.STREETSYNONYM{                                                                        */
/*	wcrccode : smallint NOT NULL (PK1)(FK1 street(wcrccode))                                            */
/*	localityid : integer NOT NULL (PK2)(FK2 street(localityid))                                         */
/*	streetid : smallint NOT NULL (PK3)(FK3 street(streetid))                                            */
/*	synonymid : smallint NOT NULL (PK4)                                                                 */
/*	streettypeacrm : character(8) NULL (FK1 streettype(streettypeacrm))                                 */
/*	streetsynonymname : character varying(200) NULL                                                     */
/*	}                                                                                                   */
/*	object public.STREETTYPE{                                                                           */
/*	streettypeacrm : character(8) NOT NULL (PK1)                                                        */
/*	streettypename : character varying(30) NULL                                                         */
/*	}                                                                                                   */
/*	object public.STREETTYPESYNONYM{                                                                    */
/*	streettypeacrm : character(8) NOT NULL (PK1)(FK1 streettype(streettypeacrm))                        */
/*	synonymid : smallint NOT NULL (PK2)                                                                 */
/*	streettypesynonymacrm : character varying(15) NULL                                                  */
/*	}                                                                                                   */
/*	public.STREETSYNONYM *-- public.STREET                                                              */
/*	public.STREETSYNONYM *-- public.STREETTYPE                                                          */
/*	public.STREET *-- public.STREETTYPE                                                                 */
/*	public.STREETTYPESYNONYM *-- public.STREETTYPE                                                      */
/*	legend center                                                                                       */
/*	<b><i><u>ТАБЛИЦЫ</u></i></b>                                                                        */
/*	                                                                                                    */
/*	<b>STREET</b>- Список улиц в населенных пунктах                                                     */
/*	<b>STREETSYNONYM</b>- Список синонимов назвачний улиц в населенных пунктах                          */
/*	<b>STREETTYPE</b>- Справочник типов улиц                                                            */
/*	<b>STREETTYPESYNONYM</b>- Справочник синонимов типов улиц                                           */
/*	endlegend                                                                                           */
/*	@enduml                                                                                             */
/*	}}}                                                                                                 */
/*	                                                                                                    */
/*	----                                                                                                */
/********************************************************************************************************/
CREATE OR REPLACE FUNCTION umlfn_Table_AllGroupScript
			(a_SchemaName	VARCHAR(100) default 'public',	/* название схемы базы данных		*/
			a_WHEREoption	VARCHAR(1000) default NULL,     /* условие запроса на выбор таблиц из системного каталога */
			a_NeedAttrDesc		BOOLEAN default false,		/* Признак необходимости включения комментария аттрибута  */
			a_Mode		        VARCHAR(20) default 'Trac'	/* Формат возвращаемой строки: 'Trac' -для  средства управления проектам; 'PlantTest' - для тестирования на сайте https://www.planttext.com/  */

				
	
 )										 

RETURNS  TEXT AS
$BODY$
DECLARE	
	c_TracMode          CONSTANT VARCHAR(50):='Trac'; 		/*для  средства управления проектам*/
	c_PlantTestMode     CONSTANT VARCHAR(50):='PlantTest'; 	/*для тестирования на сайте "https://www.planttext.com/ */
	v_Mode              VARCHAR(20); 		/* Формат возвращаемой строки: 'Trac' -для  средства управления проектам; */
							/* 'PlantTest' - для тестирования на сайте https://www.planttext.com/  */
	v_TableNameArray	VARCHAR(256)[]; 	/* Массив выбранных таблиц  */
	v_TableGroupScript	TEXT; 			/* Формируемый скрипт*/
	v_Return_Error 	Integer := 0; 		/* Код возврата*/


	--******************************************************************************************************		
BEGIN		
    v_Mode:=COALESCE(a_Mode,c_TracMode);
	v_TableGroupScript:='';
	v_TableNameArray:=admfn_Table_TableNameArray(a_SchemaName,a_WHEREoption);
	IF COALESCE(v_TableNameArray,'{}')<>'{}' THEN
		v_TableGroupScript:=umlfn_Table_FromArray(a_SchemaName,v_TableNameArray,a_NeedAttrDesc,v_Mode);
	END IF;	
	RETURN v_TableGroupScript;
END
$BODY$
LANGUAGE plpgsql;
COMMENT ON FUNCTION umlfn_Table_AllGroupScript(a_SchemaName VARCHAR(100),a_WHEREoption VARCHAR(1000),a_NeedAttrDesc BOOLEAN,a_Mode VARCHAR(20)) IS 'Возвращает строку строку с описанием группы таблиц в формате плагина (plantuml) к Trac';
--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT umlfn_Table_AllGroupScript('public','tbl.relname ~* E''^Street''');
SELECT umlfn_Table_AllGroupScript('public','tbl.relname ~* E''^Street''',FALSE,'PlantTest');

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

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlfn_Table_Script (a_SchemaName name,a_TableName name,a_NeedAttrDesc BOOLEAN,a_AllowedTableName VARCHAR(256)[]);
/********************************************************************************************************/
/*  Функция возвращает строку с описанием таблицы в формате плагина (plantuml) к Trac — средству 	    */
/*  управления проектами и отслеживания ошибок в программном обеспечении.				                */
/*------------------------------------------------------------------------------------------------------*/
/*	ПРИМЕР:	SELECT  umlfn_Table_Script('public','Street',TRUE);		                                    */
/*------------------------------------------------------------------------------------------------------*/
/*	'object public.STREET{'                                                                             */
/*	'wcrccode :  (<i>Код страны</i>) smallint NOT NULL (PK1)(FK1 locality(wcrccode))'					*/
/*	'localityid :  (<i>ИД населенного пункта</i>) integer NOT NULL (PK2)(FK2 locality(localityid))'		*/
/*	'streetid :  (<i>ИД улицы населенного пункта</i>) smallint NOT NULL (PK3)'			                */
/*	'streettypeacrm :  (<i>Акроним типа улицы</i>) character(8) NULL (FK1 streettype(streettypeacrm))' 	*/
/*	'streetname :  (<i>Наименование улицы населенного пункта</i>) character varying(150) NOT NULL'      */
/*	'streettsvector :  (<i>Расширенные характеристики улицы в населенном пункте, преобразованные в вектор полнотекстового поиска</i>) tsvector NULL '   */
/*	'streettslitevector :  (<i>Характеристики улицы в населенном пункте, преобразованные в вектор полнотекстового поиска</i>) tsvector NULL '           */
/*	'}'                                                                                                 */
/********************************************************************************************************/
CREATE OR REPLACE FUNCTION umlfn_Table_Script
			(a_SchemaName		NAME default 'public',	/* название схемы базы данных		*/				
			a_TableName		NAME default NULL,	/* Название таблицы */
 			a_NeedAttrDesc		BOOLEAN default false,		/* Признак необходимости включения комментария аттрибута  */
			a_AllowedTableName	VARCHAR(256)[]	default '{}'		/* Массив допустимых для поиска внешних ключей таблиц  */

)										 

RETURNS  TEXT AS
$BODY$
DECLARE	
	c_TableScriptPrefix	CONSTANT VARCHAR(10):='''object ';		/* Начало скрипта описания таблицы*/
	c_AttributeListPrefix	CONSTANT VARCHAR(5):='{'''||CHR(13)||CHR(10);	/* Начало списка атрибутов */
	c_AttributeListSuffix	CONSTANT VARCHAR(5):='''}'''||CHR(13)||CHR(10);	/* Конец списка атрибутов */
	c_TableScriptSuffix	CONSTANT VARCHAR(5):=' '||CHR(13)||CHR(10);	/* Конец скрипта описания таблицы*/
	c_TableNameDelimiter	CONSTANT VARCHAR(5):='.';  			/* Символ-разделитель имени таблицы	*/
	c_Blank			CONSTANT VARCHAR(5):=' ';  			/* Символ пробела	*/
	v_AttributeScript	TEXT;		/* */
	v_TableScript		TEXT;		/* */
	v_Schema		name;
	v_TableName		name;
	v_TableOID		OID;		
	v_AttributeName		name;		
	v_AttributeNum 		SMALLINT;
	v_AttributeCount	INTEGER;		/* Счетчик цикла*/
	v_Return_Error 		Integer := 0;

	cursor_Attributes CURSOR FOR  SELECT tbl.oid, attr.attnum 
			FROM pg_attribute attr 
				INNER JOIN pg_class tbl ON tbl.oid = attr.attrelid 
				INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid 
			WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) AND attr.attnum>0 
			ORDER BY tbl.relname,attr.attnum;

	--******************************************************************************************************		
BEGIN		
	v_TableScript:='';
	OPEN cursor_Attributes;
	v_AttributeCount:=0;
	v_TableScript:=c_TableScriptPrefix || LOWER(a_SchemaName) || c_TableNameDelimiter || 
                        CASE WHEN LEFT(TRIM(a_TableName),1) =UPPER(LEFT(TRIM(a_TableName),1))
                                    AND SUBSTRING(TRIM(a_TableName) FROM 2) =LOWER(SUBSTRING(TRIM(a_TableName) FROM 2))
                                                            THEN UPPER(a_TableName)
                            WHEN a_TableName ~ E'[A-ZА-ЯЁ]' THEN '"'||a_TableName||'"' 
                            ELSE  UPPER(a_TableName) END ||c_AttributeListPrefix;
	FETCH FIRST FROM cursor_Attributes INTO v_TableOID,v_AttributeNum;
	WHILE FOUND
	LOOP
		v_AttributeCount:=v_AttributeCount+1;	
		v_TableScript:=v_TableScript||COALESCE(umlfn_Attribute_String(v_TableOID,v_AttributeNum,a_NeedAttrDesc,a_AllowedTableName),'');
		FETCH NEXT  FROM cursor_Attributes INTO v_TableOID,v_AttributeNum;
	END LOOP;
	CLOSE cursor_Attributes;
	v_TableScript:=v_TableScript ||c_AttributeListSuffix;
	RETURN v_TableScript;
END
$BODY$
LANGUAGE plpgsql;
COMMENT ON FUNCTION umlfn_Table_Script(a_SchemaName name,a_TableName name,a_NeedAttrDesc BOOLEAN,a_AllowedTableName VARCHAR(256)[]) IS 'Возвращает строку с описанием таблицы в формате плагина (plantuml) к Trac';
--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT umlfn_Table_Script('public'::VARCHAR,'Street');

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

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlfn_Attribute_String (a_TableOID OID,a_AttributeNo SMALLINT,a_NeedAttrDesc BOOLEAN,a_AllowedTableName VARCHAR(256)[]);
/***************************************************************************************************************/
/*  Функция возвращает строку с описанием атрибута таблицы в формате плагина (plantuml) к Trac — средству 	*/
/*  управления проектами и отслеживания ошибок в программном обеспечении. 					*/
/*-------------------------------------------------------------------------------------------------------------*/
/* ПРИМЕРЫ:														*/
/*	ИД_Пользователь : double (PK)											*/
/*	ИД_Группа : double (FK1)											*/
/*	ИД_Должность : double (FK2)											*/
/*	Системное_Имя_Пользователя : varchar2(255) (AK)								*/
/*	ФИО : varchar2(255)												*/
/*	Телефоны : varchar2(255)											*/
/*	Почта : varchar2(100)												*/
/*	Адрес : varchar2(255)												*/
/*	Дата_Рождения : date												*/
/****************************************************************************************************************/
CREATE OR REPLACE FUNCTION umlfn_Attribute_String
				(a_TableOID		OID,				/* ИД таблицы */
				a_AttributeNo		SMALLINT,			/* Порядковый номер атрибута в таблице*/	
				a_NeedAttrDesc		BOOLEAN default false,		/* Признак необходимости включения комментария аттрибута  */	
				a_AllowedTableName	VARCHAR(256)[]	default '{}'	/* Массив допустимых для поиска внешних ключей таблиц  */

 )										 

RETURNS  TEXT AS
$BODY$
DECLARE 
	c_PrimaryKeyPrefix	CONSTANT VARCHAR(5):='(PK';		/* Начало опции об участии аттрибута в первичном ключе*/
	c_PrimaryKeySuffix	CONSTANT VARCHAR(5):=')';		/* Окончание опции об участии аттрибута в первичном ключе*/
	c_ForeignKeyPrefix	CONSTANT VARCHAR(5):='(FK';		/* Начало опции об участии аттрибута во внешнем ключе*/
	c_ForeignKeySuffix	CONSTANT VARCHAR(5):=')';		/* Окончание опции об участии аттрибута во внешнем ключе*/
	c_DescriptionPrefix	CONSTANT VARCHAR(5):='(<i>';		/* Начало комментария к атрибуту*/
	c_DescriptionSuffix	CONSTANT VARCHAR(5):='</i>)';		/* Окончание комментария к атрибуту*/
	c_EndOfAttributeString	CONSTANT VARCHAR(5):=CHR(13)||CHR(10);  /* Символы окончания строки описания атрибута	*/
	c_NULL			CONSTANT VARCHAR(5):='NULL';		/* Строка NULL */	
	c_NOT			CONSTANT VARCHAR(5):='NOT';		/* Строка NOT */	
	c_Blank			CONSTANT VARCHAR(5):=' ';		/* Символ пробела */	
	c_AttributeDelimiter	CONSTANT VARCHAR(5):=' : '; 		/* Символ - разделитель названия атрибута и его типа	*/
	c_ColumnFKList_NDims 	CONSTANT INTEGER:=1;			/* Размерность массива атрибутов внешнего ключа*/
	v_NeedAttrDesc		BOOLEAN;				/* Признак необходимости включения комментария аттрибута  */
	v_AllowedTableName	VARCHAR(256)[];				/* Массив допустимых для поиска внешних ключей таблиц  */
	v_Attribute_String 	TEXT;	 				/* Строка описания атрибута*/
	v_AttributeName 	name;					/* Название атрибута*/
	v_UserTypeName 		VARCHAR(256);				/* Пользовательский тип атрибута (название домена)*/
	v_TypeName 		VARCHAR(256);				/* Тип атрибута*/
	v_isNotNULL 		BOOLEAN;				/* Признак недопустимости значения NULL*/
	v_isAttributePK 	BOOLEAN;				/* Признак вхождения атрибута в первичный ключ */
	v_ColumnPKNo 		SMALLINT;				/* Порядковый номер аттрибута в первичном ключе*/
	v_Description		TEXT;					/* Комментари к аттрибуту */
	v_isAttributeFK 	BOOLEAN;				/* Признак вхождения атрибута во внешний ключ */
	v_ColumnFKNoARRAY	SMALLINT[];				/* Массив порядковых номеров атрибута во всех внешних ключах */
	v_FKTableNameARRAY	name[];					/* Массив названий таблиц, на которые сслылаются внешние ключи */
	v_FKTableColumnNameARRAY 	name[];					/* Массив названий атрибутов таблицы, на которую сслылается внешний ключи */
	v_ColumnFKNo		SMALLINT;				/* Порядковый номер атрибута текщем внешнем ключе */
	v_FKTableName 		name;					/* Название таблицы, на которую сслылается текщий внешний ключ */
	v_FKTableColumnName 	name;					/* Название атрибута таблицы, на которую сслылается внешний ключ */
	v_ColumnFKIndx		INTEGER;				/* Текущий индекс масссива атрибутов внешнего ключа*/		
	v_ColumnFKLBound	INTEGER;				/* Нижний индекс масссива атрибутов внешнего ключа*/		
	v_ColumnFKUBound	INTEGER;				/* Верхний индекс масссива атрибутов внешнего ключа*/	
	v_Return_Error 		Integer := 0;				/* Код возврата*/		
	
	--******************************************************************************************************		
BEGIN	
	v_Attribute_String:='';
	v_AllowedTableName:=COALESCE(a_AllowedTableName,'{}');
	v_AllowedTableName:=cnfn_Array_LowerCase(v_AllowedTableName);
	v_NeedAttrDesc:=COALESCE(a_NeedAttrDesc,false);
	SELECT INTO v_AttributeName,v_TypeName,v_isNotNULL,v_isAttributePK,v_ColumnPKNo,v_Description,v_isAttributeFK,v_ColumnFKNoARRAY,
			v_FKTableNameARRAY,v_FKTableColumnNameARRAY  
		rsa_AttributeName,rsa_TypeName,rsa_isNotNULL,rsa_isAttributePK,rsa_ColumnPKNo,rsa_Description,
			rsa_isAttributeFK,rsa_ColumnFKNo,
			rsa_FKTableName,rsa_FKTableColumnName
			FROM admtf_Attribute_Features(a_TableOID,a_AttributeNo);
	v_Attribute_String:=TRIM(v_AttributeName)||c_AttributeDelimiter||
				CASE WHEN v_Description IS NULL OR NOT v_NeedAttrDesc THEN '' 
					ELSE c_Blank||c_DescriptionPrefix||v_Description||c_DescriptionSuffix|| c_Blank END ||
						v_TypeName||
						c_Blank||CASE WHEN v_isNotNULL THEN c_NOT||c_Blank ELSE '' END || c_NULL || c_Blank ||
						CASE WHEN v_isAttributePK
							THEN c_PrimaryKeyPrefix||TRIM(COALESCE(TO_CHAR(v_ColumnPKNo,'999'),''))||
								c_PrimaryKeySuffix
							ELSE '' END;
	IF v_isAttributeFK THEN	
		v_ColumnFKLBound:=array_lower(v_ColumnFKNoARRAY,c_ColumnFKList_NDims);
		v_ColumnFKUBound:=array_upper(v_ColumnFKNoARRAY,c_ColumnFKList_NDims);
		v_ColumnFKIndx:=v_ColumnFKLBound;
		WHILE v_ColumnFKIndx<=v_ColumnFKUBound
		LOOP
			v_ColumnFKNo:=v_ColumnFKNoARRAY[v_ColumnFKIndx];
			v_FKTableName:=v_FKTableNameARRAY[v_ColumnFKIndx];
			v_FKTableColumnName:=v_FKTableColumnNameARRAY[v_ColumnFKIndx];
			IF COALESCE(a_AllowedTableName,'{}')='{}' OR ARRAY[v_FKTableName] <@ a_AllowedTableName::NAME[] THEN
				v_Attribute_String:=v_Attribute_String||c_ForeignKeyPrefix||
							TRIM(COALESCE(TO_CHAR(v_ColumnFKNo,'999'),''))||
							' '||COALESCE(v_FKTableName,'')||'('||COALESCE(v_FKTableColumnName,'')||')'||
							c_ForeignKeySuffix;
			END IF;	
			v_ColumnFKIndx:=v_ColumnFKIndx+1;
		END LOOP;
	END IF;			
	v_Attribute_String:=quote_literal(v_Attribute_String)||c_EndOfAttributeString;
	RETURN v_Attribute_String;
	
END
$BODY$
LANGUAGE plpgsql;
COMMENT ON FUNCTION umlfn_Attribute_String(a_TableOID OID,a_AttributeNo SMALLINT,a_NeedAttrDesc BOOLEAN,a_AllowedTableName VARCHAR(256)[]) IS 'Возвращает строку с описанием атрибута таблицы в формате плагина (plantuml) к Trac';


--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT * FROM umlfn_Attribute_String('public.Street'::REGCLASS,2::SMALLINT,TRUE);
SELECT * FROM generate_series (1,6) inx, LATERAL umlfn_Attribute_String('public.Street'::REGCLASS,inx::SMALLINT,FALSE) ORDER BY inx;

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

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

Скрытый текст
BEGIN TRANSACTION;
DROP FUNCTION IF EXISTS umlfn_Table_LinksFromArray (a_SchemaName VARCHAR(100),a_TableNameArray VARCHAR(256)[]);
/************************************************************************************************************/
/*  Функция возвращает строку с описанием связей таблиц из исходного массива в формате плагина (plantuml)   */
/* к Trac — средству управления проектами и отсслеживания ошибок в программном обеспечении.		            */
/*----------------------------------------------------------------------------------------------------------*/
/*	ПРИМЕР:	umlfn_Table_LinksFromArray('public','{Street,StreetType,StreetSynonym,StreetTypeSynonym}');		*/
/*----------------------------------------------------------------------------------------------------------*/
/* 'public.STREETSYNONYM *-- public.STREET'                                                                 */
/* 'public.STREETSYNONYM *-- public.STREETTYPE'                                                             */
/* 'public.STREET *-- public.STREETTYPE'                                                                    */
/* 'public.STREETTYPESYNONYM *-- public.STREETTYPE'                                                         */
/************************************************************************************************************/
CREATE OR REPLACE FUNCTION umlfn_Table_LinksFromArray
			(a_SchemaName	VARCHAR(100) default 'public',	/* название схемы базы данных		*/
			a_TableNameArray	VARCHAR(256)[]	default '{}'		/* Исходный массив  таблиц  */
 )										 

RETURNS  TEXT AS
$BODY$
DECLARE	
	c_SchemaName		CONSTANT VARCHAR(256):='public';	/* название схемы базы данных		*/
	c_TableKind		CONSTANT CHAR:='r';
	c_ForeignKeyKind	CONSTANT CHAR:='f';
	c_ManySign		CONSTANT CHAR:='N';
	c_OneSign		CONSTANT CHAR:='1';
	c_PlantManySign		CONSTANT VARCHAR:='*';
	c_PlantOneSign		CONSTANT VARCHAR:='';
	c_PlantLinkMark		CONSTANT VARCHAR:='--';


  	c_TableLinksSuffix  	CONSTANT VARCHAR(10):=CHR(13)||CHR(10);	/* Окончание описания таблицы в комментариях*/
 	c_TableNameDelimiter	CONSTANT VARCHAR(5):='.';  			/* Символ-разделитель имени таблицы	*/
	c_Blank			CONSTANT VARCHAR(5):=' ';  			/* Символ пробела	*/
	v_SchemaName		VARCHAR(256);					/* название схемы базы данных		*/
	v_TableLinksScript	TEXT;						/* Формируемый скрипт*/
	v_TableCount		INTEGER;					/* Чсетчик таблиц группы*/
	v_TableNameArray	TEXT[];						/* Массив таблиц  */
	v_TableName 		VARCHAR(256);					/* Название одной из таблиц группы*/
	v_FTableName 		VARCHAR(256);					/* Название одной из таблиц группы*/
	v_TableDescription	TEXT;						/* Описание одной из таблиц группы*/
	v_TablesRecord		RECORD;						/* Запись с данными таблицы */
	v_TableOID		OID;						/* ИД таблицы */
	v_ForeignKeyName 		VARCHAR(256);		/* Название внешнего ключа*/
	v_ProcessedTableNameArray	TEXT[];					/* Массив обработанных таблиц  */
	v_TableNameArrayRemainder	TEXT[];					/* Массив необработанных таблиц  */
	v_LinkSign			VARCHAR(5);				/* Признак связи по отношения к таклице*/
	v_LinkMarkLeftChar		VARCHAR;				/* Левый символ признака связи*/
	v_LinkMarkRightChar		VARCHAR;				/* Правый символ признака связи*/
	v_PlantLinkSign			VARCHAR(5);
	v_Return_Error 		Integer := 0;
	--******************************************************************************************************		
BEGIN		
	v_SchemaName:=COALESCE(a_SchemaName,c_SchemaName);
	v_TableNameArray:=cnfn_Array_LowerCase(a_TableNameArray);
	v_TableLinksScript:='';
	IF COALESCE(v_TableNameArray,'{}')<>'{}' THEN
		v_TableCount:=0;
		FOR v_TablesRecord IN SELECT tbl.oid AS TableOID,tbl.relname:: VARCHAR(256),ftbl.oid AS FTableOID,
							Ftbl.relname:: VARCHAR(256) AS Frelname,
						lcon.oid AS ForeignKeyOID,lcon.conname:: VARCHAR(256) AS ForeignKeyName
					FROM pg_class tbl 
					INNER JOIN pg_namespace nsp ON tbl.relnamespace = nsp.oid 
					LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid
									AND dsc.objsubid=0
					INNER JOIN pg_constraint lcon ON lcon.conrelid=tbl.oid				
					INNER JOIN pg_namespace lnspc ON lcon.connamespace = lnspc.oid	
					INNER JOIN pg_class ftbl ON lcon.confrelid=ftbl.oid
					INNER JOIN pg_namespace fnsp ON ftbl.relnamespace=fnsp.oid 
					WHERE LOWER(fnsp.nspname)=LOWER(v_SchemaName) AND ftbl.relkind=c_TableKind 
						AND lcon.contype =c_ForeignKeyKind AND LOWER(lnspc.nspname)=LOWER(v_SchemaName)
						AND ftbl.relname !~* E'(raster_|spatial_|geometry_|geography_)'
						AND ARRAY[tbl.relname::TEXT] <@ v_TableNameArray 
						AND ARRAY[ftbl.relname::TEXT] <@ v_TableNameArray
					 ORDER BY COUNT(*) OVER(PARTITION BY nsp.oid,tbl.oid) DESC, nsp.nspname,tbl.relname
		LOOP
			v_TableName:=v_TablesRecord.relname;
			v_FTableName:=v_TablesRecord.Frelname;
			v_ForeignKeyName:=v_TablesRecord.ForeignKeyName;
			v_TableCount:=v_TableCount+1;
			v_LinkSign:=admfn_Table_LinkSign(a_SchemaName,v_TableName,v_ForeignKeyName);
			v_LinkMarkLeftChar:=LEFT(v_LinkSign,1);
			v_LinkMarkRightChar:=RIGHT(v_LinkSign,1);
			v_PlantLinkSign:=CASE v_LinkMarkLeftChar WHEN c_ManySign THEN c_PlantManySign ELSE c_PlantOneSign END ||
					 c_PlantLinkMark || CASE v_LinkMarkRightChar WHEN c_ManySign THEN c_PlantManySign 
											ELSE c_PlantOneSign END;	
			v_TableLinksScript:=v_TableLinksScript||''''||LOWER(v_SchemaName)||c_TableNameDelimiter||UPPER(v_TableName)||c_Blank||
						v_PlantLinkSign||c_Blank||LOWER(v_SchemaName)||c_TableNameDelimiter||UPPER(v_FTableName)||''''||
						c_TableLinksSuffix;
			v_ProcessedTableNameArray:=array_append(v_ProcessedTableNameArray, v_TableName::TEXT);
		END LOOP;
	END IF;	
	RETURN v_TableLinksScript;
END
$BODY$
LANGUAGE plpgsql;
COMMENT ON FUNCTION umlfn_Table_LinksFromArray(a_SchemaName VARCHAR(100),a_TableNameArray VARCHAR(256)[]) IS 'Возвращает строку строку с описанием таблиц массива в формате плагина (plantuml) к Trac';
--ROLLBACK TRANSACTION;
COMMIT TRANSACTION;
SELECT umlfn_Table_LinksFromArray('public','{Street,StreetType,StreetSynonym,StreetTypeSynonym}');

ПРИЛОЖЕНИЕ 2. Дополнительные материалы

Пошаговая инструкция просмотра диаграмм классов

Скрытый текст

Посмотреть, как выглядит диаграмма классов, описанная PlantUML-скриптом можно на сайте PlantText UML editor.

Шаг 1. Перейти по ссылке https://www.planttext.com/ на страницу редактора, как показано на Рис. 5. Установить курсор на заголовке вкладки «File Manager». В открывшемся меню выбрать пункт «Import / Export».

PlantTest UML step01 v2
Рис. 5. Начальный экран PlantText UML editor

Шаг 2. В открывшемся окне «Import/Export» в строке «Import» щёлкнуть левой клавишей мыши на кнопку «Обзор», как показано.

PlantTest UML step02 v2
Рис. 6. Окно вызова загрузки PlantUML-скрипта

Откроется стандартное для Вашей операционной системы окно выбора файла. В Windows 10 оно будет выглядеть примерно так, как показано на Рис. 7.

Выбрать заранее подготовленный скрипт и нажать кнопку «Открыть».

PlantTest UML import file v2
Рис. 7. Выбор PlantUML-скрипта на диске

Здесь выбирается скрипт с окончанием «PlantTest», т.к. он создан в формате готовом для отображения диаграммы классов в PlantText UML editor.

Беды не будет, если выбрать скрипт без такого окончания, т.к. как показано дальше формат скриптов для TRAC содержит дополнительные строчки в начале и в конце скрипта, которые легко удаляются.

Шаг 3. В открывшемся окне «Import/Export» в строке «Import» щёлкнуть левой клавишей мыши на кнопку «Обзор», как показано.

PlantTest UML step03
Рис. 8. Слева загруженный PlantUML-скрипт, справа — соответствующая диаграмма классов

Как видно из Рис. 8 диаграмма классов может быть преобразованы в форматы: PNG, SVG [*5] , TXT.

PlantTest UML PNG
Рис. 9. Диаграмма классов в формате PNG

Как внести изменения в PlantUML-скрипт для TRAC, чтобы увидеть диаграмму классов

PlantText UML editor работает со скриптами, построенными по правилам языка PlantUML, в соответствии с которыми основной текст скрипта должен быть заключён между операторами @startuml и @enduml. В тоже время для встраивания в плагин (plantuml) TRAC вокруг классического текста создается дополнительная оболочка.

PlantTest UML step03_error
Рис. 10. Сообщение об ошибке после загрузки скрипта для TRAC

Для того чтобы PlantText UML editor не воспринимал скрипт как ошибочный, из его текста следует удалить строки выше оператора @startuml и ниже оператора @enduml. Эти строки выделены на Рис. 10.

После удаления экран приобретёт вид, показанный на Рис. 8.

Пошаговая инструкция создания карточки TRAC

Скрытый текст
TRAC-logo
TRAC-logo

Здесь предполагается, что «Система управления проектами TRAC» уже установлена. Тем же, кого интересуют сведения о порядке установки этой системы предлагаем перейти на страницу официального сайта под названием «Руководство по установке Trac».

Вход в установленную на сервере компании систему TRAC выполняется через браузер. Формат URL установленного TRAC может выглядеть так: https://trac.company.ru/. Где вместо «company» указывается домен компании, в которой установлена система TRAC. Поэтому, как показано на Рис. 11, первый шаг представляет собой вход с сиcтему TRAC.

TRAC entrance step01 v2
Рис. 11. Окно входа в систему TRAC

После входа открывается страница проекта, отображающая список проектов компании. Так как вход осуществляется с познавательными целями, то вторым шагом выбирается проект «песочница», предназначенный для изучения возможностей TRAC путём экспериментирования. Смотри Рис. 12.

TRAC projects step02 v2
Рис. 12. Вход в проект "песочница"
TRAC new card step02 v2
Рис. 13 Список карточек проекта и кнопка создания новой карточки

Щелчок на названии проекта левой клавишей мышки, приводит к тому, что на экране появляются список карточек проекта, а также кнопки вызова различных операций над карточками. В данном случает, как показано на Рис. 13, мы создаем новую карточку, нажав на кнопку с соответствующим названием.

TRAC create card step03
Рис. 14. Окно создания карточки проекта

В открывшемся окне для создания новой карточки вводится название карточки в поле «Краткое описание», а в основное окно вставляется текст PlantUML-скрипта. Смотри Рис. 14.

TRAC scripts wrapper
Рис. 15. TRAC- обёртка скрипта

Заметим, что вставляемый скрипт должен быть окружен операторами «обёртки» TRAC. На Рис. 15 эти операторы выделены красным цветом. После нажатия одной из кнопок «Предварительный просмотр» или «Создать карточку» на экране отобразится описанная скриптом диаграмма классов.

TRAC view card step04
Рис. 16. Диаграмма классов в системе TRAC

Цель достигнута — скрипт включен в карточку системы TRAC, в которой отображается диаграмма классов.

Комментарии (0)