1

eclipse-link によって生成されたいくつかのテーブルの主キー制約を削除するループを含むplpgsql スクリプト(編集者注: 実際には関数です)があります。次のようになります。

CREATE OR REPLACE FUNCTION remove_tables_constraints()
  RETURNS boolean AS
$BODY$
  DECLARE
    constraint_statment text;
  BEGIN
    FOR constraint_statment IN
      SELECT  'ALTER TABLE '||nspname||'.'||relname||' DROP CONSTRAINT '||conname
         FROM pg_constraint
         INNER JOIN pg_class ON conrelid=pg_class.oid
         INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace
         where relname not in('exclude_table')
         ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END,contype,nspname,relname,conname     LOOP
         raise notice 'remove_tables_constraints run [%]', constraint_statment;
         EXECUTE constraint_statment;
     END LOOP;
    RETURN true;
  END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE COST 100;

select remove_tables_constraints();

スクリプトは次を使用して実行されます。

Statement st = connection.createStatement();
st.execute(scriptStringloadedFromFile);

スクリプトは正常に機能しました (状況によっては引き続き機能します)。
テーブルの主キーを から に変更した後、機能しなくなりintましたuid。ループはエラー メッセージを表示せずに実行の途中で停止します (デバッグは最高レベルに設定されます)。

奇妙な点は、スクリプトをコードから実行するのではなく、psql シェルに貼り付けるだけで、変更後でもスクリプトが機能することです。さらに、ループを展開し、ループがインラインで実行するすべてのステートメントを記述するだけで、Java コードから実行するときに機能します。

私はこれに数日を費やしましたが、続行する方法がわかりません。何か案は ?

4

1 に答える 1

1

いくつかの問題があります。

  • 識別子をサニタイズする必要があるか、例外が発生したり、さらに悪いことに、SQL インジェクションの攻撃経路を開く可能性があります。二重引用符で囲まれていない限り、識別子は不正な文字列になる可能性があります。Postgres に自動的に処理させる方法はいくつかあります。
    以下の2つのフォームを使用しました。

  • 関数はすべての制約を削除していますが、説明に従ってPK 制約( contype = 'p')のみを削除したいと考えています。

  • システム カタログやその他のシステム スキーマを除外しているわけではありません。これは何があっても失敗するはずです。

  • 言語名を引用しないでくださいplpgsql。識別子です。

すべてをまとめると、次のようになります。

CREATE OR REPLACE FUNCTION remove_tables_constraints()
  RETURNS boolean AS
$func$
DECLARE
   constraint_statment text;
BEGIN
   FOR constraint_statment IN
      SELECT format('ALTER TABLE %s DROP CONSTRAINT %I'
                    , c.oid::regclass, o.conname)
      FROM   pg_constraint o
      JOIN   pg_class      c ON c.oid = o.conrelid
      JOIN   pg_namespace  n ON n.oid = c.relnamespace 
      WHERE  c.relname <> 'exclude_table'       -- just one? then <>
      AND    o.contype = 'p'                    -- only pk constraints
      AND    n.nspname NOT LIKE 'pg%'           -- exclude system schemas!
      AND    n.nspname <> 'information_schema'  -- exclude information schema!
      ORDER  BY n.nspname, c.relname, o.conname -- commented irrelevant item
    LOOP
         RAISE NOTICE 'remove_table_constraints run [%]', constraint_statment;
         EXECUTE constraint_statment;
    END LOOP;
    RETURN TRUE;
END
$func$
LANGUAGE plpgsql;

または、ループなしで、より良いかもしれません。ここでは、最初にコマンドの 1 つのリストに集約し、それを 1 回実行します。

CREATE OR REPLACE FUNCTION remove_tables_constraints()
  RETURNS boolean AS
$func$
DECLARE
   _sql text;
BEGIN
   SELECT INTO _sql
          string_agg(format('ALTER TABLE %s DROP CONSTRAINT %I'
                    , sub.tbl, sub.conname), E';\n')
   FROM (
      SELECT c.oid::regclass AS tbl, o.conname
      FROM   pg_constraint o
      JOIN   pg_class      c ON c.oid = o.conrelid
      JOIN   pg_namespace  n ON n.oid = c.relnamespace 
      WHERE  c.relname <> 'exclude_table'       -- just one? then <>
      AND    o.contype = 'p'                    -- only pk constraints
      AND    n.nspname NOT LIKE 'pg%'           -- exclude system schemas!
      AND    n.nspname <> 'information_schema'  -- exclude information schema!
      ORDER  BY n.nspname, c.relname, o.conname -- commented irrelevant item
      LIMIT 10
      ) sub;

   RAISE NOTICE E'remove_table_constraints:\n%', _sql;
   EXECUTE _sql;

   RETURN TRUE;
END
$func$
LANGUAGE plpgsql;
于 2013-08-14T18:04:57.807 に答える