vendredi 30 janvier 2015

PostgreSQL Primary key disappears from test table


I have a somewhat convoluted scenario where a test table I had created with a primary key won't return the primary key. pgAdmin III reports there are no constraints. I have the entire PostgreSQL query log and below have the query I used to create the test table. I then dropped the primary key on a different test table and used the query generated (it's not a query I have manually run, yet) to help me search for pgAdmin III dropping the primary key on the table in question and found nothing searching for:



ALTER TABLE public.delete_key_bigserial DROP CONSTRAINT


The string 'DROP CONSTRAINT' only appears once in the query log dating back to 2014-12-02 which is weeks before I even created the test tables. I now understand that a primary key may or may not be set to bigserial or serial and have even created a table without a primary key set id to integer and then set id to be the primary key (another can of worms for whole 'nother day).


In an earlier question I inquired about how to fetch the data_type including if it was bigserial or serial to which Erwin Brandstetter had an excellent answer. He provided two queries in particular, one to fetch the data_types for all the columns and one to fetch the data_type for the primary key. Unfortunately one of the test tables I have been testing with isn't returning any results.



SELECT a.attrelid::regclass::text, a.attname,
CASE a.atttypid
WHEN 'int'::regtype THEN 'serial'
WHEN 'int8'::regtype THEN 'bigserial'
WHEN 'int2'::regtype THEN 'smallserial'
END AS serial_type
FROM pg_attribute a
JOIN pg_constraint c ON c.conrelid = a.attrelid AND c.conkey[1] = a.attnum
JOIN pg_attrdef ad ON ad.adrelid = a.attrelid
AND ad.adnum = a.attnum
WHERE a.attrelid = 'delete_key_bigserial'::regclass
AND a.attnum > 0
AND NOT a.attisdropped
AND a.atttypid = ANY('{int,int8,int2}'::regtype[]) -- integer type
AND c.contype = 'p' -- PK
AND array_length(c.conkey, 1) = 1 -- single column
AND ad.adsrc = 'nextval('''
|| (pg_get_serial_sequence (a.attrelid::regclass::text, a.attname))::regclass
|| '''::regclass)';


The query works perfect on all the other tables.


I've only been working with PostgreSQL since November 2014 and MySQL since circa 2011 so the best thing I can do AFAIK is to fetch as much relevant data as I can. Here is the query used to create the delete_key_bigserial table from the query log:



CREATE TABLE public.delete_key_bigserial (id bigserial PRIMARY KEY NOT NULL)
WITH (OIDS = FALSE);


I simplified Erwin's query and used it on the table to compare the results in my query tool to different test tables that the query works perfectly fine on (on all four data_types):



SELECT * FROM pg_attribute a
WHERE a.attrelid = 'delete_key_bigserial'::regclass
AND a.attnum > 0
AND NOT a.attisdropped
AND attname='id'
ORDER BY a.attnum;

+----------+---------+----------+---------------+--------+--------+----------+-------------+
| attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff |
+----------+---------+----------+---------------+--------+--------+----------+-------------+
| 46390 | id | 20 | -1 | 8 | 20 | 0 | -1 |
+----------+---------+----------+---------------+--------+--------+----------+-------------+

+-----------+----------+------------+----------+------------+-----------+--------------+
| atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attisdropped |
+-----------+----------+------------+----------+------------+-----------+--------------+
| -1 | f | p | d | t | t | f |
+-----------+----------+------------+----------+------------+-----------+--------------+

+------------+-------------+--------------+--------+------------+---------------+
| attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions |
+------------+-------------+--------------+--------+------------+---------------+
| t | 0 | | | | |
+------------+-------------+--------------+--------+------------+---------------+


Erwin is deriving the type via the atttypid column when other conditions are met however the resulting column/row is identical to other tables that work. There is another catalog table I've used in my attempts to determine what the data_type of the primary key is so I decided to compare the results from that table as well via the following query:



SELECT * FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_name='delete_key_bigserial'
AND is_nullable='NO';


The only difference for any returned column/row returned (besides the table name in the table_name and column_default columns) was the dtd_identifier column. The table delete_key_bigserial returns the column dtd_identifier with the value 20, for a working table the query returns 1. The (bottom of the) PostgreSQL element_types documentation describes the column as:



An identifier of the data type descriptor of the element. This is currently not useful.



I am guessing this is a deprecated/older fashion that is kept for legacy purposes though it could simply refer to the description itself? I'm not sure but this is where I am and I'm not even certain I'm on the right path.


I'd rather deal with the issue and learn from the scenario then disregard it simply because it's a test table as one day I'm certain I'll have to deal with this issue when it's not a test table. I'll be happy to update my question with relevant information that may help track down what the issue is.





Aucun commentaire:

Enregistrer un commentaire