2. www.ibase.ru
Что нового в Firebird 3.0
•Common SQL
• Оконные (аналитические) функции
• Статистические функции
• Функции линейной регрессии
• Полный синтаксис оператора MERGE согласно SQL-
2008
• MERGE … RETURNING
• Алиасы в RETURNING
• OFFSET … FETCH
3. www.ibase.ru
Что нового в Firebird 3.0
•Common SQL (продолжение)
• SUBSTRING с регулярными выражениями
• Альтернативы для экранирования кавычек
• Тип BOOLEAN
• Псевдо столбец RDB$RECORD_VERSION
• Стабильность курсора в запросах на модификацию
данных
• Запрет смешения явных и неявных JOIN
• Внутреннее соединения с ХП
4. www.ibase.ru
Что нового в Firebird 3.0
•Procedural SQL
• SQL функции
• Подпрограммы
• Внешние процедуры, функции и триггеры
• Пакеты
• Исключения с параметрами: EXCEPTION …
USING(…)
• SQLSTATE в обработчике WHEN
• CONTNINUE в циклах
• Ссылки на курсоры как переменные типа запись
• Двунаправленные курсоры
5. www.ibase.ru
Что нового в Firebird 3.0
•DDL
• Управление допустимостью NULL значений
• ALTER DOMAIN … {SET | DROP} NOT NULL
• ALTER COLUMN … {SET | DROP} NOT NULL
• IDENTITY столбцы
• SEQUENCE и GENERATOR
• теперь синонимы
• RECREATE …, CREATE OR ALTER …
• INCREMENT [BY]
• CREATE DATABASE … ROLE …
6. www.ibase.ru
Что нового в Firebird 3.0
•DDL (продолжение)
• ALTER DATABASE …
• SET DEFAULT CHARATER SET
• {SET | DROP} LINGER
• {ENCRYPT WITH … | DECRYPT}
• DROP SHADOW … [{PRESERVE | DELETE} FILE]
• DDL триггеры
7. www.ibase.ru
Что нового в Firebird 3.0
•Security
• Управление пользователями
• ACTIVE | INACTIVE
• USING PLUGIN …
• TAGS (…)
• CREATE OR ALTER
• ALTER CURRENT USER
• SEC$USERS, SEC$USER_ATTRIBUTES …
• Привилегия USAGE
• Привилегия EXECUTE
8. www.ibase.ru
Что нового в Firebird 3.0
•Security (продолжение)
• DDL привилегии
• Уровня базы данных
• SET ROLE …, SET TRUSTED ROLE
• Отображение объектов безопасности ({CREATE |
ALTER | DROP} [GLOBAL] MAPPING …)
• Шифрование базы данных
12. www.ibase.ru
DML: Оконные функции
Синтаксис (продолжение)
<navigational_function> ::=
{LEAD | LAG} (<expr> [, <offset> [, <default>]])
| {FIRST_VALUE | LAST_VALUE} (<expr>)
| NTH_VALUE(<expr>, <offset>) [FROM_FIRST | FROM_LAST]
Замечание: Функции FIRST_VALUE, LAST_VALUE и NTH_VALUE
оперируют на кадрах окна. В настоящее время в Firebird кадры всегда
определены с первой до текущей строки, но не последней, т.е.
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
В настоящее время предложение фрейма не реализовано см. CORE-3647.
13. www.ibase.ru
DML: Оконные функции
Чего не хватает (CORE-3647)
<window frame clause> ::=
{ROWS | RANGE} <window frame extent>
<window frame extent> ::=
<window frame start> | <window frame between>
<window frame start> ::=
UNBOUNDED PRECEDING
| <value> PRECEDING
| CURRENT ROW
<window frame between> ::=
BETWEEN <window frame bound> AND <window frame bound>
<window frame bound> ::=
<window frame start>
| UNBOUNDED FOLLOWING
| <value> FOLLOWING
14. www.ibase.ru
DML: Оконные функции
Агрегатные функции:
Без оконных функций
SELECT
id, name, department, salary,
salary / (SELECT SUM(salary) FROM employee) percentage
FROM employee ORDER BY name;
Select Expression
-> Singularity Check
-> Aggregate
-> Table "EMPLOYEE" Full Scan
Select Expression
-> Sort (record length: 140, key length: 36)
-> Table "EMPLOYEE" Full Scan
15. www.ibase.ru
DML: Оконные функции
Агрегатные функции:
С оконными функциями
SELECT
id, name, department, salary,
salary / SUM(salary) OVER () percentage
FROM employee ORDER BY name;
Select Expression
-> Sort (record length: 84, key length: 8)
-> Window
-> Record Buffer (record length: 65)
-> Table "EMPLOYEE" Full Scan
16. www.ibase.ru
DML: Оконные функции
Агрегатные функции (секционирование):
SELECT
id, department, salary,
salary / SUM(salary) OVER (PARTITION BY department) percentage
FROM employee
ORDER BY id;
id department salary percentage
-- ---------- ------ ----------
1 R & D 10.00 0.3448
2 SALES 12.00 0.6000
3 SALES 8.00 0.4000
4 R & D 9.00 0.3103
5 R & D 10.00 0.3448
17. www.ibase.ru
DML: Оконные функции
Агрегатные функции (сортировка):
SELECT
payments.id AS id,
payments.bydate AS bydate,
credit.amount AS credit_amount,
payments.amount AS pay,
SUM(payments.amount) OVER(ORDER BY payments.bydate)
AS s_amount,
SUM(payments.amount) OVER(ORDER BY payments.bydate,
payments.id) AS s_amount2,
credit.amount
- SUM(payments.amount) OVER(ORDER BY payments.bydate,
payments.id) AS balance
FROM credit
JOIN payments ON payments.credit_id = credit.id
WHERE credit.id = 1
ORDER BY payments.bydate
25. www.ibase.ru
DML: Функции регрессии
Синтаксис
• REGR_AVGX(y, x) -- среднее независимой переменной
• REGR_AVGY(y, x) -- среднее зависимой переменной
• REGR_COUNT(y, x) -- количество непустых пар
• REGR_INTERCEPT(y, x) -- точка пересечения линии регрессии с
осью Y
• REGR_R2(y, x) -- коэффициент детерминации
• REGR_SLOPE(y, x) -- угол наклона линии регрессии
• REGR_SXX(y, x) -- диагностическая
• REGR_SXY(y, x) -- диагностическая
• REGR_SYY(y, x) -- диагностическая
26. www.ibase.ru
DML: Функции регрессии
Пример
WITH RECURSIVE years(byyear) AS (
SELECT 1991 FROM rdb$database UNION ALL
SELECT byyear+1 FROM years WHERE byyear < 2020
),
s AS (
SELECT EXTRACT(YEAR FROM order_date) AS byyear,
SUM(total_value) AS total_value
FROM sales GROUP BY 1
),
regr AS (
SELECT REGR_INTERCEPT(total_value, byyear) as intercept,
REGR_SLOPE(total_value, byyear) as slope
FROM s)
SELECT years.byyear AS byyear,
intercept + (slope * years.byyear) AS total_value
FROM years CROSS JOIN regr
28. www.ibase.ru
DML: MERGE согласно SQL:2008
Синтаксис
MERGE INTO target [[AS] target_alias]
USING <source> [[AS] source_alias]
ON <join condition>
<merge when> [<merge when> ...]
[RETURNING <returning_list> [INTO <variable_list>]]
<merge when> ::= <merge when matched> | <merge when not matched>
<merge when matched> ::=
WHEN MATCHED [ AND <condition> ]
THEN { UPDATE SET fieldname = <value> [fieldname = <value>] |
DELETE }
<merge when not matched> ::=
WHEN NOT MATCHED [ AND <condition> ]
THEN INSERT [ (<column_list>) ]
VALUES (<value_list>)
29. www.ibase.ru
DML: MERGE согласно SQL:2008
Множество WHEN [NOT] MATCHED и DELETE
MERGE INTO PRODUCT_IVENTORY AS TARGET
USING (SELECT SL.ID_PRODUCT,
SUM(SL.QUANTITY)
FROM SALES_ORDER_LINE SL
JOIN SALES_ORDER S ON S.ID = SL.ID_SALES_ORDER
WHERE S.BYDATE = CURRENT_DATE
GROUP BY 1
) AS SRC(ID_PRODUCT, QUANTITY)
ON TARGET.ID_PRODUCT = SRC.ID_PRODUCT
WHEN MATCHED AND TARGET.QUANTITY - SRC.QUANTITY <= 0 THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
TARGET.QUANTITY = TARGET.QUANTITY - SRC.QUANTITY,
TARGET.BYDATE = CURRENT_DATE
30. www.ibase.ru
DML: MERGE согласно SQL:2008
RETURNING
MERGE INTO PRODUCT_IVENTORY AS TARGET
USING (SELECT SL.ID_PRODUCT,
SUM(SL.QUANTITY)
FROM SALES_ORDER_LINE SL
JOIN SALES_ORDER S ON S.ID = SL.ID_SALES_ORDER
WHERE S.BYDATE = CURRENT_DATE AND SL.ID_PRODUCT = :ID_PRODUCT
GROUP BY 1
) AS SRC(ID_PRODUCT, QUANTITY)
ON TARGET.ID_PRODUCT = SRC.ID_PRODUCT
WHEN MATCHED AND TARGET.QUANTITY - SRC.QUANTITY <= 0 THEN
DELETE
WHEN MATCHED THEN
UPDATE SET
TARGET.QUANTITY = TARGET.QUANTITY - SRC.QUANTITY,
TARGET.BYDATE = CURRENT_DATE
RETURNING OLD.QUANTITY, NEW.QUANTITY, SRC.QUANTITY
31. www.ibase.ru
DML: Алиасы в RETURNING
Пример
-- without aliases
UPDATE T1 SET F2 = F2 * 10
RETURNING OLD.F2, NEW.F2;
-- with aliases
UPDATE T1 SET F2 = F2 * 10
RETURNING OLD.F2 OLD_F2, NEW.F2 AS NEW_F2;
33. www.ibase.ru
DML: OFFSET … FETCH
Пример
SELECT *
FROM T1
ORDER BY COL1
OFFSET 10 ROWS;
SELECT *
FROM (
SELECT *
FROM T1
ORDER BY COL1 DESC
OFFSET 1 ROW
FETCH NEXT 10 ROWS ONLY
) a
ORDER BY a.COL1
FETCH FIRST ROW ONLY
34. www.ibase.ru
DML: SUBSTRING c RegExp
Синтаксис
SUBSTRING (str SIMILAR <similar_pattern> ESCAPE <escape>)
<similar_pattern> ::=
<similar pattern: R1>
<escape>"<similar pattern: R2><escape>"
<similar pattern: R3>
Особенности:
• Возвращается часть строки соответствующая выражению R2
• Для возвращаемого значения истинно выражение
str SIMILAR TO R1 || R2 || R3 ESCAPE <escape>
35. www.ibase.ru
DML: SUBSTRING c RegExp
Примеры
SUBSTRING('abcabc' SIMILAR 'a#"bcab#"c' ESCAPE '#') -- bcab
SUBSTRING('abcabc' SIMILAR 'a#"%#"c' ESCAPE '#') -- bcab
SUBSTRING('abcabc' SIMILAR '_#"%#"_' ESCAPE '#') -- bcab
SUBSTRING('abcabc' SIMILAR '#"(abc)*#"' ESCAPE '#') -- abcabc
SUBSTRING('abcabc' SIMILAR '#"abc#"' ESCAPE '#') -- <null>
36. www.ibase.ru
DML: Альтернативное экранирование
кавычек
Синтаксис
Q <quote> <alternate start char>
[{ <char> }...]
<alternate end char> <quote>
Особенности:
• Если <alternate start char> является одним из символов '(', '{', '[' или '<', то
<alternate end char> должен быть использован в паре с соответствующим
"партнёром", а именно ')', '}', ']' или '>'. В других случаях <alternate end
char> совпадает с <alternate start char>.
40. www.ibase.ru
DML: Тип BOOLEAN
Примеры
CREATE TABLE TBOOL (ID INT, BVAL BOOLEAN);
COMMIT;
INSERT INTO TBOOL VALUES (1, TRUE);
INSERT INTO TBOOL VALUES (2, 2 = 4);
INSERT INTO TBOOL VALUES (3, NULL = 1);
COMMIT;
SELECT * FROM TBOOL
ID BVAL
---- -------
1 <true>
2 <false>
3 <null>
41. www.ibase.ru
DML: Тип BOOLEAN
Примеры (продолжение)
-- Проверка TRUE значения
SELECT * FROM TBOOL WHERE BVAL
-- Проверка UNKNOWN значения
SELECT * FROM TBOOL WHERE BVAL IS UNKNOWN
-- Логические значения в SELECT списке
SELECT ID, BVAL, BVAL AND ID < 2
FROM TBOOL
-- PSQL объявления с начальным значением
DECLARE VARIABLE VAR1 BOOLEAN = TRUE;
-- Допустимый синтаксис, но как и сравнение
-- с NULL, никогда не вернёт ни одной записи
SELECT * FROM TBOOL WHERE BVAL = UNKNOWN
SELECT * FROM TBOOL WHERE BVAL <> UNKNOWN
42. www.ibase.ru
DML: Стабильность курсора
Проявление
• Бесконечный цикл вставки (CORE-92)
INSERT INTO T
SELECT * FROM T
• DELETE удалит все записи (CORE-634)
DELETE FROM T
WHERE ID IN (SELECT FIRST 1 ID FROM T)
• Подвержены все DML операторы (INSERT, UPDATE, DELETE,
MERGE)
• Общий билет в трекере CORE-3362
43. www.ibase.ru
DML: Стабильность курсора
PSQL
• PSQL курсоры содержащие SUSPEND не стабильны
FOR SELECT NAME FROM T INTO :NAME
DO BEGIN
INSERT INTO T (NAME) VALUES (:NAME);
SUSPEND;
END
• PSQL курсоры не содержащие SUSPEND стабильны
FOR SELECT ID FROM T WHERE VAL IS NULL INTO :ID
DO BEGIN
UPDATE T SET VAL = 1
WHERE ID = :ID;
END
44. www.ibase.ru
DML: Смешение явных и неявных JOIN
(TA, TB JOIN TC)
эквивалентно TA, (TB JOIN C)
и не эквивалентно (TA, TB) JOIN C
Вызовет ошибку «Column does not belong to referenced table»
SELECT *
FROM TA, TB
JOIN TC ON TA.COL1 = TC.COL1
WHERE TA.COL2 = TB.COL2
Отработает без ошибок
SELECT *
FROM TA, TB
JOIN TC ON TB.COL1 = TC.COL1
WHERE TA.COL2 = TB.COL2
45. www.ibase.ru
DML: Внутренние JOIN с хранимыми
процедурами
Примеры
SELECT *
FROM T
JOIN MY_PROC(T.F1) P ON T.F2 = P.F2
• До Firebird 3.0 такой запрос вызывал ошибку «no current record for
fetch operation». Эту проблему решали так:
SELECT *
FROM T
LEFT JOIN MY_PROC(T.F1) P ON 1=1
WHERE T.F2 = P.F2
47. www.ibase.ru
PSQL: SQL функции
Синтаксис
{CREATE [OR ALTER] | ALTER | RECREATE} FUNCTION funcname
[(<inparam> [, <inparam> ...])]
RETURNS <type> [COLLATE collation] [DETERMINISTIC]
{ EXTERNAL NAME '<extname>' ENGINE <engine> }
| { AS
[<declarations>]
BEGIN
[<PSQL_statements>]
END
}
DROP FUNCTION funcname
48. www.ibase.ru
PSQL: SQL функции
Особенности
• Возвращает скалярный результат
• Для возврата значения функции используется
RETURN <value>
• Флаг DETERMINISTIC работает только для
функций без параметров
49. www.ibase.ru
PSQL: SQL функции
Примеры
CREATE FUNCTION ADD_INT(A INT, B INT DEFAULT 0)
RETURNS INT
AS
BEGIN
RETURN A+B;
END
Вызов
SELECT ADD_INT(2, 3) AS R FROM RDB$DATABASE
В PSQL
…
C = ADD_INT(A, B);
…
50. www.ibase.ru
PSQL: SQL функции
Флаг DETERMINISTIC
CREATE FUNCTION FN_T
RETURNS DOUBLE PRECISION DETERMINISTIC
AS
BEGIN
RETURN rand();
END
-- функция будет вычислена дважды и вернёт 2 разных значения
SELECT fn_t() FROM rdb$database
UNION ALL
SELECT fn_t() FROM rdb$database
-- функция будет вычислена единожды и вернёт одинаковые значения
WITH t(n) AS (
SELECT 1 FROM rdb$database
UNION ALL
SELECT 2 FROM rdb$database)
SELECT n, fn_t() FROM t
54. www.ibase.ru
PSQL: Подпрограммы
Особенности
• Подпрограмма не может быть вложена в другую подпрограмму.
Они поддерживаются только в основном модуле.
• В настоящее время подпрограмма не имеет прямого доступа для
использования переменных, курсоров и других подпрограмм из
основного модуля. Кроме того, подпрограмма не может вызывать
себя рекурсивно. Это может быть разрешено в будущем.
57. www.ibase.ru
PSQL: Пакеты
Синтаксис
{CREATE [OR ALTER] | ALTER | RECREATE} PACKAGE package_name
AS
BEGIN
[<package_item> ...]
END
{CREATE | ALTER | RECREATE} PACKAGE BODY package_name
AS
BEGIN
[<package_item> ...]
[<package_body_item> ...]
END
<package_item> ::= <function_decl>; | <procedure_decl>;
58. www.ibase.ru
PSQL: Пакеты
Синтаксис (продолжение)
<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]
{ EXTERNAL NAME '<extname>' ENGINE <engine> } |
{ AS
[<declarations>]
BEGIN
[<PSQL_statements>]
END
}
59. www.ibase.ru
PSQL: Пакеты
Синтаксис (продолжение)
<procedure_impl> ::=
PROCEDURE proc_name [(<in_impl_params>)]
[RETURNS (<out_params>)]
{ EXTERNAL NAME '<extname>' ENGINE <engine> } |
{ AS
[<declarations>]
BEGIN
[<PSQL_statements>]
END
}
Правила
• В теле пакеты должны быть реализованы все подпрограммы, стой же сигнатурой,
что и объявленные в заголовке и в начале тела пакета.
• Значения по умолчанию для параметров процедур не могут быть
переопределены (которые указываются в <package_item>). Это означает, что они
могут быть в <package_body_item> только для частных процедур, которые не
были объявлены.
60. www.ibase.ru
PSQL: Пакеты (примеры)
-- заголовок пакета
CREATE OR ALTER PACKAGE TEST
AS
BEGIN
PROCEDURE P1(I INT = 1) RETURNS (O INT); -- публичная процедура
END^
-- тело пакета, реализация
RECREATE PACKAGE BODY TEST
AS
BEGIN
FUNCTION F1(I INT) RETURNS INT; -- частная функция
PROCEDURE P1(I INT) RETURNS (O INT)
AS
BEGIN
O = F1(I); SUSPEND;
END
FUNCTION F1(I INT) RETURNS INT
AS
BEGIN
RETURN I * I;
END
END^
61. www.ibase.ru
PSQL: Пакеты (примеры)
CREATE OR ALTER PACKAGE REGEXP
AS
BEGIN
PROCEDURE preg_match(Pattern VARCHAR(8192),
Subject VARCHAR(8192))
RETURNS (Matches VARCHAR(8192));
FUNCTION preg_is_match(Pattern VARCHAR(8192),
Subject VARCHAR(8192))
RETURNS BOOLEAN;
FUNCTION preg_replace(Pattern VARCHAR(8192),
Replacement VARCHAR(8192), Subject VARCHAR(8192))
RETURNS VARCHAR(8192);
…
END
62. www.ibase.ru
PSQL: Пакеты (примеры)
RECREATE PACKAGE BODY REGEXP
AS
BEGIN
PROCEDURE preg_match(Pattern varchar(8192),
Subject varchar(8192))
RETURNS (Matches varchar(8192))
EXTERNAL name 'PCRE!preg_match' ENGINE UDR;
FUNCTION preg_is_match(Pattern varchar(8192),
Subject varchar(8192)) RETURNS BOOLEAN
AS
BEGIN
RETURN EXISTS(SELECT * FROM preg_match(:Pattern, :Subject));
END
…
END
63. www.ibase.ru
PSQL: Пакеты
Синтаксис комментариев
COMMENT ON PACKAGE package_name
IS {'sometext' | NULL}
COMMENT ON PROCEDURE package_name.proc_name
IS {'sometext' | NULL}
COMMENT ON FUNCTION package_name.func_name
IS {'sometext' | NULL}
64. www.ibase.ru
PSQL: Исключения с параметрами
Синтаксис
• Исключения со слотами (@1, @2, ...). Нумерация начинается с 1.
Максимальный номер слота равен 9.
CREATE EXCEPTION EX_WITH_PARAMS 'Error @1 : @2';
• При возбуждении исключения с параметрами используется
предложение USING
EXEPTION EX_WITH_PARAMS USING (1, 'You can not do it');
• Замечание: Если в тексте сообщения, встретится номер слота больше 9, то
второй и последующий символ будут восприняты как литералы. Например, @10
будет воспринято как @1, после которого следует литерал 0.
65. www.ibase.ru
PSQL: SQLSTATE в обработчике
WHEN
Пример
EXECUTE BLOCK
AS
DECLARE VARIABLE I INT;
BEGIN
BEGIN
I = 1 / 0;
WHEN SQLSTATE '22003' DO
EXCEPTION E_CUSTOM_EXCEPTION
'Numeric value out of range.';
WHEN SQLSTATE '22012' DO
EXCEPTION E_CUSTOM_EXCEPTION 'Division by zero.';
END
END
66. www.ibase.ru
PSQL: CONTINUE в циклах
Синтаксис
[label:]
{FOR <select_stmt> | WHILE (<condition>)} DO
BEGIN
...
CONTINUE [label];
...
END
Пример
FOR
SELECT A, D FROM ATABLE INTO :achar, :ddate
DO BEGIN
IF (ddate < current_data - 30) THEN
CONTINUE;
ELSE
/* do stuff */
...
END
67. www.ibase.ru
PSQL: Ссылки на курсоры
Пример
FOR SELECT A, B, C FROM ...
AS CURSOR C1 -- предложение INTO необязательно
DO
BEGIN
...
INSERT INTO T(A, B, C)
VALUES (C1.A, C1.B, C1.C, …); -- ссылка на курсор
END
68. www.ibase.ru
Замечания
• Для разрешения конфликтов используется символ «:»
• В операторе FOR SELECT без предложения AS
CURSOR необходимо использовать предложение
INTO. Если указано предложение AS CURSOR,
предложение INTO не требуется, но разрешено.
• В операторе FETCH предложение INTO
необязательное.
• Чтение из переменной курсора возвращает текущие
значения полей. Поэтому UPDATE с WHERE
CURRENT OF обновит значения полей в курсоре, а
DELETE установит их в NULL.
PSQL: Ссылки на курсоры
69. www.ibase.ru
PSQL: Ссылки на курсоры
Разрешение конфликтов
EXECUTE BLOCK
RETURNS (o1 CHAR(31), o2 CHAR(31))
AS
BEGIN
FOR SELECT rdb$relation_name
FROM rdb$relations
WHERE rdb$relation_name = 'RDB$RELATIONS' AS CURSOR c
DO BEGIN
FOR SELECT
-- с префиксом разрешается как курсор
:c.rdb$relation_name x1,
-- без префикса как псевдоним таблицы rdb$relations
c.rdb$relation_name x2
FROM rdb$relations c
WHERE rdb$relation_name = 'RDB$DATABASE' AS CURSOR d
DO BEGIN
...
END
END
END
70. www.ibase.ru
PSQL: Ссылки на курсоры
Обратная совместимость
EXECUTE BLOCK AS
DECLARE VARIABLE BYYEAR SMALLINT;
DECLARE VARIABLE PO_NUMBER PONUMBER;
BEGIN
FOR SELECT EXTRACT(YEAR FROM sales.order_date), -- нужен алиас
PO_NUMBER
FROM sales
INTO :BYYEAR, :PO_NUMBER
AS CURSOR c
DO
BEGIN
IF (BYYEAR > 2000) THEN
UPDATE sales SET order_date = '31.12.2000'
WHERE CURRENT OF c;
END
END
Вернёт ошибку: «no column name specified for column number 1 in derived table C».
71. www.ibase.ru
PSQL: Двунаправленные курсоры
Синтаксис
DECLARE [VARIABLE] cursor_name [SCROLL | NO SCROLL]
CURSOR FOR (<select_statement>);
FETCH cursor_name
[INTO [:]var_name [, [:]var_name ...]];
FETCH {NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n}
FROM cursor_name
[INTO [:]var_name [,[:]var_name ...]];
72. www.ibase.ru
PSQL: Двунаправленные курсоры
Пример
EXECUTE BLOCK RETURNS (N INT) AS
DECLARE C SCROLL CURSOR FOR (
SELECT ROW_NUMBER() OVER(ORDER BY RDB$RELATION_NAME) AS N
FROM RDB$RELATIONS ORDER BY RDB$RELATION_NAME);
BEGIN
-- после открытия курсора мы на 1 записи (N=1)
OPEN C; N = C.N; SUSPEND;
-- перемещаемся на 1 запись вперёд (N=2)
FETCH NEXT FROM C; N = C.N; SUSPEND;
-- перемещаемся на пятую запись (N=5)
FETCH ABSOLUTE 5 FROM C; N = C.N; SUSPEND;
-- перемещаемся на 1 запись назад (N=4)
FETCH PRIOR FROM C; N = C.N; SUSPEND;
-- перемещаемся на последнюю запись (N=61)
FETCH LAST FROM C; N = C.N; SUSPEND;
-- перемещаемся на 5 записей назад (N=56)
FETCH RELATIVE -5 FROM C; N = C.N; SUSPEND;
-- перемещаемся на первую запись (N=1)
FETCH FIRST FROM C; N = C.N; SUSPEND;
CLOSE C;
END
74. www.ibase.ru
DDL: Управление допустимостью NULL
Синтаксис
• Для столбцов таблиц
ALTER TABLE tablename
ALTER [COLUMN] colname {SET | DROP} NOT NULL
• Для доменов
ALTER DOMAIN domainname {SET | DROP} NOT NULL
Замечание: Теперь при добавлении NOT NULL столбца
предложение DEFAULT обязательное
75. www.ibase.ru
DDL: Управление допустимостью NULL
Примеры
ALTER TABLE OBJECTS
ADD QUANTITY INT DEFAULT 1 NOT NULL;
ALTER TABLE STOCK
ALTER COLUMN MODEL SET NOT NULL,
ALTER COLUMN ITEMID DROP NOT NULL;
ALTER DOMAIN D_FIRSTNAME SET NOT NULL;
76. www.ibase.ru
DDL: IDENTITY столбцы
Синтаксис
<column definition> ::=
<name> <type> GENERATED BY DEFAULT AS IDENTITY
[STARTS WITH number] <constraints>
<alter column definition> ::=
<name> RESTART [WITH number]
При создании автоинкрементного столбца создаётся системная
последовательность (RDB$GENERATORS.RDB$SYSTEM_FLAG = 6). А в
свойствах поля (RDB$RELATION_FIELDS. RDB$GENERATOR_NAME) имя этого
системного генератора.
77. www.ibase.ru
DDL: IDENTITY столбцы
Правила
• Тип столбца INTEGER, BIGINT или NUMERIC(p, 0)
• Неявно накладывается ограничение NOT NULL
• Уникальность не гарантируется
• Не может содержать предложение DEFAULT
• Не может быть COMPUTED BY
• Не может быть изменён на не IDENTITY
78. www.ibase.ru
DDL: IDENTITY столбцы
Примеры
CREATE TABLE objects (
id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(15)
);
INSERT INTO objects (name) VALUES ('Table');
INSERT INTO objects (name) VALUES ('Book');
INSERT INTO objects (id, name) VALUES (10, 'Computer');
SELECT * FROM objects;
ID NAME
---- -------
1 Table
2 Book
10 Computer
79. www.ibase.ru
DDL: Последовательности
Синтаксис
CREATE {SEQUENCE | GENERATOR} seq_name
[START WITH value] [INCREMENT [BY] increment];
ALTER {SEQUENCE | GENERATOR} seq_name
[RESTART [WITH new_val]] [INCREMENT [BY] increment];
CREATE OR ALTER {SEQUENCE | GENERATOR} seq_name
[{START WITH value | RESTART}] [INCREMENT [BY] increment];
RECREATE {SEQUENCE | GENERATOR} seq_name
[START WITH value] [INCREMENT [BY] increment];
Начальное значение генератора хранится в поле RDB$INITIAL_VALUE таблицы
RDB$GENERATORS, а значение приращения в поле RDB$GENERATOR_INCREMENT.
81. www.ibase.ru
DDL: DDL триггеры
Синтаксис
<ddl-trigger> ::=
{CREATE | RECREATE | CREATE OR ALTER} TRIGGER name
[ACTIVE | INACTIVE] {BEFORE | AFTER} <ddl event>
[POSITION n]
<ddl event> ::= ANY DDL STATEMENT |
<ddl event item> [{OR <ddl event item>} ...]
<ddl event item> ::= {CREATE | ALTER | DROP}
{TABLE | PROCEDURE | FUNCTION | TRIGGER | EXCEPTION |
VIEW | DOMAIN | SEQUENCE | INDEX | ROLE | FILTER |
USER | COLLATION | PACKAGE | PACKAGE BODY |
CHARACTER SET | MAPPING}
82. www.ibase.ru
DDL: DDL триггеры
Новые контекстные переменные (RDB$GET_CONTEXT)
• Пространство имён DDL_TRIGGER
• Существуют только внутри DDL триггеров и процедур/функций
вызываемых из этих триггеров
• Только для чтения
• Предопределённые переменные:
• EVENT_TYPE - тип события (CREATE, ALTER, DROP)
• OBJECT_TYPE - тип объекта (TABLE, VIEW и д.р.)
• DDL_EVENT - имя события = EVENT_TYPE || ' ' || OBJECT_TYPE
• OBJECT_NAME - имя объекта метаданных
• OLD_OBJECT_NAME - имя объекта метаданных до переименования
• NEW_OBJECT_NAME - имя объекта метаданных после переименования
• SQL_TEXT - текст SQL запроса
83. www.ibase.ru
DDL: DDL триггеры
Пример 1
CREATE EXCEPTION EX_BAD_SP_NAME
'Name of procedures must start with ''@1'' : ''@2''';
CREATE TRIGGER TRG_SP_CREATE BEFORE CREATE PROCEDURE
AS
DECLARE SP_NAME VARCHAR(255);
BEGIN
SP_NAME = RDB$GET_CONTEXT('DDL_TRIGGER', 'OBJECT_NAME');
IF (SP_NAME NOT STARTING 'SP_') THEN
EXCEPTION EX_BAD_SP_NAME USING ('SP_', SP_NAME);
END
84. www.ibase.ru
DDL: DDL триггеры
Пример 2
CREATE SEQUENCE ddl_seq;
CREATE TABLE ddl_log (
id BIGINT NOT NULL PRIMARY KEY,
moment TIMESTAMP NOT NULL,
user_name VARCHAR(31) NOT NULL,
event_type VARCHAR(25) NOT NULL,
object_type VARCHAR(25) NOT NULL,
ddl_event VARCHAR(25) NOT NULL,
object_name VARCHAR(31) NOT NULL,
old_object_name VARCHAR(31),
new_object_name VARCHAR(31),
sql_text BLOB sub_type text NOT NULL,
ok CHAR(1) NOT NULL
);
85. www.ibase.ru
DDL: DDL триггеры
CREATE TRIGGER trig_ddl_log_before BEFORE ANY DDL STATEMENT AS
DECLARE id TYPE OF COLUMN ddl_log.id;
BEGIN
IN AUTONOMOUS TRANSACTION DO
BEGIN
INSERT INTO ddl_log (id, moment, user_name, event_type, object_type, ddl_event,
object_name, old_object_name, new_object_name, sql_text, ok)
VALUES (NEXT VALUE FOR ddl_seq,
current_timestamp, current_user,
rdb$get_context('DDL_TRIGGER', 'EVENT_TYPE'),
rdb$get_context('DDL_TRIGGER', 'OBJECT_TYPE'),
rdb$get_context('DDL_TRIGGER', 'DDL_EVENT'),
rdb$get_context('DDL_TRIGGER', 'OBJECT_NAME'),
rdb$get_context('DDL_TRIGGER', 'OLD_OBJECT_NAME'),
rdb$get_context('DDL_TRIGGER', 'NEW_OBJECT_NAME'),
rdb$get_context('DDL_TRIGGER', 'SQL_TEXT'),
'N')
RETURNING id INTO id;
rdb$set_context('USER_SESSION', 'trig_ddl_log_id', id);
END
END!
86. www.ibase.ru
DDL: DDL триггеры
CREATE TRIGGER trig_ddl_log_after AFTER ANY DDL STATEMENT
AS
BEGIN
-- Здесь нам требуется автономная транзакция,
-- потому что в оригинальной транзакции
-- мы не увидим запись, вставленную в
-- BEFORE триггере в автономной транзакции,
-- если пользовательская транзакции не запущена
-- с режимом изоляции READ COMMITTED.
IN AUTONOMOUS TRANSACTION DO
UPDATE ddl_log SET ok = 'Y'
WHERE id = rdb$get_context('USER_SESSION', 'trig_ddl_log_id');
END!
COMMIT!
SET TERM ;!
-- Удаляем запись о создании trig_ddl_log_after.
DELETE FROM ddl_log;
COMMIT;
87. www.ibase.ru
DDL: DDL триггеры
RECREATE TABLE t1 (n1 INT, n2 INT);
-- Эта команда будет зарегистрирована единожды
-- (т.к. T1 не существует, RECREATE вызовет событие CREATE) с OK = Y.
CREATE TABLE t1 (n1 INT, n2 INT);
-- Оператор не выполнится, т.к. T1 уже существует,
-- таким образом OK будет иметь значение N.
DROP TABLE t2;
-- T2 не существует. Это действие не будет зарегистрировано.
RECREATE TABLE t1 (n INT);
-- Это действие будет зарегистрировано дважды
-- (т.к. T1 существует, действие RECREATE рассматривается
-- как DROP и CREATE) с полем OK = Y.
CREATE DOMAIN dom1 AS INT;
ALTER DOMAIN dom1 TYPE BIGINT;
ALTER DOMAIN dom1 TO dom2;
COMMIT;
88. www.ibase.ru
DDL: DDL триггеры
ID DDL_EVENT NAME OLD_NAME NEW_NAME SQL_TEXT OK
2 CREATE TABLE T1 <null> <null> RECREATE TABLE t1
(n1 INT, n2 INT)
Y
3 CREATE TABLE T1 <null> <null> CREATE TABLE t1
(n1 INT, n2 INT)
N
4 DROP TABLE T1 <null> <null> RECREATE TABLE t1
(n1 INT)
Y
5 CREATE TABLE T1 <null> <null> RECREATE TABLE t1
(n1 INT)
Y
6 CREATE DOMAIN DOM1 <null> <null> CREATE DOMAIN dom1
AS INT
Y
7 ALTER DOMAIN DOM1 <null> <null> ALTER DOMAIN dom1
TYPE BIGINT
Y
8 ALTER DOMAIN DOM1 DOM1 DOM2 ALTER DOMAIN dom1
TO dom2
Y
Результаты журналирования DDL
89. www.ibase.ru
DDL: CREATE DATABASE
Пример
CREATE USER wizard PASSWORD 'player‘
GRANT ADMIN ROLE;
CREATE DATABASE 'inet://baseserver:3050/test'
USER wizard PASSWORD 'player' ROLE RDB$ADMIN
DEFAULT CHARACTER SET UTF8;
Синтаксис строки подключения
<filespec> ::= [<server_spec>]{filepath | db_alias}
<server_spec> ::=
host[port | service]:
| host[@port | service]
| <protocol>://[host[:port | service]/]
<protocol> = inet | wnet | xnet
90. www.ibase.ru
DDL: ALTER DATABASE
Синтаксис
ALTER {DATABASE | SCHEMA}
{<add_sec_clause> [<add_sec_clausee> ...]}
| {ADD DIFFERENCE FILE 'diff_file' | DROP DIFFERENCE FILE}
| {{BEGIN | END} BACKUP}
| {SET DEFAULT CHARACTER SET charset}
| {SET LINGER TO seconds | DROP LINGER}
| {ENCRYPT WITH plugin_name | DECRYPT};
91. www.ibase.ru
DDL: ALTER DATABASE
Примеры
ALTER DATABASE SET DEFAULT CHARACTER SET WIN1251;
ALTER DATABASE SET LINGER 30;
ALTER DATABASE DROP LINGER;
ALTER DATABASE ENCRYPT WITH DbCrypt;
ALTER DATABASE DECRYPT;
95. www.ibase.ru
Security: Управление пользователями
Синтаксис (продолжение)
ALTER {USER username | CURRENT USER}
[SET] <option> [, <option> …]
[USING PLUGIN 'pluginname']
[{GRANT | REVOKE} ADMIN ROLE];
CREATE OR ALTER USER username
[SET] <option> [, <option> …]
[USING PLUGIN 'pluginname']
[{GRANT | REVOKE} ADMIN ROLE];
DROP USER username
[USING PLUGIN 'pluginname'];
96. www.ibase.ru
Security: Управление пользователями
Особенности:
• Без указания USING PLUGIN первый плагин из списка
в параметре UserManager
• Имя тега не может быть больше 31 символа
• Значение тега не может превышать 255 символов
• При создании нового пользователя пароль обязателен
• В Legacy_UserManager пароль урезается до 8
символов
• Имена пользователей в двойных кавычках
чувствительны к регистру
97. www.ibase.ru
Security: Управление пользователями
Примеры:
CREATE USER bigshot PASSWORD 'buckshot';
CREATE USER godzilla PASSWORD 'robot'
USING PLUGIN Legacy_UserManager;
CREATE USER john PASSWORD 'fYe_3Ksw'
FIRSTNAME 'John' LASTNAME 'Doe'
TAGS (BIRTHYEAR = '1970', CITY = 'New York');
CREATE USER superuser PASSWORD 'kMn8Kjh'
INACTIVE GRANT ADMIN ROLE;
98. www.ibase.ru
Security: Управление пользователями
Примеры (продолжение):
ALTER USER bigshot GRANT ADMIN ROLE;
ALTER USER godzilla PASSWORD 'robot12'
USING PLUGIN Legacy_UserManager;
ALTER CURRENT USER
TAGS (BIRTHYEAR = '1973', DROP CITY);
ALTER USER superuser SET ACTIVE;
DROP USER godzilla USING PLUGIN Legacy_UserManager;
101. www.ibase.ru
Security: Привилегия EXECUTE
Синтаксис
GRANT EXECUTE ON <object_type> object_name
TO <grantee> [WITH GRANT OPTION]
[{GRANTED BY | AS} [USER] grantor];
REVOKE [GRANT OPTION FOR]
EXECUTE ON <object_type> object_name
FROM <grantee> [{GRANTED BY | AS} [USER] grantor];
<object_type> ::= PROCEDURE | FUNCTION | PACKAGE
Замечание: Невозможно выдать или отобрать привилегию EXECUTE у отдельных
процедур и функций пакета. Привилегия EXECUTE может быть выдана только на
весь пакет.
102. www.ibase.ru
Security: Привилегия EXECUTE
Примеры
-- Привилегия EXECUTE для хранимой процедуры
GRANT EXECUTE ON PROCEDURE ADD_EMP_PROJ
TO ROLE MANAGER;
-- Привилегия EXECUTE для хранимой функции
GRANT EXECUTE ON FUNCTION GET_BEGIN_DATE TO ALEX;
-- Привилегия EXECUTE для пакета
GRANT EXECUTE ON PACKAGE APP_VAR TO PUBLIC;
-- Привилегия EXECUTE для функции выданная пакету
GRANT EXECUTE ON FUNCTION GET_BEGIN_DATE
TO PACKAGE APP_VAR;
103. www.ibase.ru
Security: Привилегия EXECUTE
Примеры (продолжение)
-- отзыв привилегии EXECUTE на процедуру
REVOKE EXECUTE ON PROCEDURE ADD_EMP_PROJ
FROM USER IVAN;
-- отзыв привилегии EXECUTE на функцию
-- и возможности передавать эту привилегию
REVOKE GRANT OPTION FOR
EXECUTE ON FUNCTION GET_BEGIN_DATE
FROM ALEX;
-- отзыв привилегии EXECUTE для пакета
REVOKE EXECUTE ON PACKAGE DATE_UTILS
FROM ROLE MANAGER;
104. www.ibase.ru
Security: Привилегия USAGE
Синтаксис
GRANT USAGE ON <object_type> object_name
TO <grantee> [WITH GRANT OPTION]
[{GRANTED BY | AS} [USER] grantor];
REVOKE [GRANT OPTION FOR]
USAGE ON <object_type> object_name
FROM <grantee> [{GRANTED BY | AS} [USER] grantor];
<object_type> ::= EXCEPTION | GENERATOR | SEQUENCE
105. www.ibase.ru
Security: Привилегия USAGE
Примеры
-- Привилегия USAGE на последовательность выданная роли
GRANT USAGE ON SEQUENCE GEN_AGE TO ROLE MANAGER;
-- Привилегия USAGE на последовательность выданная
триггеру
GRANT USAGE ON SEQUENCE GEN_AGE TO TRIGGER TR_AGE_BI;
-- Привилегия USAGE на исключение выданная пакету
GRANT USAGE ON EXCEPTION E_ACCESS_DENIED
TO PACKAGE PKG_BILL;
106. www.ibase.ru
Security: Привилегия USAGE
Примеры (продолжение)
-- Отзыв привилегии USAGE на последовательность у роли
REVOKE USAGE ON SEQUENCE GEN_AGE FROM ROLE MANAGER;
-- Отзыв привилегии USAGE на последовательность у триггера
REVOKE USAGE ON SEQUENCE GEN_AGE FROM TRIGGER TR_AGE_BI;
-- Отзыв привилегии USAGE на исключение у пакета
REVOKE USAGE ON EXCEPTION E_ACCESS_DENIED
FROM PACKAGE PKG_BILL;
107. www.ibase.ru
Security: DDL привилегии
Синтаксис
GRANT <ddl_privileges> <object_type> TO <grantee>
[WITH GRANT OPTION] [{GRANTED BY | AS} [USER] grantor];
REVOKE [GRANT OPTION FOR] <ddl_privileges> <object_type>
FROM <grantee> [{GRANTED BY | AS} [USER] grantor];
<ddl_privileges> ::=
ALL [PRIVILEGES] | <ddl_privilege> [, <ddl_privilege> …]
<ddl_privilege> ::= {CREATE | ALTER ANY | DROP ANY}
<object_type> ::= TABLE | VIEW | PROCEDURE | FUNCTION | PACKAGE |
GENERATOR | SEQUENCE | EXCEPTION | DOMAIN | FILTER | ROLE |
CHARACTER SET | COLLATION
108. www.ibase.ru
Security: DDL привилегии
Синтаксис (специальная форма для DATABASE)
GRANT <ddl_privileges> DATABASE TO <grantee>
[WITH GRANT OPTION] [{GRANTED BY | AS} [USER] grantor];
REVOKE [GRANT OPTION FOR] <ddl_privileges> <object_type>
FROM <grantee> [{GRANTED BY | AS} [USER] grantor];
<ddl_privileges> ::=
ALL [PRIVILEGES] | <ddl_privilege> [, <ddl_privilege> …]
<ddl_privilege> ::= {CREATE | ALTER | DROP}
Замечания:
• Привилегия CREATE DATABASE хранится в SecurityDatabase. Список
пользователей которые могут создать новую базу данных можно посмотреть
в таблице SEC$DB_CREATORS.
• ALL PRIVILEGES не включает привилегию CREATE DATABASE
109. www.ibase.ru
Security: DDL привилегии
Примеры
-- Разрешение пользователю Joe создавать таблицы
GRANT CREATE TABLE TO Joe;
-- Разрешение пользователю Joe изменять любые процедуры
GRANT ALTER ANY PROCEDURE TO Joe;
-- Разрешение пользователю Joe создавать, изменять и
удалять любые представления
GRANT ALL PRIVILEGES VIEW TO Joe;
-- Разрешение пользователю Joe изменять и удалять любые
генераторы (последовательности)
GRANT ALTER ANY, DROP ANY SEQUENCE TO Joe;
-- Разрешение пользователю SuperUser создавать базы данных
GRANT CREATE DATABASE TO SuperUser;
110. www.ibase.ru
Security: DDL привилегии
Примеры
-- Отзыв у Joe привилегии на создание таблиц
REVOKE CREATE TABLE FROM Joe;
-- Отзыв у Joe привилегии на изменение любых процедур
REVOKE ALTER ANY PROCEDURE FROM Joe;
-- Отзыв у Joe привилегий на создание, изменение и
удаление любых представлений
REVOKE ALL PRIVILEGES VIEW FROM Joe;
-- Отзыв у Joe привилегий на изменение и удаление любых
генераторов (последовательностей)
REVOKE ALTER ANY, DROP ANY SEQUENCE FROM Joe;
-- Отзыв у SuperUser привилегий на создание и удаление
базы данных
REVOKE CREATE, DROP DATABASE FROM SuperUser;
112. www.ibase.ru
Security: Шифрование
Синтаксис
ALTER DATABASE ENCRYPT WITH plugin_name
ALTER DATABASE DECRYPT
• Процесс шифрования может быть проконтролирован с помощью поля
MON$CRYPT_PAGE в псевдо-таблице MON$DATABASE или смотреть
страницу заголовка базы данных с помощью gstat -e.
Notes de l'éditeur
В стандарте привилегия USAGE может быть применена также для DOMAIN, CHARACTER SET, COLLATION