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

plpgsql関数の引数としてテーブル名と列名を定義しますか?

    SQLインジェクションに対して防御する必要があります ユーザー入力をコードに変換するときはいつでも。これには、システムカタログまたは直接のユーザー入力からのテーブル名と列名が含まれます。このようにして、非標準の識別子を使用した些細な例外も防止できます。基本的に3つあります 組み込みメソッド:

    1。 format()

    最初のクエリ、サニタイズ:

    CREATE OR REPLACE FUNCTION foo(_t text)
      RETURNS void
      LANGUAGE plpgsql AS
    $func$
    BEGIN
       EXECUTE format('
       ALTER TABLE %I ADD COLUMN c1 varchar(20)
                    , ADD COLUMN c2 varchar(20)', _t);
    END
    $func$;
    

    format() Postgres9.1以降が必要です。 %Iで使用します フォーマット指定子。

    テーブル名だけではあいまいな場合があります。誤って間違ったテーブルを変更しないように、スキーマ名を指定する必要がある場合があります。関連:

    • トリガー関数に動的テーブル名を指定してINSERT
    • search_pathは識別子の解決と「現在のスキーマ」にどのように影響しますか

    余談ですが、複数の列を追加 単一のALTER TABLE コマンドの方が安いです。

    2。 regclass

    登録されたクラスへのキャストを使用することもできます(regclass既存の特殊なケースの場合 テーブル名。オプションでスキーマ修飾。これは、有効でなく、呼び出し元のユーザーに表示されないテーブル名の場合、すぐに適切に失敗します。 regclassへのキャストでサニタイズされた最初のクエリ :

    CREATE OR REPLACE FUNCTION foo(_t regclass)
      RETURNS void
      LANGUAGE plpgsql AS
    $func$
    BEGIN
       EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
                                       , ADD COLUMN c2 varchar(20)';
    END
    $func$;
    

    電話:

    SELECT foo('table_name');
    

    または:

    SELECT foo('my_schema.table_name'::regclass);
    

    余談ですが、textだけを使用することを検討してください varchar(20)の代わりに 。

    3。 quote_ident()

    サニタイズされた2番目のクエリ:

    CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
      RETURNS void
      LANGUAGE plpgsql AS
    $func$
    BEGIN
       EXECUTE 'UPDATE ' || _t    -- sanitized with regclass
            || ' SET ' || quote_ident(_c) || ' = ''This is a test''';
    END
    $func$;
    

    複数の連結/補間の場合、format() きれいです...

    関連する回答:

    • PostgreSQL関数パラメータとしてのテーブル名
    • Postgres関数と準備されたクエリ

    大文字と小文字を区別してください!

    引用符で囲まれていない識別子はではないことに注意してください ここで小文字にキャストします。 SQLで識別子として使用される場合[Postgresは自動的に小文字にキャストします][7]。ただし、ここでは文字列を渡します 動的SQLの場合。示されているようにエスケープすると、CaMelケース識別子(UserSなど) )は二重引用符で保持されます("UserS" )、"name with space"のような他の非標準の名前と同じように "SELECT" したがって、このコンテキストでは名前で大文字と小文字が区別されます。

    私の常識的なアドバイスは、法的な小文字の識別子のみを使用し、それについて心配することはありません。

    余談ですが、一重引用符は値用、二重引用符は識別子用です。参照:

    • https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS



    1. InnoDBを使用した全文検索

    2. 結合されたテーブル列の個別の合計を取得します

    3. GROUP BYを使用してMySQLで文字列を連結するにはどうすればよいですか?

    4. SQL ServerのLOG10()の例