sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLでのサーバーサイドプログラミングの概要

    Postgresサーバーに事前定義されたコードを実行させる方法はたくさんあります。以下は、Postgresサーバーに事前定義されたロジックを保存させる方法の例を含む包括的なリストです。これは後でアプリケーションから使用できます。

    SQL関数

    Postgresを使用すると、サポートされている言語で関数本体を記述できる「ユーザー定義関数」を作成できます。 「SQL関数」は、通常のSQLで記述されたユーザー定義関数であり、複雑なクエリとSQLステートメントのシーケンスをカプセル化する最も簡単な方法です。

    次にいくつかの例を示します。

    -- update item price and record the change
    CREATE FUNCTION update_price(item text, newprice numeric) RETURNS void AS $$
        UPDATE items SET price=$2 WHERE name=$1;
        INSERT INTO audit (event, new_price, at, item)
          VALUES ('price changed', $2, now(), $1);
    $$ LANGUAGE SQL;
    
    -- a function from uuid-osp
    CREATE FUNCTION uuid_timestamp_bits(uuid) RETURNS varbit AS
    $$ SELECT ('x' || substr($1::text, 15, 4) || substr($1::text, 10, 4) ||
               substr($1::text, 1, 8) || substr($1::text, 20, 4))::bit(80)
              & x'0FFFFFFFFFFFFFFF3FFF' $$
    LANGUAGE SQL STRICT IMMUTABLE;

    SQL関数は、基本型、複合型、および行を受け入れて返すことができます。また、可変数の引数、引数および多態性引数のデフォルト値もサポートしています。テーブルからのSELECTを模倣して、複数の行を返すこともできます。また、何も返却する必要はありません。

    ただし、関数本体にはSQLステートメントのみを含めることができます。これは、フロー制御ステートメント(if、while、…)、変数などがないことを意味します。

    CREATE FUNCTIONコマンドは、関数を作成するために使用されます。いつものように、ALTERとDROPthemを実行できます。

    これは、さらに掘り下げるのに最適な場所です:https://www.postgresql.org/docs/current/xfunc-sql.html

    C関数

    SQL関数は最も簡単に記述でき、最も強力ではありませんが、逆に、関数はCで記述でき、ほとんど何でもできます。このような関数はCでコーディングし、Postgresによって動的にロードできる共有ライブラリとして構築する必要があります。

    共有ライブラリをロードする場所、関数の名前と署名をPostgresに指示する必要があります:

    CREATE FUNCTION sum(integer, integer) RETURNS integer
        AS 'myfuncs', 'sum'
        LANGUAGE C STRICT;

    これは、共有ライブラリmyfuncs.so は、事前定義された検索パスに存在し、Postgresによって呼び出すことができるエントリポイントを含みます。エントリポイントの1つは、関数として呼び出すことができる「合計」です。

    Cの実際のコードは長すぎてここに含めることはできませんが、ドキュメントですべてを読むことができます。サーバープログラミングインターフェイス(SPI)と組み合わせると、他の方法で実行できるほとんどすべての操作を実行できます。

    たとえば、ここで定義されているC関数を使用すると、HTTPリクエストを実行できます。

    SELECT status, content_type FROM http_get('https://postgresql.org/');

    このような共有ライブラリをC++やGoなどの他の言語で記述して、「C」リンケージを使用して共有ライブラリを構築することもできます。

    PL/pgSQL関数

    SQLとC以外に、手続き型言語で関数を記述できます。 。このような4つの言語はコアPostgreSQLでサポートされています– pgSQL、Python、Perl、Tcl。手続き型言語自体のサポートはC共有ライブラリから提供され、 mod_perlのように動作します。 またはmod_python アパッチ時代から。

    pgSQL は、PostgreSQLの保存された関数が記述されている、標準的な、最も使用されているSQLのような言語です。 template1にインストールされているため、デフォルトで使用できます。 。

    PL / pgSQLは、変数、式、および制御ステートメントを備えた本格的な言語です。特にSQLデータを操作するためのカーソルなどの機能が含まれています。ここに詳細に記載されています。

    次に例を示します:

    CREATE FUNCTION repeat(times integer, s text)
        RETURNS text
        AS $$
    DECLARE
        result text;
    BEGIN
        result := '';
        FOR i IN 1..times LOOP
            result := result || s;
        END LOOP;
        RETURN result;
    END;
    $$
    LANGUAGE plpgsql
    IMMUTABLE;
    
    -- psql> SELECT repeat(10, '*');
    --    repeat
    -- ------------
    --  **********
    -- (1 row)
    その他のコア手続き型言語

    他の手続き型言語(Python、Perl、Tcl)を使用すると、開発者はすでに使い慣れている言語を使用できます。これらの言語のサポートはPostgresソースツリーにありますが、ディストリビューションは通常、デフォルトでバイナリをインストールしません。たとえば、Debianでは次のことを行う必要があります。

    sudo apt install postgresql-plpython-11

    PostgreSQL11のPL/Pythonサポートをインストールします。

    関数の記述に使用している言語が何であれ、呼び出し元はその使用法の違いを認識しません。

    Python

    PL / Python拡張機能は、Python2およびPython3での関数の記述をサポートしています。これをインストールするには、次のようにします。

    CREATE EXTENSION plpythonu;

    PL/Pythonで記述された関数は次のとおりです。

    CREATE FUNCTION pymax (a integer, b integer)
      RETURNS integer
    AS $$
      if a > b:
        return a
      return b
    $$ LANGUAGE plpythonu;

    関数本体が実行されるPython環境には、plpyというモジュールがあります。 自動的にインポートされます。このモジュールには、クエリの準備と実行、トランザクションの処理、カーソルの操作を可能にするメソッドが含まれています。

    詳細については、Postgresドキュメントの第46章を参照してください。

    Perl

    そうですね、Perlです。 Postgresの開発、テスト、ビルドのプロセスはPerlextensivelyを使用しており、手続き型言語としてもサポートされています。使用を開始するには、ディストリビューションに関連するバイナリパッケージがインストールされていることを確認し(例:Debianの場合は「postgresql-plperl-nn」)、拡張機能「plperl」をインストールします。

    PL/Perlで書かれた関数は次のとおりです。

    CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
        my ($x, $y) = @_;
        if (not defined $x) {
            return undef if not defined $y;
            return $y;
        }
        return $x if not defined $y;
        return $x if $x > $y;
        return $y;
    $$ LANGUAGE plperl;

    完全なドキュメントはこちら。

    Tcl

    Tclは、コアPostgresによってサポートされるさらに別のPLです。次に例を示します:

    CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
        if {[argisnull 1]} {
            if {[argisnull 2]} { return_null }
            return $2
        }
        if {[argisnull 2]} { return $1 }
        if {$1 > $2} {return $1}
        return $2
    $$ LANGUAGE pltcl;

    詳細については、こちらのドキュメントを参照してください。

    非コア手続き型言語

    これらの言語以外にも、Java、Lua、Rなどの他の言語のサポートを開発および維持するオープンソースプロジェクトがあります。

    ここにリストがあります:https://www.postgresql.org/docs/current/external-pl.html

    集計関数

    集計関数は一連の値に対して動作し、単一の結果を返します。PostgreSQLには多数の組み込み集計関数があります(完全なリストはこちらをご覧ください)。たとえば、列内のすべての値の母標準偏差を取得するには、次のようにします。できること:

    SELECT stddev_pop(grade) FROM students;

    同様に動作する独自の集計関数を定義できます。ユーザー定義の集計は、内部状態で機能するいくつかの個別のスタンドアロン関数から組み立てられます(たとえば、平均を計算する集計の内部状態は、「合計」変数と「カウント」変数である可能性があります)。

    一連の値の中央値を計算するユーザー定義の集計は次のとおりです。

    -- from https://wiki.postgresql.org/wiki/Aggregate_Median
    CREATE OR REPLACE FUNCTION _final_median(NUMERIC[])
       RETURNS NUMERIC AS
    $$
       SELECT AVG(val)
       FROM (
         SELECT val
         FROM unnest($1) val
         ORDER BY 1
         LIMIT  2 - MOD(array_upper($1, 1), 2)
         OFFSET CEIL(array_upper($1, 1) / 2.0) - 1
       ) sub;
    $$
    LANGUAGE 'sql' IMMUTABLE;
     
    CREATE AGGREGATE median(NUMERIC) (
      SFUNC=array_append,
      STYPE=NUMERIC[],
      FINALFUNC=_final_median,
      INITCOND='{}'
    );

    これは次のように呼び出すことができます:

    SELECT median(grade) FROM students;

    詳細については、aggregatesおよびCREATEAGGREGATEステートメントに関するドキュメントを参照してください。

    ユーザー定義タイプ

    以前に見たCで記述された共有ライブラリは、関数だけでなくデータ型も定義できます。これらのユーザー定義型は、組み込み型と同様に、列のデータ型として使用できます。ユーザー定義タイプの値を操作する関数を定義できます。

    新しい型を定義するには、少しコードが必要です。複素数を表す新しい型の作成について説明しているドキュメントを参照してください。 Postgresソースには、このためのチュートリアルコードも含まれています。

    オペレーター

    演算子を使用すると、関数が使いやすくなります(たとえば、1 + 2を記述します)。 sum(1, 2)ではなく )、CREATEOPERATORステートメントを使用してユーザー定義型の演算子を定義できます。

    +を作成する例を次に示します。 関数complex_addにマップする演算子 2つのcomplexを追加します 番号:

    CREATE OPERATOR + (
        leftarg = complex,
        rightarg = complex,
        function = complex_add,
        commutator = +
    );

    詳細はこちらとこちら。

    演算子クラスと演算子ファミリ

    演算子クラスを使用すると、データ型を組み込みのBツリーやその他のインデックスメソッドで機能させることができます。たとえば、「complex」タイプの列にBツリーインデックスを作成する場合は、このタイプの2つの値を比較して、一方が他方よりも小さいか、等しいか、大きいかを判断する方法をPostgresに指示する必要があります。

    複雑な型を整数または浮動小数点値と比較するとよいでしょう。これが演算子ファミリの出番です。

    オペレータークラスとファミリーについては、ここですべて読むことができます。

    トリガー

    トリガーは、通常の操作で副作用を引き起こす強力なメカニズムですが、使いすぎたり乱用したりすると危険な場合があります。基本的に、トリガーはイベントを関数に接続します。参照されている関数を呼び出すことができます:

    • テーブルの行の挿入/更新/削除の前または後
    • テーブルの切り捨てについて
    • ビューの行の挿入/更新/削除の代わりに

    この関数は、ステートメントの影響を受ける行ごとに呼び出すことも、ステートメントごとに呼び出すこともできます。また、トリガーのカスケードなど、さらに多くのことがあります。これらはすべてここで説明されています。

    トリガー関数は、Cまたは任意のPL関数で記述できますが、inSQLでは記述できません。 監査に行を挿入する例を次に示します。 表、価格に対して行われたすべての更新 アイテムの 。

    -- first create the function
    CREATE FUNCTION log_update() RETURNS TRIGGER AS $$
        INSERT INTO audit (event, new_price, at, item)
          VALUES ('price changed', NEW.price, now(), OLD.item);
    $$
    LANGUAGE plpgsql;
    
    -- then create the trigger
    CREATE TRIGGER audit_price_changes
        AFTER UPDATE ON items
        FOR EACH ROW
        WHEN (OLD.price IS DISTINCT FROM NEW.price)
        EXECUTE FUNCTION log_update();

    CREATE TRIGGERのドキュメントとともに、トリガーに関するすべてをここでお読みください。

    イベントトリガー

    トリガー 単一のテーブルのDMLイベントに応答するイベントトリガー 特定のデータベースのDDLイベントに応答できます。イベントには、テーブル、インデックス、スキーマ、ビュー、関数、タイプ、演算子などのさまざまなオブジェクトの作成、変更、削除が含まれます。

    「監査」スキーマからのオブジェクトのドロップを防ぐイベントトリガーは次のとおりです。

    -- create function first
    CREATE FUNCTION nodrop() RETURNS event_trigger LANGUAGE plpgsql AS $$
    BEGIN
        IF EXISTS(
          SELECT 1
          FROM pg_event_trigger_dropped_objects() AS T
          WHERE T.schema_name = 'audit')
        THEN
          RAISE EXCEPTION 'not allowed to drop objects in audit schema';
        END IF;
    END $$;
    
    -- create event trigger
    CREATE EVENT TRIGGER trigger_nodrop
        ON sql_drop
        EXECUTE FUNCTION nodrop();

    詳細については、こちらとCREATEEVENTTRIGGERのドキュメントをご覧ください。

    ルール

    PostgreSQLには、クエリプランナーに到達する前にクエリを書き直すことができる機能が付属しています。操作は、受信URLを処理する前に書き換えるようにNginxまたはApacheを構成するのと多少似ています。

    テーブルのINSERTステートメントに影響を与え、他の何かを実行させる2つの例を次に示します。

    -- make inserts into "items" table a no-op
    CREATE RULE rule1 AS ON INSERT TO items DO INSTEAD NOTHING;
    
    -- make inserts go elsewhere
    CREATE RULE rule2 AS ON INSERT TO items DO INSTEAD
        INSERT INTO items_pending_review VALUES (NEW.name, NEW.price);

    ドキュメントのこの章には、ルールに関する詳細情報があります。

    ストアドプロシージャ

    Postgres 11以降、保存されたプロシージャを作成することができます。 保存された関数と比較して、procedurescanが実行できる追加の機能はトランザクション制御だけです。

    次に例を示します:

    CREATE PROCEDURE check_commit(v integer)
    LANGUAGE plpgsql AS $$
    BEGIN
        IF v % 2 = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
    END $$;
    
    -- call it
    CALL check_commit(10);

    詳細については、こちらとこちらをご覧ください。

    その他のエキゾチックなもの 外部データラッパー

    外部データラッパー(FDW)を使用すると、anotherPostgresサーバー、MySQL、Oracle、Cassandraなどの他のデータソースと通信できます。外部サーバーにアクセスするためのすべてのロジックは、共有ライブラリとしてCで記述されています。

    FDWに基づくcstore_fdwと呼ばれる列型ストアもあります。

    FDW実装のリストは、PostgresWikiおよびその他のドキュメントにあります。

    インデックスアクセスメソッド

    PostgreSQLには、Bツリー、ハッシュ、GINなどのインデックスタイプが付属しています。これに似た独自のインデックスタイプをC共有ライブラリとして作成することができます。詳細はこちら。

    テーブルアクセスメソッド

    今後のPostgreSQL12では、独自のデータストレージ構造を作成できるようになります。ここで説明するインターフェースを実装することにより、選択した方法でタプルデータを物理的にディスク上に保存できます。

    論理レプリケーションプラグイン

    PostgreSQLでは、論理レプリケーションは、先行書き込みログ(WAL)の内容を任意の形式(SQLテキストやjsonなど)に「デコード」し、レプリケーションスロットを介してサブスクライバーに公開することで実装されます。このデコードは、論理デコード出力プラグインを介して行われます。 、ここで説明するように、C共有ライブラリとして実装できます。「test_decoding」共有ライブラリはそのようなプラグインの1つであり、独自のプラグインを作成できます。

    手続き型言語ハンドラー

    ハンドラーを作成することで、PostgresPLとしてお気に入りのプログラミング言語のサポートを追加することもできます。これもC共有ライブラリとしてです。ここから始めて、PL/GoまたはPL/Rustを作成してください!

    拡張機能

    拡張機能は、Postgresのパッケージ管理方法です。何か便利なことをするC関数と、それを設定するために必要な「CREATEFUNCTION」ステートメントを作成するSQLステートメントがいくつかあるとします。これらは、Postgresが1つのステップでインストール(およびアンインストール)できる「拡張機能」としてバンドルできます(「CREATEEXTENSION」を呼び出すことにより)。新しいバージョンを出すときは、拡張機能にもアップグレード手順を含めることができます。

    サーバー側のプログラミング自体ではありませんが、拡張機能は、サーバー側のコードをパッケージ化して配布するための標準的で非常に効率的な方法です。

    拡張機能の詳細については、こちらとこちらをご覧ください。


    1. PostgreSQLの将来のテーブルに対する特権を付与しますか?

    2. SQLServerの「intをデータ型numericに変換する算術オーバーフローエラー」を修正しました

    3. エラー、文字列、またはバイナリデータは、挿入しようとすると切り捨てられます

    4. データベースからデータをプルしてListViewとして表示する方法