FirebirdSQL logo
 Firebird APIСтруктура UDR 

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

Синтаксис
{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 ;^

Внешние триггеры

Синтаксис
{CREATE [OR ALTER] | RECREATE} TRIGGER trigname
{
    <relation_trigger_legacy>
  | <relation_trigger_sql2003>
  | <database_trigger>
  | <ddl_trigger>
}
<external-body>

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

<relation_trigger_legacy> ::=
  FOR {tablename | viewname}
  [ACTIVE | INACTIVE]
  {BEFORE | AFTER} <mutation_list>
  [POSITION number]

<relation_trigger_sql2003> ::=
  [ACTIVE | INACTIVE]
  {BEFORE | AFTER} <mutation_list>
  [POSITION number]
  ON {tablename | viewname}

<database_trigger> ::=
  [ACTIVE | INACTIVE]
  ON db_event
  [POSITION number]

<ddl_trigger> ::=
  [ACTIVE | INACTIVE]
  {BEFORE | AFTER} <ddl_events>
  [POSITION number]

<mutation_list> ::= <mutation> [OR <mutation> [OR <mutation>]]

<mutation> ::= INSERT | UPDATE | DELETE

<db_event> ::=
    CONNECT
  | DISCONNECT
  | TRANSACTION START
  | TRANSACTION COMMIT
  | TRANSACTION ROLLBACK


<ddl_events> ::=
    ANY DDL STATEMENT
  | <ddl_event_item> [{OR <ddl_event_item>} ...]

<ddl_event_item> ::=
    CREATE TABLE | ALTER TABLE | DROP TABLE
  | CREATE PROCEDURE | ALTER PROCEDURE | DROP PROCEDURE
  | CREATE FUNCTION | ALTER FUNCTION | DROP FUNCTION
  | CREATE TRIGGER | ALTER TRIGGER | DROP TRIGGER
  | CREATE EXCEPTION | ALTER EXCEPTION | DROP EXCEPTION
  | CREATE VIEW | ALTER VIEW | DROP VIEW
  | CREATE DOMAIN | ALTER DOMAIN | DROP DOMAIN
  | CREATE ROLE | ALTER ROLE | DROP ROLE
  | CREATE SEQUENCE | ALTER SEQUENCE | DROP SEQUENCE
  | CREATE USER | ALTER USER | DROP USER
  | CREATE INDEX | ALTER INDEX | DROP INDEX
  | CREATE COLLATION | DROP COLLATION
  | ALTER CHARACTER SET
  | CREATE PACKAGE | ALTER PACKAGE | DROP PACKAGE
  | CREATE PACKAGE BODY | DROP PACKAGE BODY
  | CREATE MAPPING | ALTER MAPPING | DROP MAPPING

Внешний триггер можно изменить с помощью оператора ALTER TRIGGER.

Синтаксис
ALTER TRIGGER trigname {
[ACTIVE | INACTIVE]
[
    {BEFORE | AFTER} {<mutation_list> | <ddl_events>}
  | ON db_event
]
[POSITION number]
[<external-body>]

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

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

<mutation_list> ::= <mutation> [OR <mutation> [OR <mutation>]]

<mutation> ::= { INSERT | UPDATE | DELETE }

Удалить внешний триггер можно с помощью оператора DROP TRIGGER.

Синтаксис
DROP TRIGGER trigname
Table 1. Некоторые параметры внешнего триггера
Параметр Описание

trigname

Имя триггера. Может содержать до 31 байта.

relation_trigger_legacy

Объявление табличного триггера(унаследованное).

relation_trigger_sql2003

Объявление табличного триггера согласностандарту SQL-2003.

database_trigger

Объявление триггера базы данных.

ddl_trigger

Объявление DDL триггера.

tablename

Имя таблицы.

viewname

Имя представления.

mutation_list

Список событий таблицы.

mutation

Одно из событий таблицы.

db_event

Событие соединения или транзакции.

ddl_events

Список событий изменения метаданных.

ddl_event_item

Одно из событий изменения метаданных.

number

Порядок срабатывания триггера. От 0 до 32767.

extbody

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

module name

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

routine name

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

misc info

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

engine

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

Приведём примеры объявления внешних триггеров с пояснениями.

create database 'c:\temp\slave.fdb';

create table persons (
    id integer not null,
    name varchar(60) not null,
    address varchar(60),
    info blob sub_type text
);

commit;

create database 'c:\temp\master.fdb';

create table persons (
    id integer not null,
    name varchar(60) not null,
    address varchar(60),
    info blob sub_type text
);

create table replicate_config (
    name varchar(31) not null,
    data_source varchar(255) not null
);

insert into replicate_config (name, data_source)
   values ('ds1', 'c:\temp\slave.fdb');

create trigger persons_replicate
after insert on persons
external name 'udrcpp_example!replicate!ds1'
engine udr;

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

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