2013-07-08 17 views
5

Quello che sto cercando di fare è di generare un errore fuori intervallo in caso di date al di fuori dell'intervallo supportato come ciò che fa il typecasting.Errore di aumento quando la data non è valida

Sto usando PostgreSQL-9.1.6 su CentOS. La questione è al di sotto ...

postgres=# select to_date('20130229','yyyymmdd'); 
    to_date 
------------ 
2013-03-01 
(1 row) 

Ma l'uscita che voglio vedere è:

postgres=# select '20130229'::date; 
ERROR: date/time field value out of range: "20130229" 

Navigare sul web ho trovato an informative page. Così ho fatto aggiungendo IS_VALID_JULIAN al corpo della funzione di to_date, aggiungendo le quattro linee segnato + qui sotto per formatting.c:

Datum 
to_date(PG_FUNCTION_ARGS) 
{ 
    text  *date_txt = PG_GETARG_TEXT_P(0); 
    text  *fmt = PG_GETARG_TEXT_P(1); 
    DateADT   result; 
    struct pg_tm tm; 
    fsec_t   fsec; 

    do_to_timestamp(date_txt, fmt, &tm, &fsec); 

+  if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) 
+  ereport(ERROR, 
+    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), 
+    errmsg("date out of range: \"%s\"",text_to_cstring(date_txt)))); 

    result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; 

    PG_RETURN_DATEADT(result); 
} 

Poi ho ricostruito PostgreSQL:

pg_ctl -m fast stop      # 1. stopping pgsql 
vi src/backend/utils/adt/formatting.c  # 2. using the version above 
rm -rf /usr/local/pgsql/*     # 3. getting rid of all bin files 
./configure --prefix=/usr/local/pgsql 
    --enable-nls --with-perl --with-libxml 
    --with-pam --with-openssl 
make && make install      # 4. rebuilding source  
pg_ctl start        # 5. starting the engine 

mie info directory bin è sotto.

[/home/postgres]echo $PATH 
/usr/lib64/qt-3.3/bin: 
/usr/local/bin: 
/bin: 
/usr/bin: 
/usr/local/sbin: 
/usr/sbin: 
/sbin: 
/home/postgres/bin: 
/usr/bin: 
/usr/local/pgsql/bin: 
/usr/local/pgpool/bin: 
/usr/local/pgtop/bin/pg_top: 

[/home/postgres]which pg_ctl 
/usr/local/pgsql/bin/pg_ctl 

[/home/postgres]which postgres 
/usr/local/pgsql/bin/postgres 

[/usr/local/bin]which psql 
/usr/local/pgsql/bin/psql 

Ma al momento del check to_date ancora una volta, il risultato è rimasto lo stesso.

postgres=# select to_date('20130229','yyyymmdd'); 
    to_date 
------------ 
2013-03-01 
(1 row) 

C'è qualcosa che mi è sfuggito?

+0

Ad una ipotesi, il server che stai utilizzando non è lo stesso del file binario che hai avviato. –

+0

L'approccio non ha nulla di sbagliato, vero? – KIM

+0

Er ... se si collega il codice e lo si compila, è necessario eseguire i binari che sono stati compilati. L'esecuzione di un altro binario non correlato non funzionerà. –

risposta

1

È possibile scrivere la propria funzione to_date(), ma è necessario chiamarla con il nome qualificato dello schema. (Io ho usato lo schema "pubblico", ma non c'è niente di speciale in questo.)

create or replace function public.to_date(any_date text, format_string text) 
returns date as 
$$ 
select to_date((any_date::date)::text, format_string); 
$$ 
language sql 

Utilizzando il nome della funzione nuda si esegue la funzione TO_DATE nativo().

select to_date('20130229', 'yyyymmdd'); 
2013-03-01 

Utilizzando il nome dello schema qualificato esegue la funzione definita dall'utente.

select public.to_date('20130229', 'yyyymmdd'); 
ERROR: date/time field value out of range: "20130229" 
SQL state: 22008 

So che non è proprio quello che stai cercando. Ma . . .

  • E 'più semplice di ricostruzione PostgreSQL dalla fonte.
  • La riparazione del codice sorgente SQL e PLPGSQL esistente è una semplice ricerca e sostituzione con un editor di streaming. Sono abbastanza sicuro che non si possa sbagliare, a patto che davvero voglia ogni utilizzo del to_date() nativo per essere public.to_date().
  • La funzione nativa di to_date() funzionerà come previsto. Le estensioni e altri codici potrebbero fare affidamento sul suo comportamento piuttosto particolare. Pensaci bene e molto prima di cambiare il comportamento delle funzioni native.

Nuovo SQL e PLPGSQL dovrebbero essere rivisti, tuttavia. Non mi aspetto che gli sviluppatori ricordino di scrivere public.to_date() ogni volta. Se si utilizza il controllo della versione, è possibile scrivere un hook precommit per assicurarsi che venga utilizzato solo public.to_date().

La funzione nativa di to_date() ha un comportamento che non vedo documentato. Non solo puoi chiamarlo con il 29 febbraio, puoi chiamarlo con il 345 febbraio o il 9999 febbraio.

select to_date('201302345', 'yyyymmdd'); 
2014-01-11 

select to_date('2013029999', 'yyyymmdd'); 
2040-06-17 
Problemi correlati