Заставить postgres выполнять ожидание блокировки

#c #postgresql #plpgsql #notify #listen

#c #postgresql #plpgsql #уведомить #слушать

Вопрос:

Я подумал, что было бы интересно (и полезно) создать блокировку wait(), которую можно было бы использовать из функции plpgsql. У меня это работает, но я не уверен, что это хорошо задумано. При использовании datagrip возникает одна интересная проблема. Если я вызываю свой pg_wait() из функции:

 select util.wait_test_func() into var   --this calls my pg_wait()
  

Функция будет правильно блокироваться до тех пор, пока я не отправлю УВЕДОМЛЕНИЕ в другом окне консоли запросов. Фактически, если функция wait_test_function() вызывает мою pg_wait() три раза, она будет корректно заблокирована три раза, и мне придется вызвать NOTIFY три раза, чтобы разрешить завершение функции. Однако, как только функция завершится, если я вызову ее снова, она немедленно вернется без блокировки. Это почти так, как если бы УВЕДОМЛЕНИЕ все еще находилось в очереди, но я не совсем уверен, что это проблема. Если я закрою консоль запросов datagrip, открою новую и повторно выполню вызов функции, она снова будет работать, как ожидалось, правильно блокируя. Я могу повторять это последовательно. Первый вызов в новом окне консоли запросов всегда правильно блокируется, но каждый последующий вызов всегда возвращается немедленно. Это моя первая функция C в postgres, поэтому мне интересно, не делаю ли я что-то в корне неправильное. Спасибо за любую помощь. Мой код следует.

Функция C:

 #ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>

#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#include "libpq-fe.h"
#include "postgres.h"
#include <limits.h>
#include <unistd.h>
#include <string.h>
#include "fmgr.h"
#include "utils/palloc.h"
#include "utils/elog.h"
#include "storage/bufpage.h"
#include "utils/builtins.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1( pg_wait );

Datum pg_wait( PG_FUNCTION_ARGS );

Datum pg_wait( PG_FUNCTION_ARGS )
{
    PGconn     *conn;
    PGresult   *res;
    PGnotify   *notify;
    int         nnotifies;
    int         sock;
    fd_set      input_mask;
    
    char* conninfo = text_to_cstring(PG_GETARG_TEXT_PP(0));
    char* channel_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
    
    char strlisten[50];
    strcpy(strlisten,  "LISTEN ");
    strcat(strlisten, channel_name);

    conn = PQconnectdb(conninfo);
    res = PQexec(conn, strlisten);
    PQclear(res);

    sock = PQsocket(conn);
    FD_ZERO(amp;input_mask);
    FD_SET(sock, amp;input_mask);
    select(sock   1, amp;input_mask, NULL, NULL, NULL);
    PQconsumeInput(conn);
    if ((notify = PQnotifies(conn)) != NULL)
    {
       PQfreemem(notify);
       PQconsumeInput(conn);
    }
    PQfinish(conn);

    PG_RETURN_TEXT_P( PG_GETARG_TEXT_PP(1) );
}
  

Util.wait_test_func()

 create or replace function util.wait_test_func() returns integer
    parallel safe
    language plpgsql
as $$
DECLARE
    signal_name TEXT;
BEGIN
    RAISE NOTICE 'Before wait1';
    SELECT pg_wait('dbname=edw port=5432','CHANNEL1') INTO signal_name;
    RAISE NOTICE 'After wait1: %', signal_name;

    RAISE NOTICE 'Before wait2';
    SELECT pg_wait('dbname=edw port=5432','CHANNEL1') INTO signal_name;
    RAISE NOTICE 'After wait2: %', signal_name;

    RAISE NOTICE 'Before wait3';
    SELECT pg_wait('dbname=edw port=5432','CHANNEL1') INTO signal_name;
    RAISE NOTICE 'After wait3: %', signal_name;

    RETURN 0;
END
$$;
  

Еще раз спасибо за любую помощь, которую вы можете предоставить.

Комментарии:

1. Что произойдет, если вы используете psql вместо datagrip?

2. Я действительно попробовал это, и это ничего не изменило.

Ответ №1:

Вы пытались объявить свою функцию VOLATILE

Комментарии:

1. Я только что попробовал это сейчас, и это не имело никакого значения. То же самое поведение, что и раньше.

2. Я попробовал это снова, но на этот раз я добавил его как в тестовую функцию wait_test_func(), так и в функцию C pg_wait() . Добавление его в функцию C имело значение. Это сработало! Большое вам спасибо за ответ.