Пишу сейчас очередной генератор структуры БД из метаданных для своей организации.
Для первоначального заполнения структуры новой БД взяли, разумеется старую версию оной. Однако, в результате анализа структуры выяснилось, что мои предшественники вовсю пользовались зарезервированными словами типа LEVEL и DESC для именования столбцов таблиц. Надо при генерации БД это учитывать и заключать названия столбцов в двойные кавычки ("). Все бы ничего, но есть такой элемент структуры таблицы, как CHECK и в нем условие ограничения описано в виде SQL-выражения, например:
TYPE_ID is not null
или
Upper(Name)=Name
Каким образом обработать их?
Тум, ту-ру-руууум! Разумеется регулярными выражениями. Для этого мне нужно определить границы слов, чтоб не заменить случаем Unnamed в Un"name"d. К сожалению, регулярные выражения ORACLE не поддерживают операторы определения границ слова \< и \>, поэтому придется выполнить два дополнительных прохода по строке до и после замены, чтобы создать их самому. Самый глубоко вложенный regexp_replace реализует обрамление chr(2) вокруг всех символов, которые могут быть использованы для разделения искомых идентификаторов. Следующий regexp_replace производит нужную нам замену. Самый верхний regexp_replace восстанавливает первоначальный вид строки.
select
regexp_replace(
regexp_replace(
regexp_replace('"NAME" IS NULL OR UPPER(NAME)=UNNAMED_FUNC(NAME)', '([^[:alnum:]_$"])',chr(2) || '\1' || chr(2)),
'(\s|'||chr(2)||'|^)NAME(\s|'||chr(2)||'||$)',
'"NAME"'
),
chr(2),
null
)
from dual
Для первоначального заполнения структуры новой БД взяли, разумеется старую версию оной. Однако, в результате анализа структуры выяснилось, что мои предшественники вовсю пользовались зарезервированными словами типа LEVEL и DESC для именования столбцов таблиц. Надо при генерации БД это учитывать и заключать названия столбцов в двойные кавычки ("). Все бы ничего, но есть такой элемент структуры таблицы, как CHECK и в нем условие ограничения описано в виде SQL-выражения, например:
TYPE_ID is not null
или
Upper(Name)=Name
Каким образом обработать их?
Тум, ту-ру-руууум! Разумеется регулярными выражениями. Для этого мне нужно определить границы слов, чтоб не заменить случаем Unnamed в Un"name"d. К сожалению, регулярные выражения ORACLE не поддерживают операторы определения границ слова \< и \>, поэтому придется выполнить два дополнительных прохода по строке до и после замены, чтобы создать их самому. Самый глубоко вложенный regexp_replace реализует обрамление chr(2) вокруг всех символов, которые могут быть использованы для разделения искомых идентификаторов. Следующий regexp_replace производит нужную нам замену. Самый верхний regexp_replace восстанавливает первоначальный вид строки.
select
regexp_replace(
regexp_replace(
regexp_replace('"NAME" IS NULL OR UPPER(NAME)=UNNAMED_FUNC(NAME)', '([^[:alnum:]_$"])',chr(2) || '\1' || chr(2)),
'(\s|'||chr(2)||'|^)NAME(\s|'||chr(2)||'||$)',
'"NAME"'
),
chr(2),
null
)
from dual
цветом показаны:
обрабатываемое выражение
искомая строка
замещающая строка
Шаблон поиска (^[:alnum:]_$") учитывает все символы, которые могут входить в название идентификатора. Символ " - добавлен для того, чтобы идентификатор, уже обрамленный двойными кавычками, не множил их вокруг себя.