Newer
Older
/*-------------------------------------------------------------------------
*
* date.c
* implements DATE and TIME data types specified in SQL-92 standard
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.123 2006/02/09 03:39:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include "access/hash.h"
#include "libpq/pqformat.h"
#include "parser/scansup.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/nabstime.h"
#include "utils/timestamp.h"
/*
* gcc's -ffast-math switch breaks routines that expect exact results from
* expressions like timeval / SECS_PER_HOUR, where timeval is double.
*/
#ifdef __FAST_MATH__
#error -ffast-math is known to break this code
#endif
static int time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec);
static int timetz2tm(TimeTzADT *time, struct pg_tm * tm, fsec_t *fsec, int *tzp);
static int tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result);
static int tm2timetz(struct pg_tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
Thomas G. Lockhart
committed
/*****************************************************************************
* Date ADT
*****************************************************************************/
/* date_in()
* Given date text string, convert to internal date format.
Datum
date_in(PG_FUNCTION_ARGS)
char *str = PG_GETARG_CSTRING(0);
Thomas G. Lockhart
committed
fsec_t fsec;
Bruce Momjian
committed
*tm = &tt;
int tzp;
Bruce Momjian
committed
int dtype;
int dterr;
Bruce Momjian
committed
char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS];
char workbuf[MAXDATELEN + 1];
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp);
if (dterr != 0)
DateTimeParseError(dterr, str, "date");
switch (dtype)
{
case DTK_DATE:
break;
case DTK_CURRENT:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("date/time value \"current\" is no longer supported")));
break;
case DTK_EPOCH:
GetEpochTime(tm);
Bruce Momjian
committed
default:
DateTimeParseError(DTERR_BAD_FORMAT, str, "date");
break;
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\"", str)));
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
PG_RETURN_DATEADT(date);
}
/* date_out()
* Given internal format date, convert to text string.
Datum
date_out(PG_FUNCTION_ARGS)
Bruce Momjian
committed
char *result;
Bruce Momjian
committed
*tm = &tt;
char buf[MAXDATELEN + 1];
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
EncodeDateOnly(tm, DateStyle, buf);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
}
/*
* date_recv - converts external binary format to date
*/
Datum
date_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
PG_RETURN_DATEADT((DateADT) pq_getmsgint(buf, sizeof(DateADT)));
}
/*
* date_send - converts date to binary format
*/
Datum
date_send(PG_FUNCTION_ARGS)
{
StringInfoData buf;
pq_begintypsend(&buf);
pq_sendint(&buf, date, sizeof(date));
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
/*
* Comparison functions for dates
*/
Datum
date_eq(PG_FUNCTION_ARGS)
{
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 == dateVal2);
}
Datum
date_ne(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 != dateVal2);
Datum
date_lt(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 < dateVal2);
Datum
date_le(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 <= dateVal2);
}
Datum
date_gt(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 > dateVal2);
}
Datum
date_ge(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_BOOL(dateVal1 >= dateVal2);
}
Datum
date_cmp(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
if (dateVal1 < dateVal2)
PG_RETURN_INT32(-1);
else if (dateVal1 > dateVal2)
PG_RETURN_INT32(1);
PG_RETURN_INT32(0);
}
Datum
date_larger(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
}
Datum
date_smaller(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
}
/* Compute difference between two dates in days.
Datum
date_mi(PG_FUNCTION_ARGS)
DateADT dateVal1 = PG_GETARG_DATEADT(0);
DateADT dateVal2 = PG_GETARG_DATEADT(1);
PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
}
/* Add a number of days to a date, giving a new date.
* Must handle both positive and negative numbers of days.
Datum
date_pli(PG_FUNCTION_ARGS)
DateADT dateVal = PG_GETARG_DATEADT(0);
int32 days = PG_GETARG_INT32(1);
PG_RETURN_DATEADT(dateVal + days);
}
/* Subtract a number of days from a date, giving a new date.
Datum
date_mii(PG_FUNCTION_ARGS)
DateADT dateVal = PG_GETARG_DATEADT(0);
int32 days = PG_GETARG_INT32(1);
PG_RETURN_DATEADT(dateVal - days);
}
/*
* Internal routines for promoting date to timestamp and timestamp with
* time zone
Thomas G. Lockhart
committed
*/
#ifdef HAVE_INT64_TIMESTAMP
/* date is days since 2000, timestamp is microseconds since same... */
#define date2timestamp(dateVal) \
((Timestamp) ((dateVal) * USECS_PER_DAY))
#else
/* date is days since 2000, timestamp is seconds since same... */
#define date2timestamp(dateVal) \
((Timestamp) ((dateVal) * (double)SECS_PER_DAY))
#endif
static TimestampTz
date2timestamptz(DateADT dateVal)
{
TimestampTz result;
*tm = &tt;
j2date(dateVal + POSTGRES_EPOCH_JDATE,
&(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
tz = DetermineTimeZoneOffset(tm, global_timezone);
#ifdef HAVE_INT64_TIMESTAMP
result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
result = dateVal * (double) SECS_PER_DAY + tz;
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#endif
return result;
}
/*
* Crosstype comparison functions for dates
*/
Datum
date_eq_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
}
Datum
date_ne_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
}
Datum
date_lt_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
}
Datum
date_gt_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
}
Datum
date_le_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
}
Datum
date_ge_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
}
Datum
date_cmp_timestamp(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
Timestamp dt1;
dt1 = date2timestamp(dateVal);
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
}
Datum
date_eq_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
}
Datum
date_ne_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
}
Datum
date_lt_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
}
Datum
date_gt_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
}
Datum
date_le_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
}
Datum
date_ge_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
dt1 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
}
Datum
date_cmp_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
TimestampTz dt1;
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
dt1 = date2timestamptz(dateVal);
PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
}
Datum
timestamp_eq_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
}
Datum
timestamp_ne_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
}
Datum
timestamp_lt_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
}
Datum
timestamp_gt_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
}
Datum
timestamp_le_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
}
Datum
timestamp_ge_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
}
Datum
timestamp_cmp_date(PG_FUNCTION_ARGS)
{
Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
DateADT dateVal = PG_GETARG_DATEADT(1);
Timestamp dt2;
dt2 = date2timestamp(dateVal);
PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
}
Datum
timestamptz_eq_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) == 0);
}
Datum
timestamptz_ne_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) != 0);
}
Datum
timestamptz_lt_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) < 0);
}
Datum
timestamptz_gt_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) > 0);
}
Datum
timestamptz_le_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) <= 0);
}
Datum
timestamptz_ge_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_BOOL(timestamptz_cmp_internal(dt1, dt2) >= 0);
}
Datum
timestamptz_cmp_date(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(1);
dt2 = date2timestamptz(dateVal);
PG_RETURN_INT32(timestamptz_cmp_internal(dt1, dt2));
}
Thomas G. Lockhart
committed
/* Add an interval to a date, giving a new date.
* Must handle both positive and negative intervals.
*
* We implement this by promoting the date to timestamp (without time zone)
* and then using the timestamp plus interval function.
Thomas G. Lockhart
committed
*/
Datum
date_pl_interval(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
Timestamp dateStamp;
Thomas G. Lockhart
committed
dateStamp = date2timestamp(dateVal);
Thomas G. Lockhart
committed
return DirectFunctionCall2(timestamp_pl_interval,
TimestampGetDatum(dateStamp),
PointerGetDatum(span));
Thomas G. Lockhart
committed
}
/* Subtract an interval from a date, giving a new date.
* Must handle both positive and negative intervals.
*
* We implement this by promoting the date to timestamp (without time zone)
* and then using the timestamp minus interval function.
Thomas G. Lockhart
committed
*/
Datum
date_mi_interval(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
Interval *span = PG_GETARG_INTERVAL_P(1);
Timestamp dateStamp;
Thomas G. Lockhart
committed
dateStamp = date2timestamp(dateVal);
Thomas G. Lockhart
committed
return DirectFunctionCall2(timestamp_mi_interval,
TimestampGetDatum(dateStamp),
PointerGetDatum(span));
Thomas G. Lockhart
committed
}
/* date_timestamp()
* Convert date to timestamp data type.
Datum
date_timestamp(PG_FUNCTION_ARGS)
DateADT dateVal = PG_GETARG_DATEADT(0);
Timestamp result;
result = date2timestamp(dateVal);
PG_RETURN_TIMESTAMP(result);
}
/* timestamp_date()
* Convert timestamp to date data type.
*/
Datum
timestamp_date(PG_FUNCTION_ARGS)
{
Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
DateADT result;
*tm = &tt;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
PG_RETURN_DATEADT(result);
}
/* date_timestamptz()
* Convert date to timestamp with time zone data type.
*/
Datum
date_timestamptz(PG_FUNCTION_ARGS)
{
DateADT dateVal = PG_GETARG_DATEADT(0);
TimestampTz result;
result = date2timestamptz(dateVal);
PG_RETURN_TIMESTAMP(result);
}
/* timestamptz_date()
* Convert timestamp with time zone to date data type.
timestamptz_date(PG_FUNCTION_ARGS)
TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
DateADT result;
*tm = &tt;
Thomas G. Lockhart
committed
fsec_t fsec;
char *tzn;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) != 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
PG_RETURN_DATEADT(result);
}
/* abstime_date()
* Convert abstime to date data type.
Datum
abstime_date(PG_FUNCTION_ARGS)
AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
DateADT result;
*tm = &tt;
int tz;
switch (abstime)
{
case INVALID_ABSTIME:
case NOSTART_ABSTIME:
case NOEND_ABSTIME:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert reserved abstime value to date")));
* pretend to drop through to make compiler think that result will
* be set
*/
default:
abstime2tm(abstime, &tz, tm, NULL);
result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
break;
}
PG_RETURN_DATEADT(result);
}
/* date_text()
* Convert date to text data type.
*/
Datum
date_text(PG_FUNCTION_ARGS)
{
/* Input is a Date, but may as well leave it in Datum form */
text *result;
char *str;
int len;
str = DatumGetCString(DirectFunctionCall1(date_out, date));
len = strlen(str) + VARHDRSZ;
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
result = palloc(len);
VARATT_SIZEP(result) = len;
memmove(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
PG_RETURN_TEXT_P(result);
}
/* text_date()
* Convert text string to date.
* Text type is not null terminated, so use temporary string
* then call the standard input routine.
*/
Datum
text_date(PG_FUNCTION_ARGS)
{
text *str = PG_GETARG_TEXT_P(0);
int i;
char *sp,
*dp,
dstr[MAXDATELEN + 1];
if (VARSIZE(str) - VARHDRSZ > MAXDATELEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
Peter Eisentraut
committed
errmsg("invalid input syntax for type date: \"%s\"",
sp = VARDATA(str);
dp = dstr;
for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
*dp++ = *sp++;
*dp = '\0';
return DirectFunctionCall1(date_in,
CStringGetDatum(dstr));
}
/*****************************************************************************
* Time ADT
*****************************************************************************/
Datum
time_in(PG_FUNCTION_ARGS)
char *str = PG_GETARG_CSTRING(0);
Thomas G. Lockhart
committed
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
TimeADT result;
Thomas G. Lockhart
committed
fsec_t fsec;
*tm = &tt;
int tz;
int nf;
int dterr;
char workbuf[MAXDATELEN + 1];
char *field[MAXDATEFIELDS];
int dtype;
int ftype[MAXDATEFIELDS];
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
dterr = DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, &tz);
if (dterr != 0)
DateTimeParseError(dterr, str, "time");
Thomas G. Lockhart
committed
tm2time(tm, fsec, &result);
Thomas G. Lockhart
committed
AdjustTimeForTypmod(&result, typmod);
Thomas G. Lockhart
committed
PG_RETURN_TIMEADT(result);
Thomas G. Lockhart
committed
/* tm2time()
* Convert a tm structure to a time data type.
*/
static int
tm2time(struct pg_tm * tm, fsec_t fsec, TimeADT *result)
Thomas G. Lockhart
committed
{
#ifdef HAVE_INT64_TIMESTAMP
*result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
Thomas G. Lockhart
committed
#else
*result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec + fsec;
Thomas G. Lockhart
committed
#endif
return 0;
}
/* time2tm()
* Convert time data type to POSIX time structure.
* For dates within the system-supported time_t range, convert to the
* local time zone. If out of this range, leave as GMT. - tgl 97/05/27
*/
static int
time2tm(TimeADT time, struct pg_tm * tm, fsec_t *fsec)
Thomas G. Lockhart
committed
{
#ifdef HAVE_INT64_TIMESTAMP
tm->tm_hour = time / USECS_PER_HOUR;
time -= tm->tm_hour * USECS_PER_HOUR;
tm->tm_min = time / USECS_PER_MINUTE;
time -= tm->tm_min * USECS_PER_MINUTE;
tm->tm_sec = time / USECS_PER_SEC;
time -= tm->tm_sec * USECS_PER_SEC;
Thomas G. Lockhart
committed
*fsec = time;
#else
double trem;
recalc:
Thomas G. Lockhart
committed
trem = time;
TMODULO(trem, tm->tm_hour, (double) SECS_PER_HOUR);
TMODULO(trem, tm->tm_min, (double) SECS_PER_MINUTE);
trem = TIMEROUND(trem);
/* roundoff may need to propagate to higher-order fields */
if (trem >= 1.0)
{
time = ceil(time);
goto recalc;
}
Thomas G. Lockhart
committed
*fsec = trem;
#endif
return 0;
}
Datum
time_out(PG_FUNCTION_ARGS)
TimeADT time = PG_GETARG_TIMEADT(0);
char *result;
*tm = &tt;
Thomas G. Lockhart
committed
fsec_t fsec;
char buf[MAXDATELEN + 1];
Thomas G. Lockhart
committed
time2tm(time, tm, &fsec);
EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
result = pstrdup(buf);
PG_RETURN_CSTRING(result);
}
/*
* time_recv - converts external binary format to time
*
* We make no attempt to provide compatibility between int and float
* time representations ...
*/
Datum
time_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif