Postgresql

由於缺少 oid 運算符,無法從 pgAdmin4 中的表中輸出數據

  • November 11, 2019

我目前正在本地執行 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 伺服器以某種方式損壞?

以前從未見過OID。這是一流的“犯罪現場”!

... attrelid=-1519044407::oid ...
... rel.oid = -1519044407::oid ...

事實

0.

2^32 - 1519044407 = 2775922889

我們已經驗證 OID2775922889確實存在於您的數據庫中。測試:

SELECT * FROM pg_class WHERE oid = 2775922889;
SELECT * FROM pg_class WHERE oid = '-1519044407';
SELECT * FROM pg_class WHERE relname = 'test_table';

1.

關於對象標識符類型的手冊:

oid類型目前實現為無符號四字節整數。

2.

Postgres cast 無論如何都接受有符號整數(!)

字元串文字的 Postgres I/O 轉換以及integer目前的轉換(第 12 頁)無論如何都接受負整數值/文字作為輸入。似乎只是二進制將有符號的四字節整數強制轉換為無符號的四字節整數,反之亦然。至少值得記住。

奇怪的是,這些工作:

test=# SELECT '-1519044407'::oid, '-1519044407'::int::oid;
   oid     |    oid     
------------+------------
2775922889 | 2775922889

轉換為intvs時導致不同的表示bigint

test=# SELECT (oid '2775922889')::int
test-#      , (oid '2775922889')::bigint;
   int4     |    int8    
-------------+------------
-1519044407 | 2775922889  -- !!

3.

數值常數手冊

請注意,任何前導加號或減號實際上都不被視為常數的一部分;它是應用於常量的運算符。

4.

強制轉換運算符:: 優先於一元減號運算符 ( -)。

結論

1.

我以前從未在系統目錄中看到過該範圍內的 OID 編號,並且我一直在使用各種大型數據庫。您的數據庫(集群)有問題。

Daniel Vérité 的評論改進了:

要麼你正在以瘋狂的速度燒掉 OID 號碼——已經有 28 億個號碼。在 OID 環繞之前,還有約 15 億個。你有任何用創建的表WITH OIDS嗎?(沒有人應該再這樣做了。該功能在 Postgres 12中已被棄用和刪除。)或者一些程式碼過度創建/刪除新對象?OID 計數器是按實例計算的,而不是按數據庫計算的,因此所有 db 都會消耗 OID。原始碼中

有一條關於如何在環繞後處理 OID 衝突的註釋。碰撞會導致輕微的性能損失。GetNewOidWithIndex

或者有人/某事弄亂了您的系統目錄。

2.

如果上述查詢是由 pgAdmin4 生成的,則存在嚴重的錯誤

也許這還沒有浮出水面,因為在系統目錄中沒有人在那個範圍內有 OID,但是?

似乎它使用 OID 的整數表示進行操作,並且天真地將它們粘貼為數字文字,包括在查詢中錯誤的符號。字元串文字可以工作:'-1519044407'::oid. 或者括號會使其工作:(-1519044407)::oid.

但這不是

-1519044407::oid 

因為:

    1. 1519044407被視為數字文字,最初被強制轉換為integer.
    1. 強制轉換運算符::優先於符號運算符-,並且整數被強制轉換為 (wrong!!) oid
    1. 最後,Postgres 嘗試應用符號運算符,幸運的是,失敗並報告了錯誤消息:
ERROR:  operator does not exist: - oid at character 125

如果它不會在那裡失敗,可能會發生嚴重的廢話。

db<>在這裡擺弄

我已經在 pgadmin-hackers list 上發布了一條註釋之前也記錄了

一個相關的錯誤。(使用 Postgres 社區帳戶訪問。)它被追溯到一個 psycopg2 問題,在 32 位版本中使用了錯誤的 OID 數據類型。應該在 psycopg2 版本 2.8.4(pgAdmin4 依賴)中修復。

引用自:https://dba.stackexchange.com/questions/247119