質問

Firebirdが1つのSQLステートメントの過程でそれを再計算しないことを知っているように、外部関数を一定または不変として作成することは可能ですか?

以下の例(Firebird 2.1)では、gettimeofday()がcurrent_timestampのように振る舞いたいと思いますが、代わりに2回評価されます。

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を1回実行し、特定のクエリの結果に列を追加することもできます

編集 要求に応じて、私はストアドプロシージャを含めています:

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