2012-08-05 8 views
5

Si è verificato un problema durante l'inserimento del valore 32767 in una colonna smallint in Postgres, che avrebbe restituito l'errore smallint nell'intervallo. Questo era strano perché potevo fare:PostgreSQL: overflow minimo durante la creazione dell'indice su più colonne. è un insetto?

SELECT 32767::int2; 

Quale funzionerebbe bene. Dopo aver tirato un po 'di capelli, ho finalmente rintracciato questo in un indice sulla colonna in questione. In primo luogo, ecco lo schema (Beh, non proprio, ma ho semplificato questo fino a un caso repro):

CREATE TABLE Test 
(
    id uuid NOT NULL, 
    cooktime smallint, 
    preptime smallint, 
    CONSTRAINT test_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

ora creare il seguente indice:

CREATE INDEX idx_test_totaltime 
    ON Test 
    USING btree 
    ((cooktime + preptime)); 

Avanti, cerco di creare la seguente riga:

INSERT INTO Test (CookTime, PrepTime, Id) 
VALUES (
    (32767)::int2, 
    (10)::int2, 
    (E'fd47dc1e-c3c6-42c1-b058-689e926a72a4')::uuid 
); 

ottengo l'errore:

ERROR: smallint out of range SQL state: 22003

Sembra che idx_test_totaltime si aspetti un valore massimo di int2, anche se l'indice viene applicato sulla somma di due piccoli valori.

Si tratta di un bug Postgres o mi manca qualcosa di semplice? C'è un modo per ovviare a questa limitazione oppure dovrei rendere queste colonne int4 e utilizzare un vincolo CHECK per limitare ogni valore a 32767? Sto usando Postgres 9.0.0 (Sì, ho bisogno di aggiornamento!), Ma ho creato un SQL Fiddle che dimostra questo errore su 9.1.4.

risposta

4

tuo problema è che è un altro int2 + int2int2 quindi l'espressione nell'indice, (cooktime + preptime), trabocca per (32767, 10). È possibile aggirare questo problema con un po 'di fusione nella espressione di indice:

CREATE INDEX idx_test_totaltime 
    ON Test 
    USING btree 
    ((cooktime::int4 + preptime::int4)); 

è necessario solo uno dei calchi, ma utilizzando sia non fa male.

+0

Che funziona. Tuttavia, ho notato che se esegui 'SELECT * FROM Test WHERE CookTime + PrepTime> 100', non userà l'indice. Devi invece specificare 'WHERE CookTime :: Int4 + PrepTime :: Int4> 100'. Ora devo aggiornare il mio codice di ricerca :) –

+1

@MikeChristensen: Questo è un buon punto sull'indice che non si abitua. Consiglierei di dimenticare tutto il business di 'int2' e di usare' int' per la colonna con i vincoli CHECK appropriati. –

+1

Lancia il risultato del calcolo a INT2, non le colonne nell'indice. –

3

Perché non si utilizza uno INTERVAL per un intervallo di tempo? È una soluzione perfetta per il tuo problema.

+0

Probabilmente è un'ottima soluzione. Fare questo cambiamento ora potrebbe essere un po 'disordinato, ma potrei fare qualche esperimento per vedere cosa sarebbe coinvolto. Tuttavia, la soluzione di Mu funziona perfettamente bene e mi ha richiesto di aggiornare il codice minimo. –

Problemi correlati