Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Помогите с рекурсивным вызовом процедуры FB2.5 / 23 сообщений из 23, страница 1 из 1
01.04.2014, 15:01:54
    #38601955
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Всем доброго времени суток!

Нарисовал следующую процедуру которая должна подсчитать количество слов в BLOB разделённых напр. запятой или несколькими другими символами.
но при попытке вызвать эту процедуру рекурсивно вываливает Too many .....
Попробовал использовать WITH RECURSIVE но никак не пойму как его в этой ситуации прикрутить :(

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
create or alter procedure SYSTEM_GETWORDCOUNT(
 I_TEXT BLOB SUB_TYPE 0 SEGMENT SIZE 80,
 I_COUNT integer default 0,
 I_TRENNER varchar(50) default Null
)
returns (
O_COUNT integer
)
as
declare variable V_POS integer;
declare variable V_LEN integer;
begin
   O_COUNT = 0;
   V_LEN = 0;

   if (I_TRENNER is null) then
   I_TRENNER = ',';

   V_POS = POSITION(:I_TRENNER IN :I_TEXT)+1;
   V_LEN = CHAR_LENGTH(I_TEXT)-V_POS ;

   if (V_POS > 0) then
   begin

     /*  пробовал и так */
     /*  SELECT O_COUNT from SYSTEM_GETWORDCOUNT(SUBSTRING(:I_TEXT FROM :V_POS FOR :V_LEN),:I_COUNT,:I_TRENNER) into :O_COUNT;  */

     /*  и так */ 
     /*   execute procedure SYSTEM_GETWORDCOUNT SUBSTRING(I_TEXT FROM V_POS FOR V_LEN),I_COUNT,I_TRENNER RETURNING_VALUES O_COUNT;*/

     O_COUNT = O_COUNT + I_COUNT;
     suspend;
   end
   else
   begin
      O_COUNT = I_COUNT +1;
      suspend;
   end

end^



помогите. Спасибо.
...
Рейтинг: 0 / 0
01.04.2014, 15:25:21
    #38601994
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Код: sql
\r\nSET TERM ^ ;\r\n\r\ncreate or alter procedure LIST_TO_ROWS (\r\n    A_LST blob sub_type 1 segment size 80,\r\n    A_DEL char(1) = \',\')\r\nreturns (\r\n    LINE integer,\r\n    EOF integer,\r\n    ITEM varchar(8192))\r\nAS\r\n  declare pos_ int;\r\n  declare offset int = 1;\r\n  declare beg int;\r\n  declare buf varchar(30100);\r\nbegin\r\n  -- Splits blob to lines by single char delimiter.\r\n  -- adapted from here:\r\n  -- /topic/607154&pg=2#6686267\r\n  if (a_lst is null) then exit;\r\n  line=0;\r\n\r\n  while (0=0) do begin\r\n    buf = substring(a_lst from offset for 30100);\r\n    pos_ = 1; beg = 1;\r\n    while (pos_ <= char_length(buf) and pos_ <= 30000) do begin\r\n      if (substring(buf from pos_ for 1) = :a_del) then begin\r\n        if (pos_ > beg) then\r\n          item = substring(buf from beg for pos_ - beg);\r\n        else\r\n          item = \'\'; --null;\r\n        suspend;\r\n        line=line+1;\r\n        beg = pos_ + 1;\r\n      end\r\n      pos_ = pos_ + 1;\r\n    end\r\n    if (offset + pos_ - 2 = char_length(a_lst)) then leave;\r\n    offset = offset + beg - 1;\r\n    if (offset > char_length(a_lst)) then leave;\r\n  end\r\n\r\n  if (pos_ > beg) then begin\r\n    item = substring(buf from beg for pos_ - beg);\r\n    eof=-1;\r\n  end\r\n  else begin\r\n    item = \'\';\r\n    eof=-1;\r\n  end\r\n  suspend;\r\nend^\r\n\r\nSET TERM ; ^\r\n
\r\n

PS. Спасибо адресуйте WildSery (один из двух команданте этого раздела форума)
...
Рейтинг: 0 / 0
01.04.2014, 17:44:45
    #38602193
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Таблоид,
Спасибо и Вам и WildSery
...
Рейтинг: 0 / 0
11.04.2014, 13:30:16
    #38612271
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Таблоид
Код: sql
\r\nSET TERM ^ ;\r\n\r\ncreate or alter procedure LIST_TO_ROWS (\r\n    A_LST blob sub_type 1 segment size 80,\r\n    A_DEL char(1) = \',\')\r\nreturns (\r\n    LINE integer,\r\n    EOF integer,\r\n    ITEM varchar(8192))\r\nAS\r\n  declare pos_ int;\r\n  declare offset int = 1;\r\n  declare beg int;\r\n  declare buf varchar(30100);\r\nbegin\r\n  -- Splits blob to lines by single char delimiter.\r\n  -- adapted from here:\r\n  -- /topic/607154&pg=2#6686267\r\n  if (a_lst is null) then exit;\r\n  line=0;\r\n\r\n  while (0=0) do begin\r\n    buf = substring(a_lst from offset for 30100);\r\n    pos_ = 1; beg = 1;\r\n    while (pos_ <= char_length(buf) and pos_ <= 30000) do begin\r\n      if (substring(buf from pos_ for 1) = :a_del) then begin\r\n        if (pos_ > beg) then\r\n          item = substring(buf from beg for pos_ - beg);\r\n        else\r\n          item = \'\'; --null;\r\n        suspend;\r\n        line=line+1;\r\n        beg = pos_ + 1;\r\n      end\r\n      pos_ = pos_ + 1;\r\n    end\r\n    if (offset + pos_ - 2 = char_length(a_lst)) then leave;\r\n    offset = offset + beg - 1;\r\n    if (offset > char_length(a_lst)) then leave;\r\n  end\r\n\r\n  if (pos_ > beg) then begin\r\n    item = substring(buf from beg for pos_ - beg);\r\n    eof=-1;\r\n  end\r\n  else begin\r\n    item = \'\';\r\n    eof=-1;\r\n  end\r\n  suspend;\r\nend^\r\n\r\nSET TERM ; ^\r\n
\r\n

PS. Спасибо адресуйте WildSery (один из двух команданте этого раздела форума)

У меня тут один немецкий коллега посмотрел в эту функцию и сказал что она может вызвать нестабильную работу FireBird 2.5.
Так что все полностью зависнет. Дескать а что будет если произойдёт выход за границу буфера итп. Я попытался ему объяснить что тут контроль выхода за границу буфера присутствует но это не спасло от письма начальству с уведомлением что код нестабильный и может вызвать зависание сервера и он не несёт ответственности при его использовании. Может я слепой и чего то не вижу опасного в этой функции, просветите.
Спасибо
...
Рейтинг: 0 / 0
11.04.2014, 13:36:24
    #38612283
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Mikhail Tchervonenkoэто не спасло от письма начальству с уведомлением что код
нестабильный и может вызвать зависание сервера и он не несёт ответственности при его
использовании
Ответь письмом о низкой квалификации немецкого коллеги в области Firebird с рекомендацией
увольнения его за несоответствие служебной должности. Ну или тряси с него тесткейс. Типа
"докажь, что оно зависнет!"
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
11.04.2014, 13:45:56
    #38612303
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Dimitry Sibiryakov,

Да фиг с ним, с зависанием.
Где он тут увидел буфер, за пределы которого можно выйти?
...
Рейтинг: 0 / 0
11.04.2014, 13:50:07
    #38612317
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Dimitry Sibiryakov,

Я конечно так не буду поступать но за идею доказать нестабильность кода тестом в результате которого произойдёт ошибка спасибо.
А то когда такие письма приходят людям которые в программировании не разбираются начинаются вопросы на которые и ответить то нельзя толком т.к. они не знают программирования. А с тестом все понятно, вот тест который вызывает указанную функцию и вот ошибка которая при этом возникает. А если ошибки нет то уж извините, код функции стабилен.
...
Рейтинг: 0 / 0
11.04.2014, 13:51:49
    #38612321
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Mikhail TchervonenkoЯ попытался ему объяснить что тут контроль выхода за границу буфера присутствует
Вот и зря. Нет тут никакого буфера, обычная работа со строками.
Я даже не помню, нафига я оставил строку длиной 30100, а не 30000. Пожалуй, оно лишнее.

Это не UDF с СИ-кодом. Это высокоуровневый язык интерпретатора.
Здесь любые операции со строками (конкатенация, сравнение, подстрока) безопасны по определению.
В противном случае можно считать нестабильным и ненадёжным сам Firebird.
...
Рейтинг: 0 / 0
11.04.2014, 13:53:35
    #38612323
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSery,

буфером он называет эту строку
Код: plsql
1.
2.
3.
.....
declare buf varchar(30100); 
.....
...
Рейтинг: 0 / 0
11.04.2014, 13:55:38
    #38612327
miwaonline
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Mikhail TchervonenkoDimitry Sibiryakov,

Я конечно так не буду поступать
Зря. Если в компании принято письменно уведомлять начальство о косяках коллег/подчиненных, то надо так делать независимо от личного (не)принятия такого поведения. Просто чтобы не оказаться виновным в случае очередного косяка немецкого коллеги.
...
Рейтинг: 0 / 0
11.04.2014, 13:57:02
    #38612329
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Mikhail TchervonenkoУ меня тут один немецкий коллега посмотрел в эту функциюПокажите ему еще одну, "пущай полетает"
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
create or alter procedure split_into_words (
    a_text dm_name,
    a_dels varchar(50) default ',.<>/?;:''"[]{}`~!@#$%^&*()-_=+\|/',
    a_special char(1) default ' '
)
returns (
  word dm_name
) as
begin
for
    with recursive
    j as( -- loop #1: transform list of delimeters to rows
        select s,1 i, substring(s from 1 for 1) del
        from(
          select replace(:a_dels,:a_special,'') s
          from rdb$database
        )
        
        UNION ALL
        
        select s, i+1, substring(s from i+1 for 1)
        from j
        where substring(s from i+1 for 1)<>''
    )

    ,d as(
        select :a_text s, :a_special sp from rdb$database
    )
    ,e as( -- loop #2: perform replacing each delimeter to `space`
        select d.s, replace(d.s, j.del, :a_special) s1, j.i, j.del
        from d join j on j.i=1

        UNION ALL

        select e.s, replace(e.s1, j.del, :a_special) s1, j.i, j.del
        from e
        join j on j.i = e.i + 1
    )
    ,f as(
        select s1 from e order by i desc rows 1
    )
    
    ,r as ( -- loop #3: perform split text into single words
        select iif(t.k>0, substring(t.s from t.k+1 ), t.s) s,
             iif(t.k>0,position( del, substring(t.s from t.k+1 )),-1) k,
             t.i,
             t.del,
             iif(t.k>0,left(t.s, t.k-1),t.s) word
        from(
          select f.s1 s, d.sp del, position(d.sp, s1) k, 0 i from f cross join d
        )t

        UNION ALL

        select iif(r.k>0, substring(r.s from r.k+1 ), r.s) s,
             iif(r.k>0,position(r.del, substring(r.s from r.k+1 )),-1) k,
             r.i+1,
             r.del,
             iif(r.k>0,left(r.s, r.k-1),r.s) word
        from r
        where r.k>=0
    )
    select word from r where word>''
    into
        word
do
    suspend;
end


PS. Годится только для строки с не более чем 1024 словами. Разбивает на слова по произвольному списку разделителей (по дефолту этот список - все знаки препинания, плюс пробел).
...
Рейтинг: 0 / 0
11.04.2014, 13:57:20
    #38612331
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSeryВ противном случае можно считать нестабильным и ненадёжным сам Firebird.

Ну дык именно так этот немец и считает.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
11.04.2014, 14:06:26
    #38612351
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Dimitry SibiryakovНу дык именно так этот немец и считает.
Ну и при чём тут функция?
...
Рейтинг: 0 / 0
11.04.2014, 14:07:20
    #38612355
m7m
m7m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSeryЯ даже не помню, нафига я оставил строку длиной 30100, а не 30000. Пожалуй, оно лишнее.
Ну наверное считал что "слов" длиннее 100 символов
да еще и в конце "буфера" не будет
...
Рейтинг: 0 / 0
11.04.2014, 14:15:05
    #38612374
m7m
m7m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Dimitry Sibiryakov[quot Mikhail TchervonenНу или тряси с него тесткейс. Типа
"докажь, что оно зависнет!"


Код: sql
1.
select * from Tmp_List_To_Rows(' а вот здесь 3002 символа в которых нет символа разделителя')
...
Рейтинг: 0 / 0
11.04.2014, 14:16:53
    #38612380
m7m
m7m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
вместо Tmp_List_To_Rows читать List_To_Rows
...
Рейтинг: 0 / 0
11.04.2014, 14:19:16
    #38612387
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
m7m,

Да пофигу, сколько там символов, всё одно дальше 30000 читаться не будут.
Видимо, это остался мусор, сперва я пробовал писать не по 1 символу, а через поиск подстроки.

На самом деле, могу уронить сервер этой функцией. Достаточно подать "слово" длиной больше 30000.
Такой проверки в функции нет, и она зациклится.
Но точно так же я могу уронить сервер и вообще без функций. Как и любой из нас, любой сервер помимо firebird.

(хочешь, чтобы твой немецкий нетоварищ так и не нашёл примера - вставь проверку на beg = 1 после внутреннего цикла).
...
Рейтинг: 0 / 0
11.04.2014, 14:29:46
    #38612401
m7m
m7m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
m7mвместо Tmp_List_To_Rows читать List_To_Rows
и вместо 3002 читать 30002
...
Рейтинг: 0 / 0
11.04.2014, 14:36:43
    #38612412
m7m
m7m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSerym7m,
Да пофигу, сколько там символов, всё одно дальше 30000 читаться не будут.

таки да тут я был неправ
WildSery(хочешь, чтобы твой немецкий нетоварищ так и не нашёл примера - вставь проверку на beg = 1 после внутреннего цикла).
а это уже не мне
...
Рейтинг: 0 / 0
11.04.2014, 14:48:01
    #38612423
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Mikhail Tchervonenko,

Лови вариант с заткнутой "дыркой" зацикливания на очень длинное слово.
Кстати, исправления Таблоида тоже хороши - выходное "слово" не надо 8192 ограничивать, нехорошо это.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
create or alter procedure LIST_TO_ROWS (
    A_LST blob sub_type text,
    A_DEL char(1) = ',')
returns (
    LINE integer,
    EOF integer,
    ITEM varchar(32000))
AS
  declare pos_ int;
  declare offset int = 1;
  declare beg int;
  declare buf varchar(32000);
begin
  -- Splits blob to lines by single char delimiter.
  if (a_lst is null) then exit;
  line = 0;

  while (0=0) do begin
    buf = substring(a_lst from offset for 32000);
    pos_ = 1; beg = 1;
    while (pos_ <= char_length(buf) and pos_ <= 32000) do begin
      if (substring(buf from pos_ for 1) = :a_del) then begin
        if (pos_ > beg) then
          item = substring(buf from beg for pos_ - beg);
        else
          item = '';
        suspend;
        line = line + 1;
        beg = pos_ + 1;
      end
      pos_ = pos_ + 1;
    end
    if (beg = 1 and pos_ > 32000) then leave;
    if (offset + pos_ - 2 = char_length(a_lst)) then leave;
    offset = offset + beg - 1;
    if (offset > char_length(a_lst)) then leave;
  end

  if (beg = 1 and pos_ > 32000) then begin
    item = '#N/A';
    eof = -1;
  end
  else if (pos_ > beg) then begin
    item = substring(buf from beg for pos_ - beg);
    eof = -1;
  end
  else begin
    item = '';
    eof = -1;
  end
  suspend;
end
...
Рейтинг: 0 / 0
11.04.2014, 14:53:07
    #38612431
Таблоид
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSeryвыходное "слово" не надо 8192 ограничивать, нехорошо это.Пришлось из-за UTF8. Деталей не помню уже.
...
Рейтинг: 0 / 0
11.04.2014, 15:11:49
    #38612464
WildSery
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
Таблоид,

Ну так и буфер подрезать надо. Или 30К символов UTF-8 влезают в строку?
...
Рейтинг: 0 / 0
11.04.2014, 18:55:19
    #38612794
Mikhail Tchervonenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите с рекурсивным вызовом процедуры FB2.5
WildSery,

Спасибо
...
Рейтинг: 0 / 0
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Помогите с рекурсивным вызовом процедуры FB2.5 / 23 сообщений из 23, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]