Функции для работы с Dictionary (Map)

0 views
Skip to first unread message

Andrei K.

unread,
Apr 10, 2014, 4:32:31 AM4/10/14
to ru-fi...@googlegroups.com

Нововведения в ФБ 3.0 (процедурные функции и локальные процедуры)
позволят еще больше логики из приложения вынести в БД
и выполнять на сервере.

Для сложных обработок будет крайне нехватать объектов
типа Dictionary (его же можно использовать как массив). Конечно,
можно обойтись временными таблицами, но работа с ними
будет гораздо более громоздкой и их надо создавать заранее.

Функции, которые можно было бы добавить:

// добавляет или присваивает значение по ключу
RDB$DICTIONARY_ADD(context, dictionary_name, key, value)

// проверяет наличие ключа
RDB$DICTIONARY_HAS(context, dictionary_name, key)

// возвращает количество элементов
RDB$DICTIONARY_COUNT(context, dictionary_name)

// удаляет элемент
RDB$DICTIONARY_REMOVE(context, dictionary_name, key)

//очищает словарь
RDB$DICTIONARY_CLEAR(context, dictionary_name)

context здесь это 'USER_SESSION' или 'USER_TRANSACTION'

Roman Simakov

unread,
Apr 10, 2014, 4:36:31 AM4/10/14
to FirebirdSQL
10 апреля 2014 г., 12:32 пользователь Andrei K. <gs1...@gmail.com> написал:
> Конечно,
> можно обойтись временными таблицами, но работа с ними
> будет гораздо более громоздкой и их надо создавать заранее.

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

--
Roman Simakov

Simonov Denis

unread,
Apr 10, 2014, 5:36:44 AM4/10/14
to ru-fi...@googlegroups.com
Andrei K. <gs1994-Re5JQEe...@public.gmane.org> писал(а) в
своём письме Thu, 10 Apr 2014 12:32:31 +0400:
Можно сделать свой Package и разместить туда все свои функции для работы
со словарём, а внутри они будут обращаться всё к той же GTT


--
Написано с помощью почтового клиента Opera: http://www.opera.com/mail/

Simonov Denis

unread,
Apr 10, 2014, 6:33:00 AM4/10/14
to ru-fi...@googlegroups.com
Andrei K. <gs1...@gmail.com> писал(а) в
своём письме Thu, 10 Apr 2014 12:32:31 +0400:


>
> Для сложных обработок будет крайне нехватать объектов
> типа Dictionary (его же можно использовать как массив). Конечно,
> можно обойтись временными таблицами, но работа с ними
> будет гораздо более громоздкой и их надо создавать заранее.
>
> Функции, которые можно было бы добавить:
>
> // добавляет или присваивает значение по ключу
> RDB$DICTIONARY_ADD(context, dictionary_name, key, value)
>
> // проверяет наличие ключа
> RDB$DICTIONARY_HAS(context, dictionary_name, key)
>
> // возвращает количество элементов
> RDB$DICTIONARY_COUNT(context, dictionary_name)
>
> // удаляет элемент
> RDB$DICTIONARY_REMOVE(context, dictionary_name, key)
>
> //очищает словарь
> RDB$DICTIONARY_CLEAR(context, dictionary_name)
>
> context здесь это 'USER_SESSION' или 'USER_TRANSACTION'
>

написал модуль реализующий это. Я думаю при желании его можно заточить под
твои нужды

CREATE GLOBAL TEMPORARY TABLE SESSION_DICTIONARY (
NAME VARCHAR(31) NOT NULL,
KEY_NAME VARCHAR(31) NOT NULL,
DIC_VALUE VARCHAR(255)
) ON COMMIT PRESERVE ROWS;

ALTER TABLE SESSION_DICTIONARY ADD CONSTRAINT PK_SESSION_DICTIONARY
PRIMARY KEY (NAME, KEY_NAME);

CREATE GLOBAL TEMPORARY TABLE TRANSACTION_DICTIONARY (
NAME VARCHAR(31) NOT NULL,
KEY_NAME VARCHAR(31) NOT NULL,
DIC_VALUE VARCHAR(255)
) ON COMMIT DELETE ROWS;

ALTER TABLE TRANSACTION_DICTIONARY ADD CONSTRAINT
PK_TRANSACTION_DICTIONARY PRIMARY KEY (NAME, KEY_NAME);

CREATE EXCEPTION E_INCORRECT_DICTIONARY_CONTEXT 'Не корректный контекст
для словаря';

SET TERM ^;

CREATE OR ALTER PACKAGE DICTIONARY
AS
begin
-- добавляет или присваивает значение по ключу
function ADD_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31),
dic_value varchar(255)) returns varchar(255);

-- проверяет наличие ключа
function HAS_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns boolean;

-- возвращает количество элементов
function COUNT_ITEM(context varchar(31),
dictionary_name varchar(31)) returns int;

-- удаляет элемент
function REMOVE_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns varchar(255);

--очищает словарь
function CLEAR(context varchar(31),
dictionary_name varchar(31)) returns int;

-- возвращает элемент
function GET_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns varchar(255);
end^

RECREATE PACKAGE BODY DICTIONARY
AS
begin

/*************************************/
-- Реализация приватных функций
/*************************************/

-- проверяет правильность контекста
procedure CHECK_CONTEXT(context varchar(31))
as
begin
if (UPPER(context) not in ('USER_SESSION', 'USER_TRANSACTION')) then
exception E_INCORRECT_DICTIONARY_CONTEXT;
end

/*************************************/
-- Реализация публичных функций
/*************************************/

-- добавляет или присваивает значение по ключу
function ADD_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31),
dic_value varchar(255)) returns varchar(255)
as
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
insert into SESSION_DICTIONARY(name, key_name, dic_value)
values (:dictionary_name, :key_name, :dic_value);
return dic_value;
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
insert into TRANSACTION_DICTIONARY(name, key_name, dic_value)
values (:dictionary_name, :key_name, :dic_value);
return dic_value;
end
end

-- проверяет наличие ключа
function HAS_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns boolean
as
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
return EXISTS(select *
from SESSION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name);
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
return EXISTS(select *
from TRANSACTION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name);
end
end

-- возвращает количество элементов
function COUNT_ITEM(context varchar(31),
dictionary_name varchar(31)) returns int
as
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
return (select count(*)
from SESSION_DICTIONARY
where name = :dictionary_name);
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
return (select count(*)
from TRANSACTION_DICTIONARY
where name = :dictionary_name);
end
end

-- удаляет элемент
function REMOVE_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns varchar(255)
as
declare variable xValue varchar(255);
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
delete from SESSION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name
returning dic_value
into xValue;
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
delete from TRANSACTION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name
returning dic_value
into xValue;
end
return xValue;
end

--очищает словарь
function CLEAR(context varchar(31),
dictionary_name varchar(31)) returns int
as
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
delete from SESSION_DICTIONARY
where name = :dictionary_name;
return ROW_COUNT;
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
delete from TRANSACTION_DICTIONARY
where name = :dictionary_name;
return ROW_COUNT;
end
end

-- возвращает элемент
function GET_ITEM(context varchar(31),
dictionary_name varchar(31),
key_name varchar(31)) returns varchar(255)
as
declare variable xValue varchar(255);
begin
execute procedure CHECK_CONTEXT(:context);
if (UPPER(context) = 'USER_SESSION') then
begin
select dic_value
from SESSION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name
into xValue;
end
if (UPPER(context) = 'USER_TRANSACTION') then
begin
select dic_value
from TRANSACTION_DICTIONARY
where name = :dictionary_name and
key_name = :key_name
into xValue;
end
return xValue;
end
end^

SET TERM ;^

Roman Simakov

unread,
Apr 10, 2014, 7:05:56 AM4/10/14
to FirebirdSQL
Нет, не хочу быть занудой, но пардон это все для чего? Чтобы вместо

> insert into SESSION_DICTIONARY(name, key_name, dic_value) values (:dictionary_name, :key_name, :dic_value);
писать
ADD_ITEM(context, dictionary_name, key_name)

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


--
Roman Simakov

Simonov Denis

unread,
Apr 10, 2014, 7:50:15 AM4/10/14
to ru-fi...@googlegroups.com
Roman Simakov <roman.simakov-Re5J...@public.gmane.org>
писал(а) в своём письме Thu, 10 Apr 2014 15:05:56 +0400:
ну мне они не нужны. Я просто показал вопрашающему что это не сложно
реализовать.
Да и потестировал заодно пакеты.

Andrei K.

unread,
May 14, 2014, 5:38:05 AM5/14/14
to ru-fi...@googlegroups.com, sim-...@list.ru

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




On Thursday, April 10, 2014 2:50:15 PM UTC+3, Simonov Denis wrote:
Roman Simakov <roman.simakov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>  
Reply all
Reply to author
Forward
0 new messages