Вопрос

Можно ли сделать внешнюю функцию как постоянную или неизменную, чтобы Firebird знал, что не пересматривает ее в течение одного оператора SQL?

В примере ниже (Firebird 2.1) я бы хотел, чтобы GetTimeOfDay () вели себя как Current_TimestAmp, но вместо этого он оценивается дважды:

SQL> DECLARE EXTERNAL FUNCTION gettimeofday -- gettimeofday(2) wrapper
CON>         RETURNS DOUBLE PRECISION BY VALUE
CON>         ENTRY_POINT 'UDF_gettimeofday' MODULE_NAME 'udf_gettimeofday';

SQL> SELECT CURRENT_TIMESTAMP AS ts,
CON>        CAST(GETTIMEOFDAY() AS INTEGER) AS time_t,
CON>        FB_SLEEP(2) AS zzz
CON>   FROM rdb$database
CON>  CROSS JOIN (SELECT 1 AS foo
CON>                FROM rdb$database
CON>               UNION ALL
CON>              SELECT 2
CON>                FROM rdb$database) d;

                       TS       TIME_T          ZZZ
========================= ============ ============
2011-03-15 20:57:46.0390    1300244268            0
2011-03-15 20:57:46.0390    1300244270            0

Как вы можете видеть, значение «ts» остается постоянным, но мой «Time_t» достигает вызовов fb_sleep (). (Fb_sleep - это удобная функция для паузы в течение заданного количества секунд.)

Что я хочу, я хочу? Я знаю, что PostgreSQL разрешает именно это с его концепцией СТАБИЛЬНЫЙ Функции.

Это было полезно?

Решение 2

Вкратце

Краткий ответ - «Нет», а сопровождающее руководство - «всегда запускайте ваш сервер в UTC».

Обходные пути

  • Самый простой случай: стабильные временные метки UTC
    (Это была моя первоначальная цель.) Если Current_timestamp достаточно точен, просто запустите свой сервер в UTC. Не требуется UDF.

  • Явно предварительно выпустить UDF
    Там нет непосредственно поддерживаемого способа «стабилизировать» UDF. Таким образом, большинству клиентов лучше просто предварительно выписать возвратное значение UDF, предоставляя это буквальное значение доступным в виде клиентского параметра, в GTT и т. Д.

Клудж

Current_transaction и current_timestamp, вместе взятые вместе, эффективно идентифицируют отдельный запрос, по крайней мере, к точности current_timestamp. (Снова предполагая, что часы находятся в UTC, чтобы повторение времени повторно во время изменения сбережений дневного света.)

Это в виду, выбираемая хранимая процедура может кэшировать возвращаемое значение UDF как строка Используя rdb $ set_context и rdb $ get_context, хранение в контексте user_transaction и отключение от Current_timestamp. Добавьте небольшую дополнительную логику, чтобы обрезать количество записей, хранящихся в User_transaction. Выносливый

Другие советы

Afaik, вы не можете пометить UDF как постоянную или не подлежащую пользу Firebird, но как обходной путь вы можете положиться на встроенный вид (он же полученная таблица), чтобы достичь того, что вы хотите: выберите значение только один раз и используйте его в качестве постоянного в ваших результатах. У меня нет никакого UDF под рукой, чтобы сделать тест, так что, возможно, какая -то синтаксическая ошибка, но я надеюсь, что вы поймаете идею этого:

SELECT CURRENT_TIMESTAMP AS ts,
        q1.time_t,
        FB_SLEEP(2) AS zzz
   FROM rdb$database
  CROSS JOIN (select CAST(GETTIMEOFDAY() AS INTEGER) AS time_t from rdb$database)
  CROSS JOIN (SELECT 1 AS foo
                FROM rdb$database
               UNION ALL
              SELECT 2
                FROM rdb$database) d;

Вы также можете полагаться на выбираемую хранируемую процедуру для запуска UDF один раз и добавить столбец к результатам данного запроса

Редактировать Как было запрошено, я включаю хранимую процедуру:

SET TERM ^ ;

CREATE PROCEDURE ExampleSP 
RETURNS 
(
  ts timestamp
, time_t integer
, zzz integer
)
as
BEGIN
  SELECT CAST(GetTimeOfDay() AS Integer)
    FROM rdb$database
    INTO :time_t;
  for SELECT Current_Timestamp AS ts,
             FB_SLEEP(2) AS zzz
        FROM rdb$database
       CROSS JOIN (SELECT 1 AS foo
                     FROM rdb$database
                    UNION ALL
                   SELECT 2
                     FROM rdb$database) d
        INTO :ts, :zzz do
    SUSPEND;
END
^

SET TERM ; ^

SELECT * FROM ExampleSP;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top