mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-23 05:53:06 +01:00
165 lines
6.7 KiB
Python
165 lines
6.7 KiB
Python
#coding:utf-8
|
||
|
||
"""
|
||
ID: exception.handling-name-and-message
|
||
FBTEST: functional.exception.handling_name_and_message
|
||
TITLE: Context variables EXCEPTION and ERROR_MESSAGE for ability to log exception info (including call stack!) on server side
|
||
DESCRIPTION:
|
||
Testing new built-in context variables for exception handling (appearance: 06-sep-2016 21:12, 4.0 only):
|
||
* 'exception' -- returns name of the active user-defined exception;
|
||
* 'error_message' -- returns interpreted text for the active exception.
|
||
See: https://github.com/FirebirdSQL/firebird/commit/ebd0d3c8133c62b5359100de5f1eec541e43da3b
|
||
Explanation: doc\\sql.extensions\\README.context_variables
|
||
|
||
GOOD NEWS:
|
||
call stack now can be logged on database without calling of mon$ tables,
|
||
simple by parsing 'error_message' content (part that follows by last newline character).
|
||
|
||
WARNING-1.
|
||
This test intentionally creates exception with non-ascii name and parametrized non-ascii message text.
|
||
Length of exception *NAME* can be up to 63 non-ascii characters, but upper bound for length of exception
|
||
*MESSAGE* is limited to 1023 *bytes* (NOT chars!) ==> it's max length for two-byte encoding (win1251 etc)
|
||
will be usually much less, about 500...600 characters. This limit can not be overpassed nowadays.
|
||
For database with default cset = utf8 table rdb$exception will have following DDL:
|
||
RDB$EXCEPTION_NAME (RDB$EXCEPTION_NAME) CHAR(63) Nullable
|
||
RDB$MESSAGE (RDB$MESSAGE) VARCHAR(1023) CHARACTER SET NONE Nullable
|
||
Checked on 4.0.0.366
|
||
|
||
WARNING-2.
|
||
It seems that handling of message with length = 1023 bytes (i.e. exactly upper limit) works wrong.
|
||
Waiting for reply from dimitr, letter 09-sep-2016 18:27.
|
||
NOTES:
|
||
[07.12.2016]
|
||
'exception' and 'error_message' context variables were replaced with calls RDB$ERROR(EXCEPTION) and RDB$ERROR(MESSAGE)
|
||
(letter from dimitr, 06.12.2016 21:44; seems that this was done in 4.0.0.461, between 02-dec-2016 and 04-dec-2016)
|
||
"""
|
||
|
||
import pytest
|
||
from firebird.qa import *
|
||
|
||
db = db_factory(charset='UTF8')
|
||
|
||
test_script = """
|
||
recreate exception "Что-то неправильно со складом" 'Остаток стал отрицательным: @1';
|
||
|
||
/*
|
||
|
||
This will be added after trouble with length = 1023 characters will be solved (TODO after):
|
||
|
||
recreate exception "ЙцуКенгШщзХъЭждЛорПавЫфЯчсмиТьбЮЪхЗщШШГнЕкУцЙФывААпрОолДжЭЭюБьТ"
|
||
'*Лев Николаевич Толстой * *Анна Каренина * /Мне отмщение, и аз воздам/ *ЧАСТЬ ПЕРВАЯ* *I *
|
||
Все счастливые семьи похожи друг на друга, каждая несчастливая
|
||
семья несчастлива по-своему.
|
||
Все смешалось в доме Облонских. Жена узнала, что муж был в связи
|
||
с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что
|
||
не может жить с ним в одном доме. Положение это продолжалось уже
|
||
третий день и мучительно чувствовалось и самими супругами, и всеми
|
||
членами семьи, и домочадцами. Все члены семьи и домочадцы
|
||
чувствовали, что нет смысла в их сожительстве и что на каждом
|
||
п1
|
||
';
|
||
*/
|
||
|
||
recreate table log_user_trouble(
|
||
e_declared_name varchar(63) character set utf8,
|
||
e_detailed_text varchar(2000) character set utf8
|
||
);
|
||
|
||
set term ^;
|
||
create or alter procedure sp_log_user_trouble(
|
||
e_declared_name varchar(63) character set utf8,
|
||
e_detailed_text varchar(2000) character set utf8
|
||
) as
|
||
begin
|
||
in autonomous transaction do
|
||
insert into log_user_trouble(e_declared_name, e_detailed_text) values(:e_declared_name, :e_detailed_text);
|
||
end
|
||
^
|
||
set term ;^
|
||
commit;
|
||
|
||
set list on;
|
||
|
||
/*
|
||
show table rdb$exceptions;
|
||
select
|
||
rdb$exception_name,
|
||
char_length(trim(rdb$exception_name)) exc_name_char_len,
|
||
octet_length(trim(rdb$exception_name)) exc_name_octt_len,
|
||
char_length(rdb$message) detailed_text_char_len,
|
||
octet_length(rdb$message) detailed_text_octt_len
|
||
from rdb$exceptions;
|
||
--*/
|
||
|
||
-- RDB$ERROR(GDSCODE|SQLCODE|SQLSTATE|EXCEPTION|MESSAGE)
|
||
set term ^;
|
||
create or alter procedure sp_check_amount(a_new_qty int) as
|
||
begin
|
||
begin
|
||
if (a_new_qty < 0) then
|
||
exception "Что-то неправильно со складом" using( a_new_qty );
|
||
--exception "ЙцуКенгШщзХъЭждЛорПавЫфЯчсмиТьбЮЪхЗщШШГнЕкУцЙФывААпрОолДжЭЭюБьТ"; -- malformed string
|
||
|
||
when any do
|
||
if ( RDB$ERROR(EXCEPTION) is not null) then
|
||
-- before 4.0.0.462 (04.12.2016): execute procedure sp_log_user_trouble(exception, error_message);
|
||
execute procedure sp_log_user_trouble( RDB$ERROR(EXCEPTION), RDB$ERROR(MESSAGE) );
|
||
else
|
||
exception;
|
||
|
||
end
|
||
|
||
end
|
||
^
|
||
|
||
create or alter procedure sp_run_write_off(a_new_qty int) as
|
||
declare old_qty int = 1;
|
||
declare new_qty int;
|
||
begin
|
||
new_qty = old_qty - a_new_qty;
|
||
execute procedure sp_check_amount( new_qty );
|
||
end
|
||
^
|
||
|
||
create or alter procedure "главная точка входа" as
|
||
begin
|
||
execute procedure sp_run_write_off(9);
|
||
end
|
||
^
|
||
set term ;^
|
||
commit;
|
||
|
||
set term ^;
|
||
execute block as
|
||
begin
|
||
execute procedure "главная точка входа";
|
||
end
|
||
^
|
||
set term ;^
|
||
commit;
|
||
|
||
set count on;
|
||
select * from log_user_trouble;
|
||
"""
|
||
|
||
act = isql_act('db', test_script, substitutions=[('line:\\s[0-9]+,', 'line: x'),
|
||
('col:\\s[0-9]+', 'col: y')])
|
||
|
||
expected_stdout = """
|
||
E_DECLARED_NAME Что-то неправильно со складом
|
||
E_DETAILED_TEXT exception 1
|
||
Что-то неправильно со складом
|
||
Остаток стал отрицательным: -8
|
||
At procedure 'SP_CHECK_AMOUNT' line: x col: y
|
||
At procedure 'SP_RUN_WRITE_OFF' line: x col: y
|
||
At procedure 'главная точка входа' line: x col: y
|
||
At block line: x col: y
|
||
Records affected: 1
|
||
"""
|
||
|
||
@pytest.mark.version('>=4.0')
|
||
def test_1(act: Action):
|
||
act.expected_stdout = expected_stdout
|
||
act.execute()
|
||
assert act.clean_stdout == act.clean_expected_stdout
|