powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Помогите с рекурсивным вызовом процедуры FB2.5
23 сообщений из 23, страница 1 из 1
Помогите с рекурсивным вызовом процедуры FB2.5
    #38601955
Фотография Mikhail Tchervonenko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем доброго времени суток!

Нарисовал следующую процедуру которая должна подсчитать количество слов в 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
Помогите с рекурсивным вызовом процедуры FB2.5
    #38601994
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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
Помогите с рекурсивным вызовом процедуры FB2.5
    #38602193
Фотография Mikhail Tchervonenko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,
Спасибо и Вам и WildSery
...
Рейтинг: 0 / 0
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612271
Фотография Mikhail Tchervonenko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид
Код: 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
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612283
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Mikhail Tchervonenkoэто не спасло от письма начальству с уведомлением что код
нестабильный и может вызвать зависание сервера и он не несёт ответственности при его
использовании
Ответь письмом о низкой квалификации немецкого коллеги в области Firebird с рекомендацией
увольнения его за несоответствие служебной должности. Ну или тряси с него тесткейс. Типа
"докажь, что оно зависнет!"
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612303
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry Sibiryakov,

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

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

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

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

Я конечно так не буду поступать
Зря. Если в компании принято письменно уведомлять начальство о косяках коллег/подчиненных, то надо так делать независимо от личного (не)принятия такого поведения. Просто чтобы не оказаться виновным в случае очередного косяка немецкого коллеги.
...
Рейтинг: 0 / 0
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612329
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612331
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WildSeryВ противном случае можно считать нестабильным и ненадёжным сам Firebird.

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


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

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

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

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

таки да тут я был неправ
WildSery(хочешь, чтобы твой немецкий нетоварищ так и не нашёл примера - вставь проверку на beg = 1 после внутреннего цикла).
а это уже не мне
...
Рейтинг: 0 / 0
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612423
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612431
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WildSeryвыходное "слово" не надо 8192 ограничивать, нехорошо это.Пришлось из-за UTF8. Деталей не помню уже.
...
Рейтинг: 0 / 0
Помогите с рекурсивным вызовом процедуры FB2.5
    #38612464
WildSery
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,

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

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


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