web-dev-qa-db-fra.com

Impossible de sortir les données des tables dans pgAdmin4 en raison de l'opérateur oid manquant

J'utilise actuellement Postgresql 10.6 localement avec lequel j'interfère avec PgAdmin 4.12, jusqu'à aujourd'hui tout fonctionnait bien. Cependant, aujourd'hui, j'ai exécuté la requête suivante dans l'éditeur de requête pgAdmin:

SELECT * FROM test_table LIMIT 100

et a obtenu l'erreur suivante:

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[])

La chose étrange est que lorsque j'exécute la même commande sur des tables qui ont été créées hier, les données sont sorties avec succès dans la fenêtre de sortie des données Pgadmin. J'ai également essayé d'exécuter la même commande avec psql:

psql -U postgres -d geodata -c 'SELECT * FROM test_table LIMIT 100'

qui a également réussi. Je suis capable de créer des tableaux dans Pgadmin mais pas de les sortir directement. Toute nouvelle table que je crée puis que la sortie se termine avec l'erreur la plus élevée, la seule différence réside dans les changements d'oid. J'ai désinstallé Pgadmin et je me suis assuré de supprimer tous les dossiers restants et de réinstaller sans changement.

Quelqu'un a-t-il une idée du problème? Le problème vient-il de pgadmin ou mon serveur Postgresql est-il corrompu d'une manière ou d'une autre?

5
Trashmonk

Jamais vu un négatif OID avant. C'est une "scène de crime" de première classe!

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

Faits

0.

2^32 - 1519044407 = 2775922889

Et nous avons vérifié que OID 2775922889 existe en effet dans votre base de données. Tests:

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

1.

Le manuel sur les types d'identifiant d'objet:

Le type oid est actuellement implémenté comme un entier non signé sur quatre octets.

2.

La distribution Postgres accepte quand même signé entier (!)

La conversion d'E/S Postgres à partir de littéraux de chaîne, ainsi que le transtypage de integercurrently (p. 12) accepte de toute façon des valeurs entières négatives/littéraux. Semble juste binaire contraindre un entier signé de quatre octets à entier non signé de quatre octets et vice versa. Cela vaut la peine de garder à l'esprit au moins.

Celles-ci, étrangement, fonctionnent:

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

Conduit à une représentation différente lors de la conversion en int et bigint:

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

3.

Le manuel sur Constantes numériques :

Notez que tout signe positif plus ou moins n'est pas réellement considéré comme faisant partie de la constante; c'est un opérateur appliqué à la constante.

4.

L'opérateur de transtypage ::a priorité sur l'opérateur unaire moins (-).

Conclusions

1.

Je n'ai jamais vu OID numéros de cette plage dans les catalogues système auparavant, et j'ai travaillé avec toutes sortes de grosses bases de données. Vous avez un problème dans votre DB (cluster).

Amélioré avec les commentaires de Daniel Vérité:

Soit vous gravez OID numéros à un rythme insensé - déjà 2,8 milliards de chiffres. ~ 1,5 milliard restent jusqu'à OID wraparound . Avez-vous des tables créées avec WITH OIDS? (Personne ne devrait plus. La fonctionnalité est déconseillée et supprimée dans Postgres 12 .) Ou du code créant/supprimant excessivement de nouveaux objets? Le compteur OID est par instance, pas par base de données, donc tous les dbs contribuent à la consommation de OID.
Il y a commentaire dans le code source de GetNewOidWithIndex pour savoir comment OID les collisions sont traitées après le bouclage. Les collisions entraînent un mineur pénalité de performance.

Ou quelqu'un/quelque chose a sali vos catalogues système.

2.

Si la requête ci-dessus a été générée par pgAdmin4, il y a un bug sérieux .

Peut-être que cela n'a pas encore fait surface, car personne n'avait encore d'OID dans cette plage dans les catalogues système?

On dirait qu'il fonctionne avec la représentation entier des OID, et les colle naïvement comme des littéraux numériques incluant le signe par erreur dans les requêtes. Un chaîne littéral fonctionnerait: '-1519044407'::oid. Ou les parenthèses le feraient fonctionner: (-1519044407)::oid.

Mais cela ne pas :

-1519044407::oid 

Parce que:

    1. 1519044407 est considéré comme un littéral numérique et initialement contraint à integer.
    1. L'opérateur de transtypage :: a priorité sur l'opérateur de signe - et l'entier est converti en (faux !!) oid.
    1. Enfin, Postgres essaie d'appliquer l'opérateur de signe et, heureusement, échoue avec le message d'erreur signalé:
    ERROR:  operator does not exist: - oid at character 125
    

    S'il n'y échouait pas, de graves bêtises pourraient se produire.

db <> violon ici

J'ai posté un note à la liste des pgadmin-hackers .
A n bogue connexe a déjà été enregistré auparavant , aussi. (Accès avec le compte de la communauté Postgres.) Il a été retracé à un problème psycopg2 en utilisant le mauvais type de données pour OID dans les versions 32 bits. Devrait être corrigé dans psycopg2 version 2.8.4 (dont dépend pgAdmin4).

5
Erwin Brandstetter

Ce problème est déjà enregistré @ https://redmine.postgresql.org/projects/pgadmin4 . Ce problème est introduit dans la bibliothèque psycopg2 et il a été signalé.

2
Khushboo Vashi