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

Postgresql:データベーストリガーで一重引用符をエスケープする方法は?

    一般に、引用符は2倍にすることでエスケープされます。

    変数をSQL文字列に連結するには、quote_literal()を使用する必要があります -その関数は、一重引用符を適切にエスケープします(例:

    )。
    quote_literal(temp_row.row_data)
    

    そうは言っても、より良い(そしてより安全な)解決策は、format()と組み合わせたパラメーターを使用することです。 :

    EXECUTE 
       format('INSERT INTO audit.%I_history values ($1, $2, $3)', tg_table_name)
       using temp_row.action_tstamp_tx, temp_row.action, temp_row.row_data; 
    

    %I プレースホルダーは通常、識別子を適切にエスケープしますが、この場合は機能しません。非標準のテーブル名でも正しく機能することを100%確認したい場合は、最初にターゲットテーブル名を変数に入れ、それをformat()に使用する必要があります。 機能:

    l_tablename := TG_TABLE_NAME || '_history';
    EXECUTE 
       format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
       using ....
    

    この部分:

    v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
    execute v_sql into temp_row;
    

    最初の行の後も失敗します。 execute .. into ... クエリがシングルを返すことを期待します 。使用しているステートメントはすべてを返します 履歴テーブルの行。

    そもそもなぜそうするのかもわかりません。

    履歴テーブルから選択する必要はまったくありません。

    このようなもので十分です(未テスト! ):

    IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN
        temp_row := OLD;
    ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
        temp_row := OLD;
    ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
        temp_row := NEW;
    ELSE
        RAISE EXCEPTION '[audit.if_modified] - Trigger func added as trigger for unhandled case: %, %',TG_OP, TG_LEVEL;
        RETURN NULL;
    END IF;
    
    execute format ('insert ... values ($1, $2, $3') 
       using now(), SUBSTRING(TG_OP,1,1), temp_row;
    

    最後に、監査トリガーは以前に作成されており、これに対する既成のソリューションがたくさんあります:




    1. odbcを使用してasp.netc#およびMysqlのクエリ問題を更新します

    2. null以外の列を連結すると、Postgresqlで生成された列が失敗する

    3. MySQLで2つの日付の間のレコードを取得する方法

    4. MacでMysqlを起動できません