8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.142 2008/07/07 18:09:46 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.143 2008/10/14 17:12:33 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
38
38
#endif
39
39
40
40
41
+ static void EncodeSpecialDate (DateADT dt , char * str );
41
42
static int time2tm (TimeADT time , struct pg_tm * tm , fsec_t * fsec );
42
43
static int timetz2tm (TimeTzADT * time , struct pg_tm * tm , fsec_t * fsec , int * tzp );
43
44
static int tm2time (struct pg_tm * tm , fsec_t fsec , TimeADT * result );
@@ -147,6 +148,14 @@ date_in(PG_FUNCTION_ARGS)
147
148
GetEpochTime (tm );
148
149
break ;
149
150
151
+ case DTK_LATE :
152
+ DATE_NOEND (date );
153
+ PG_RETURN_DATEADT (date );
154
+
155
+ case DTK_EARLY :
156
+ DATE_NOBEGIN (date );
157
+ PG_RETURN_DATEADT (date );
158
+
150
159
default :
151
160
DateTimeParseError (DTERR_BAD_FORMAT , str , "date" );
152
161
break ;
@@ -174,10 +183,14 @@ date_out(PG_FUNCTION_ARGS)
174
183
* tm = & tt ;
175
184
char buf [MAXDATELEN + 1 ];
176
185
177
- j2date (date + POSTGRES_EPOCH_JDATE ,
178
- & (tm -> tm_year ), & (tm -> tm_mon ), & (tm -> tm_mday ));
179
-
180
- EncodeDateOnly (tm , DateStyle , buf );
186
+ if (DATE_NOT_FINITE (date ))
187
+ EncodeSpecialDate (date , buf );
188
+ else
189
+ {
190
+ j2date (date + POSTGRES_EPOCH_JDATE ,
191
+ & (tm -> tm_year ), & (tm -> tm_mon ), & (tm -> tm_mday ));
192
+ EncodeDateOnly (tm , DateStyle , buf );
193
+ }
181
194
182
195
result = pstrdup (buf );
183
196
PG_RETURN_CSTRING (result );
@@ -208,6 +221,20 @@ date_send(PG_FUNCTION_ARGS)
208
221
PG_RETURN_BYTEA_P (pq_endtypsend (& buf ));
209
222
}
210
223
224
+ /*
225
+ * Convert reserved date values to string.
226
+ */
227
+ static void
228
+ EncodeSpecialDate (DateADT dt , char * str )
229
+ {
230
+ if (DATE_IS_NOBEGIN (dt ))
231
+ strcpy (str , EARLY );
232
+ else if (DATE_IS_NOEND (dt ))
233
+ strcpy (str , LATE );
234
+ else /* shouldn't happen */
235
+ elog (ERROR , "invalid argument for EncodeSpecialDate" );
236
+ }
237
+
211
238
212
239
/*
213
240
* Comparison functions for dates
@@ -280,6 +307,14 @@ date_cmp(PG_FUNCTION_ARGS)
280
307
PG_RETURN_INT32 (0 );
281
308
}
282
309
310
+ Datum
311
+ date_finite (PG_FUNCTION_ARGS )
312
+ {
313
+ DateADT date = PG_GETARG_DATEADT (0 );
314
+
315
+ PG_RETURN_BOOL (!DATE_NOT_FINITE (date ));
316
+ }
317
+
283
318
Datum
284
319
date_larger (PG_FUNCTION_ARGS )
285
320
{
@@ -306,6 +341,11 @@ date_mi(PG_FUNCTION_ARGS)
306
341
DateADT dateVal1 = PG_GETARG_DATEADT (0 );
307
342
DateADT dateVal2 = PG_GETARG_DATEADT (1 );
308
343
344
+ if (DATE_NOT_FINITE (dateVal1 ) || DATE_NOT_FINITE (dateVal2 ))
345
+ ereport (ERROR ,
346
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
347
+ errmsg ("cannot subtract infinite dates" )));
348
+
309
349
PG_RETURN_INT32 ((int32 ) (dateVal1 - dateVal2 ));
310
350
}
311
351
@@ -318,6 +358,9 @@ date_pli(PG_FUNCTION_ARGS)
318
358
DateADT dateVal = PG_GETARG_DATEADT (0 );
319
359
int32 days = PG_GETARG_INT32 (1 );
320
360
361
+ if (DATE_NOT_FINITE (dateVal ))
362
+ days = 0 ; /* can't change infinity */
363
+
321
364
PG_RETURN_DATEADT (dateVal + days );
322
365
}
323
366
@@ -329,6 +372,9 @@ date_mii(PG_FUNCTION_ARGS)
329
372
DateADT dateVal = PG_GETARG_DATEADT (0 );
330
373
int32 days = PG_GETARG_INT32 (1 );
331
374
375
+ if (DATE_NOT_FINITE (dateVal ))
376
+ days = 0 ; /* can't change infinity */
377
+
332
378
PG_RETURN_DATEADT (dateVal - days );
333
379
}
334
380
@@ -342,18 +388,25 @@ date2timestamp(DateADT dateVal)
342
388
{
343
389
Timestamp result ;
344
390
391
+ if (DATE_IS_NOBEGIN (dateVal ))
392
+ TIMESTAMP_NOBEGIN (result );
393
+ else if (DATE_IS_NOEND (dateVal ))
394
+ TIMESTAMP_NOEND (result );
395
+ else
396
+ {
345
397
#ifdef HAVE_INT64_TIMESTAMP
346
- /* date is days since 2000, timestamp is microseconds since same... */
347
- result = dateVal * USECS_PER_DAY ;
348
- /* Date's range is wider than timestamp's, so must check for overflow */
349
- if (result / USECS_PER_DAY != dateVal )
350
- ereport (ERROR ,
351
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
352
- errmsg ("date out of range for timestamp" )));
398
+ /* date is days since 2000, timestamp is microseconds since same... */
399
+ result = dateVal * USECS_PER_DAY ;
400
+ /* Date's range is wider than timestamp's, so check for overflow */
401
+ if (result / USECS_PER_DAY != dateVal )
402
+ ereport (ERROR ,
403
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
404
+ errmsg ("date out of range for timestamp" )));
353
405
#else
354
- /* date is days since 2000, timestamp is seconds since same... */
355
- result = dateVal * (double ) SECS_PER_DAY ;
406
+ /* date is days since 2000, timestamp is seconds since same... */
407
+ result = dateVal * (double ) SECS_PER_DAY ;
356
408
#endif
409
+ }
357
410
358
411
return result ;
359
412
}
@@ -366,24 +419,30 @@ date2timestamptz(DateADT dateVal)
366
419
* tm = & tt ;
367
420
int tz ;
368
421
369
- j2date (dateVal + POSTGRES_EPOCH_JDATE ,
370
- & (tm -> tm_year ), & (tm -> tm_mon ), & (tm -> tm_mday ));
371
-
372
- tm -> tm_hour = 0 ;
373
- tm -> tm_min = 0 ;
374
- tm -> tm_sec = 0 ;
375
- tz = DetermineTimeZoneOffset (tm , session_timezone );
422
+ if (DATE_IS_NOBEGIN (dateVal ))
423
+ TIMESTAMP_NOBEGIN (result );
424
+ else if (DATE_IS_NOEND (dateVal ))
425
+ TIMESTAMP_NOEND (result );
426
+ else
427
+ {
428
+ j2date (dateVal + POSTGRES_EPOCH_JDATE ,
429
+ & (tm -> tm_year ), & (tm -> tm_mon ), & (tm -> tm_mday ));
430
+ tm -> tm_hour = 0 ;
431
+ tm -> tm_min = 0 ;
432
+ tm -> tm_sec = 0 ;
433
+ tz = DetermineTimeZoneOffset (tm , session_timezone );
376
434
377
435
#ifdef HAVE_INT64_TIMESTAMP
378
- result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC ;
379
- /* Date's range is wider than timestamp's, so must check for overflow */
380
- if ((result - tz * USECS_PER_SEC ) / USECS_PER_DAY != dateVal )
381
- ereport (ERROR ,
382
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
383
- errmsg ("date out of range for timestamp" )));
436
+ result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC ;
437
+ /* Date's range is wider than timestamp's, so check for overflow */
438
+ if ((result - tz * USECS_PER_SEC ) / USECS_PER_DAY != dateVal )
439
+ ereport (ERROR ,
440
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
441
+ errmsg ("date out of range for timestamp" )));
384
442
#else
385
- result = dateVal * (double ) SECS_PER_DAY + tz ;
443
+ result = dateVal * (double ) SECS_PER_DAY + tz ;
386
444
#endif
445
+ }
387
446
388
447
return result ;
389
448
}
@@ -797,15 +856,19 @@ timestamp_date(PG_FUNCTION_ARGS)
797
856
* tm = & tt ;
798
857
fsec_t fsec ;
799
858
800
- if (TIMESTAMP_NOT_FINITE (timestamp ))
801
- PG_RETURN_NULL ();
802
-
803
- if (timestamp2tm (timestamp , NULL , tm , & fsec , NULL , NULL ) != 0 )
804
- ereport (ERROR ,
805
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
806
- errmsg ("timestamp out of range" )));
859
+ if (TIMESTAMP_IS_NOBEGIN (timestamp ))
860
+ DATE_NOBEGIN (result );
861
+ else if (TIMESTAMP_IS_NOEND (timestamp ))
862
+ DATE_NOEND (result );
863
+ else
864
+ {
865
+ if (timestamp2tm (timestamp , NULL , tm , & fsec , NULL , NULL ) != 0 )
866
+ ereport (ERROR ,
867
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
868
+ errmsg ("timestamp out of range" )));
807
869
808
- result = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - POSTGRES_EPOCH_JDATE ;
870
+ result = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - POSTGRES_EPOCH_JDATE ;
871
+ }
809
872
810
873
PG_RETURN_DATEADT (result );
811
874
}
@@ -840,15 +903,19 @@ timestamptz_date(PG_FUNCTION_ARGS)
840
903
int tz ;
841
904
char * tzn ;
842
905
843
- if (TIMESTAMP_NOT_FINITE (timestamp ))
844
- PG_RETURN_NULL ();
845
-
846
- if (timestamp2tm (timestamp , & tz , tm , & fsec , & tzn , NULL ) != 0 )
847
- ereport (ERROR ,
848
- (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
849
- errmsg ("timestamp out of range" )));
906
+ if (TIMESTAMP_IS_NOBEGIN (timestamp ))
907
+ DATE_NOBEGIN (result );
908
+ else if (TIMESTAMP_IS_NOEND (timestamp ))
909
+ DATE_NOEND (result );
910
+ else
911
+ {
912
+ if (timestamp2tm (timestamp , & tz , tm , & fsec , & tzn , NULL ) != 0 )
913
+ ereport (ERROR ,
914
+ (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
915
+ errmsg ("timestamp out of range" )));
850
916
851
- result = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - POSTGRES_EPOCH_JDATE ;
917
+ result = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday ) - POSTGRES_EPOCH_JDATE ;
918
+ }
852
919
853
920
PG_RETURN_DATEADT (result );
854
921
}
@@ -869,16 +936,19 @@ abstime_date(PG_FUNCTION_ARGS)
869
936
switch (abstime )
870
937
{
871
938
case INVALID_ABSTIME :
872
- case NOSTART_ABSTIME :
873
- case NOEND_ABSTIME :
874
939
ereport (ERROR ,
875
940
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
876
941
errmsg ("cannot convert reserved abstime value to date" )));
942
+ result = 0 ; /* keep compiler quiet */
943
+ break ;
877
944
878
- /*
879
- * pretend to drop through to make compiler think that result will
880
- * be set
881
- */
945
+ case NOSTART_ABSTIME :
946
+ DATE_NOBEGIN (result );
947
+ break ;
948
+
949
+ case NOEND_ABSTIME :
950
+ DATE_NOEND (result );
951
+ break ;
882
952
883
953
default :
884
954
abstime2tm (abstime , & tz , tm , NULL );
@@ -1452,9 +1522,9 @@ datetime_timestamp(PG_FUNCTION_ARGS)
1452
1522
TimeADT time = PG_GETARG_TIMEADT (1 );
1453
1523
Timestamp result ;
1454
1524
1455
- result = DatumGetTimestamp ( DirectFunctionCall1 ( date_timestamp ,
1456
- DateADTGetDatum ( date )));
1457
- result += time ;
1525
+ result = date2timestamp ( date );
1526
+ if (! TIMESTAMP_NOT_FINITE ( result ))
1527
+ result += time ;
1458
1528
1459
1529
PG_RETURN_TIMESTAMP (result );
1460
1530
}
@@ -2304,11 +2374,18 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS)
2304
2374
TimeTzADT * time = PG_GETARG_TIMETZADT_P (1 );
2305
2375
TimestampTz result ;
2306
2376
2377
+ if (DATE_IS_NOBEGIN (date ))
2378
+ TIMESTAMP_NOBEGIN (result );
2379
+ else if (DATE_IS_NOEND (date ))
2380
+ TIMESTAMP_NOEND (result );
2381
+ else
2382
+ {
2307
2383
#ifdef HAVE_INT64_TIMESTAMP
2308
- result = date * USECS_PER_DAY + time -> time + time -> zone * USECS_PER_SEC ;
2384
+ result = date * USECS_PER_DAY + time -> time + time -> zone * USECS_PER_SEC ;
2309
2385
#else
2310
- result = date * (double ) SECS_PER_DAY + time -> time + time -> zone ;
2386
+ result = date * (double ) SECS_PER_DAY + time -> time + time -> zone ;
2311
2387
#endif
2388
+ }
2312
2389
2313
2390
PG_RETURN_TIMESTAMP (result );
2314
2391
}
0 commit comments