FirebirdSQL logo

Объявления UDR

UDR могут быть добавлены или удалены из базы данных с помощью DDL командподобно тому, как вы добавляете или удаляете обычные PSQL процедуры,функции или триггеры. В этом случае вместо тела триггера указываетсяместо его расположения во внешнем модуле с помощью предложения EXTERNAL NAME.

Рассмотрим синтаксис этого предложения, он будет общим для внешнихпроцедур, функций и триггеров.

Синтаксис
EXTERNAL NAME '<extname>' ENGINE <engine>
[AS <extbody>]

<extname> ::= '<module name>!<routine name>[!<misc info>]'

Аргументом этого предложения EXTERNAL NAME является строка, указывающаяна расположение функции во внешнем модуле. Для внешних модулей,использующих движок UDR, в этой строке через разделитель указано имявнешнего модуля, имя функции внутри модуля и определённая пользователеминформация. В качестве разделителя используется восклицательный знак(!).

В предложении ENGINE указывается имя движка для обработки подключениявнешних модулей. В Firebird для работы с внешними модулями написанных накомпилируемых языках (C, C++, Pascal) используется движок UDR. Длявнешних функций написанных на Java требуется движок Java.

После ключевого слова AS может быть указан строковый литерал — "тело"внешнего модуля (процедуры, функции или триггера), оно может бытьиспользовано внешним модулем для различных целей. Например, может бытьуказан SQL запрос для доступа к внешней БД или текст на некотором языкедля интерпретации вашей функцией.

Внешние функции

Синтаксис
{CREATE [OR ALTER] | RECREATE} FUNCTION funcname [(<inparam> [, <inparam> ...])]
RETURNS <type> [COLLATE collation] [DETERMINISTIC]
EXTERNAL NAME <extname> ENGINE <engine>
[AS <extbody>]


<inparam> ::= <param_decl> [{= | DEFAULT} <value>]

<value> ::=  {literal | NULL | context_var}

<param_decl> ::= paramname <type> [NOT NULL] [COLLATE collation]

<extname> ::= '<module name>!<routine name>[!<misc info>]'

<type> ::= <datatype> | [TYPE OF] domain | TYPE OF COLUMN rel.col

<datatype> ::=
    {SMALLINT | INT[EGER] | BIGINT}
  | BOOLEAN
  | {FLOAT | DOUBLE PRECISION}
  | {DATE | TIME | TIMESTAMP}
  | {DECIMAL | NUMERIC} [(precision [, scale])]
  | {CHAR | CHARACTER | CHARACTER VARYING | VARCHAR} [(size)]
    [CHARACTER SET charset]
  | {NCHAR | NATIONAL CHARACTER | NATIONAL CHAR} [VARYING] [(size)]
  | BLOB [SUB_TYPE {subtype_num | subtype_name}]
    [SEGMENT SIZE seglen] [CHARACTER SET charset]
  | BLOB [(seglen [, subtype_num])]

Все параметры внешней функции можно изменить с помощью оператора ALTERFUNCTION.

Синтаксис
ALTER FUNCTION funcname [(<inparam> [, <inparam> ...])]
RETURNS <type> [COLLATE collation] [DETERMINISTIC]
EXTERNAL NAME <extname> ENGINE <engine>
[AS <extbody>]

<extname> ::= '<module name>!<routine name>[!<misc info>]'

Удалить внешнюю функцию можно с помощью оператора DROP FUNCTION.

Синтаксис
DROP FUNCTION funcname
Table 1. Некоторые параметры внешней функции
Параметр Описание

funcname

Имя хранимой функции. Может содержать до 31 байта.

inparam

Описание входного параметра.

module name

Имя внешнего модуля, в котором расположена функция.

routine name

Внутреннее имя функции внутри внешнего модуля.

misc info

Определяемая пользователем информация для передачи в функциювнешнего модуля.

engine

Имя движка для использования внешних функций. Обычноуказывается имя UDR.

extbody

Тело внешней функции. Строковый литерал который можетиспользоваться UDR для различных целей.

Здесь мы не будем описывать синтаксис входных параметров и выходногорезультата. Он полностью соответствует синтаксису для обычных PSQLфункций, который подробно описан в "Руководстве по языку SQL". Вместоэтого приведём примеры объявления внешних функций с пояснениями.

create function sum_args (
    n1 integer,
    n2 integer,
    n3 integer
)
returns integer
external name 'udrcpp_example!sum_args'
engine udr;

Реализация функции находится в модуле udrcpp_example. Внутри этогомодуля функция зарегистрирована под именем sum_args. Для работы внешнейфункции используется движок UDR.

create or alter function regex_replace (
  regex varchar(60),
  str varchar(60),
  replacement varchar(60)
)
returns varchar(60)
external name 'org.firebirdsql.fbjava.examples.fbjava_example.FbRegex.replace(
      String, String, String)'
engine java;

Реализация функции находится в статической функции replace классаorg.firebirdsql.fbjava.examples.fbjava_example.FbRegex. Для работывнешней функции используется движок Java.

Внешние процедуры

Синтаксис
{CREATE [OR ALTER] | RECREATE} PROCEDURE procname [(<inparam> [, <inparam> ...])]
RETURNS (<outparam> [, <outparam> ...])
EXTERNAL NAME <extname> ENGINE <engine>
[AS <extbody>]

<inparam> ::= <param_decl> [{= | DEFAULT} <value>]

<outparam>  ::=  <param_decl>

<value> ::=  {literal | NULL | context_var}

<param_decl> ::= paramname <type> [NOT NULL] [COLLATE collation]

<extname> ::= '<module name>!<routine name>[!<misc info>]'

<type> ::= <datatype> | [TYPE OF] domain | TYPE OF COLUMN rel.col

<datatype> ::=
    {SMALLINT | INT[EGER] | BIGINT}
  | BOOLEAN
  | {FLOAT | DOUBLE PRECISION}
  | {DATE | TIME | TIMESTAMP}
  | {DECIMAL | NUMERIC} [(precision [, scale])]
  | {CHAR | CHARACTER | CHARACTER VARYING | VARCHAR} [(size)]
    [CHARACTER SET charset]
  | {NCHAR | NATIONAL CHARACTER | NATIONAL CHAR} [VARYING] [(size)]
  | BLOB [SUB_TYPE {subtype_num | subtype_name}]
    [SEGMENT SIZE seglen] [CHARACTER SET charset]
  | BLOB [(seglen [, subtype_num])]

Все параметры внешней процедуры можно изменить с помощью оператора ALTER PROCEDURE.

Синтаксис
ALTER PROCEDURE procname [(<inparam> [, <inparam> ...])]
RETURNS (<outparam> [, <outparam> ...])
EXTERNAL NAME <extname> ENGINE <engine>
[AS <extbody>]

Удалить внешнюю процедуру можно с помощью оператора DROP PROCEDURE.

Синтаксис
DROP PROCEDURE procname
Table 1. Некоторые параметры внешней процедуры
Параметр Описание

procname

Имя хранимой процедуры. Может содержать до 31 байта.

inparam

Описание входного параметра.

outparam

Описание выходного параметра.

module name

Имя внешнего модуля, в котором расположена процедура.

routine name

Внутреннее имя процедуры внутри внешнего модуля.

misc info

Определяемая пользователем информация для передачи впроцедуру внешнего модуля.

engine

Имя движка для использования внешних процедур. Обычноуказывается имя UDR.

extbody

Тело внешней процедуры. Строковый литерал который можетиспользоваться UDR для различных целей.

Здесь мы не будем описывать синтаксис входных и выходных параметров. Онполностью соответствует синтаксису для обычных PSQL процедур, которыйподробно описан в "Руководстве по языку SQL". Вместо этого приведёмпримеры объявления внешних процедур с пояснениями.

create procedure gen_rows_pascal (
    start_n integer not null,
    end_n integer not null
)
returns (
    result integer not null
)
external name 'pascaludr!gen_rows'
engine udr;

Реализация функции находится в модуле pascaludr. Внутри этого модуляпроцедура зарегистрирована под именем gen_rows. Для работы внешнейпроцедуры используется движок UDR.

create or alter procedure write_log (
  message varchar(100)
)
external name 'pascaludr!write_log'
engine udr;

Реализация функции находится в модуле pascaludr. Внутри этого модуляпроцедура зарегистрирована под именем write_log. Для работы внешнейпроцедуры используется движок UDR.

create or alter procedure employee_pgsql (
  -- Firebird 3.0.0 has a bug with external procedures without parameters
  dummy integer = 1
)
returns (
  id type of column employee.id,
  name type of column employee.name
)
external name 'org.firebirdsql.fbjava.examples.fbjava_example.FbJdbc
    .executeQuery()!jdbc:postgresql:employee|postgres|postgres'
engine java
as 'select * from employee';

Реализация функции находится в статической функции executeQuery классаorg.firebirdsql.fbjava.examples.fbjava_example.FbJdbc. Послевосклицательного знака "!" располагаются сведения для подключения квнешней базе данных через JDBC. Для работы внешней функции используетсядвижок Java. Здесь в качестве "тела" внешней процедуру передаётся SQLзапрос для извлечения данных.

Note
Замечание

В этой процедуре используется заглушка, в которой передаётсянеиспользуемый параметр. Это связано с тем, что в Firebird 3.0присутствует баг с обработкой внешних процедур без параметров.

Размещение внешних процедур и функций внутри пакетов

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

Синтаксис
{CREATE [OR ALTER] | RECREATE} PACKAGE package_name
AS
BEGIN
  [<package_item> ...]
END

{CREATE | RECREATE} PACKAGE BODY package_name
AS
BEGIN
  [<package_item> ...]
  [<package_body_item> ...]
END

<package_item> ::=
    <function_decl>;
  | <procedure_decl>;

<function_decl> ::=
  FUNCTION func_name [(<in_params>)]
  RETURNS <type> [COLLATE collation]
  [DETERMINISTIC]

<procedure_decl> ::=
  PROCEDURE proc_name [(<in_params>)]
  [RETURNS (<out_params>)]

<package_body_item> ::=
    <function_impl>
  | <procedure_impl>

<function_impl> ::=
  FUNCTION func_name [(<in_impl_params>)]
  RETURNS <type> [COLLATE collation]
  [DETERMINISTIC]
  <routine body>

<procedure_impl> ::=
  PROCEDURE proc_name [(<in_impl_params>)]
  [RETURNS (<out_params>)]
  <routine body>

<routine body> ::= <sql routine body> | <external body reference>

<sql routine body> ::=
  AS
    [<declarations>]
  BEGIN
    [<PSQL_statements>]
  END

<declarations> ::= <declare_item> [<declare_item> ...]

<declare_item> ::=
    <declare_var>;
  | <declare_cursor>;
  | <subroutine declaration>;
  | <subroutine implimentation>

<subroutine declaration> ::= <subfunc_decl> | <subproc_decl>

<subroutine implimentation> ::= <subfunc_impl> | <subproc_impl>

<external body reference> ::=
  EXTERNAL NAME <extname> ENGINE <engine> [AS <extbody>]

<extname> ::= '<module name>!<routine name>[!<misc info>]'

Для внешних процедур и функций в заголовке пакета указываются имя,входные параметры, их типы, значения по умолчанию, и выходные параметры,а в теле пакета всё то же самое, кроме значений по умолчанию, а такжеместо расположения во внешнем модуле (предложение EXTERNAL NAME), имядвижка, и возможно "тело" процедуры/функции.

Предположим вы написали UDR для работы с регулярными выражениями,которая расположена во внешнем модуле (динамической библиотеке) PCRE, иу вас есть ещё несколько UDR выполняющих другие задачи. Если бы мы неиспользовали PSQL пакеты, то все наши внешние процедуры и функции былибы перемешаны как друг с другом, так и с обычными PSQL процедурами ифункциями. Это усложняет поиск зависимостей и внесение изменений вовнешние модули, а кроме того создаёт путаницу, и заставляет как минимумиспользовать префиксы для группировки процедур и функций. PSQL пакетызначительно облегчают нам эту задачу.

SET TERM ^;

CREATE OR ALTER PACKAGE REGEXP
AS
BEGIN
  PROCEDURE preg_match(
      APattern VARCHAR(8192), ASubject VARCHAR(8192))
    RETURNS (Matches VARCHAR(8192));

  FUNCTION preg_is_match(
      APattern VARCHAR(8192), ASubject VARCHAR(8192))
    RETURNS BOOLEAN;

  FUNCTION preg_replace(
      APattern VARCHAR(8192),
      AReplacement VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS VARCHAR(8192);

  PROCEDURE preg_split(
      APattern VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS (Lines VARCHAR(8192));

  FUNCTION preg_quote(
      AStr VARCHAR(8192),
      ADelimiter CHAR(10) DEFAULT NULL)
    RETURNS VARCHAR(8192);
END^

RECREATE PACKAGE BODY REGEXP
AS
BEGIN
  PROCEDURE preg_match(
      APattern VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS (Matches VARCHAR(8192))
    EXTERNAL NAME 'PCRE!preg_match' ENGINE UDR;

  FUNCTION preg_is_match(
      APattern VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS BOOLEAN
  AS
  BEGIN
    RETURN EXISTS(
      SELECT * FROM preg_match(:APattern, :ASubject));
  END

  FUNCTION preg_replace(
      APattern VARCHAR(8192),
      AReplacement VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS VARCHAR(8192)
    EXTERNAL NAME 'PCRE!preg_replace' ENGINE UDR;

  PROCEDURE preg_split(
      APattern VARCHAR(8192),
      ASubject VARCHAR(8192))
    RETURNS (Lines VARCHAR(8192))
    EXTERNAL NAME 'PCRE!preg_split' ENGINE UDR;

  FUNCTION preg_quote(
      AStr VARCHAR(8192),
      ADelimiter CHAR(10))
    RETURNS VARCHAR(8192)
    EXTERNAL NAME 'PCRE!preg_quote' ENGINE UDR;
END^

SET TERM ;^