私は現在Postgresql 10.6をローカルで実行していますが、PgAdmin 4.12を使用してインターフェイスします。今日まで、すべてが正常に実行されていました。しかし、今日はpgAdminクエリエディターで次のクエリを実行しました。
SELECT * FROM test_table LIMIT 100
次のエラーが発生しました:
ERROR: operator does not exist: - oid at character 125 HINT: No operator matches the given name and argument type. You might need to add an explicit type cast. STATEMENT: SELECT at.attname, at.attnum, ty.typname FROM pg_attribute at LEFT JOIN pg_type ty ON (ty.oid = at.atttypid) WHERE attrelid=-1519044407::oid AND attnum = ANY ( (SELECT con.conkey FROM pg_class rel LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' WHERE rel.relkind IN ('r','s','t', 'p') AND rel.oid = -1519044407::oid)::oid[])
奇妙なことに、昨日作成されたテーブルで同じコマンドを実行すると、データがPgadminデータ出力ウィンドウに正常に出力されます。また、psqlで同じコマンドを実行してみました。
psql -U postgres -d geodata -c 'SELECT * FROM test_table LIMIT 100'
これも成功しました。 Pgadminでテーブルを作成できますが、直接出力することはできません。私が作成した新しいテーブルはすべて、一番上のエラーで終了します。唯一の違いは、OIDの変更です。 Pgadminをアンインストールし、残っているすべてのフォルダーを削除して、変更せずに再インストールしました。
誰が問題が何であるかについて何か考えがありますか?問題はpgadminが原因ですか、それともPostgresqlサーバーが何らかの方法で破損していますか?
negativeOIDを見たことがない。これは一流の「犯罪現場」です!
... attrelid=-1519044407::oid ... ... rel.oid = -1519044407::oid ...
2^32 - 1519044407 = 2775922889
また、OID 2775922889
が実際にDBに存在することを確認しました。テスト:
SELECT * FROM pg_class WHERE oid = 2775922889;
SELECT * FROM pg_class WHERE oid = '-1519044407';
SELECT * FROM pg_class WHERE relname = 'test_table';
oid
型は現在、符号なし4バイト整数として実装されています。
とにかくPostgresキャストはsigned整数を受け入れます(!)
文字列リテラルからのPostgres I/O変換、およびinteger
currently(12ページ)からのキャストは、負の整数値/リテラルを入力として受け入れます。符号付き4バイト整数を符号なし4バイト整数にバイナリで強制変換するように、またはその逆のように見えます。少なくとも心に留めておく価値があります。
これらは、奇妙に働きます:
test=# SELECT '-1519044407'::oid, '-1519044407'::int::oid;
oid | oid
------------+------------
2775922889 | 2775922889
int
とbigint
にキャストすると、異なる表現になります。
test=# SELECT (oid '2775922889')::int
test-# , (oid '2775922889')::bigint;
int4 | int8
-------------+------------
-1519044407 | 2775922889 -- !!
先頭のプラス記号またはマイナス記号は、実際には定数の一部とは見なされないことに注意してください。これは定数に適用される演算子です。
キャスト演算子::
優先されます 単項マイナス演算子(-
)よりも優先されます。
これまでにシステムカタログでその範囲のOID番号を見たことがなく、あらゆる種類の大きなデータベースで作業してきました。DB(クラスター)に問題があります。
DanielVéritéからのコメントで改善:
いずれかOIDの数値をめちゃくちゃな速度で燃やしています-すでに28億の数値OIDラップアラウンドまで、約15億が残ります。 WITH OIDS
で作成されたテーブルはありますか? (これ以上誰もすべきではありません。この機能は非推奨で、 Postgres 12で削除 です。)または、新しいオブジェクトを過剰に作成/削除するコードがありますか? OIDカウンターはインスタンスごとであり、データベースごとではないため、すべてのデータベースがOID消費に貢献しています。
OIDの衝突がラップアラウンド後にどのように処理されるかについて、 GetNewOidWithIndex
のソースコードにコメントがあります。衝突により、パフォーマンスが若干低下します。
または誰か/何かがシステムカタログをめちゃくちゃにしました。
上記のクエリがpgAdmin4によって生成された場合、重大なバグがあります。
システムカタログでその範囲のOIDがまだ誰もいないので、それはまだ浮上しなかったのでしょうか?
OIDのinteger表現で動作し、クエリで誤って符号を含む数値リテラルとして単純に貼り付けているようです。 stringリテラルが機能します:'-1519044407'::oid
。または、括弧を使用すると機能します:(-1519044407)::oid
。
しかし、これはnotを行います:
-1519044407::oid
理由:
1519044407
は数値リテラルとして解釈され、最初はinteger
に強制変換されます。::
は、符号演算子-
よりも優先され、整数は(間違った!!)oid
にキャストされます。ERROR: operator does not exist: - oid at character 125
そこで失敗しないと、重大なナンセンスが発生する可能性があります。
db <> fiddle ここ
pgadmin-hackersリストへのメモ を投稿しました。
A 関連するバグがそこに記録される前 も。 (Postgresコミュニティアカウントを使用してアクセスします。)32ビットバージョンのOIDに誤ったデータ型を使用しているpsycopg2の問題が原因でした。psycopg2バージョン2.8.4で修正する必要があります(pgAdmin4が依存します)。
この問題はすでに記録されています@ https://redmine.postgresql.org/projects/pgadmin4 。この問題はpsycopg2ライブラリで発生し、報告されています。