diff -c -r --new-file pgsql.old/doc/src/sgml/func.sgml pgsql.new/doc/src/sgml/func.sgml
*** pgsql.old/doc/src/sgml/func.sgml 2005-05-23 03:50:01.000000000 +0200
--- pgsql.new/doc/src/sgml/func.sgml 2005-05-24 17:30:22.000000000 +0200
***************
*** 4989,4994 ****
--- 4989,5003 ----
+ add_months(date, integer)
+ date
+ Returns date plus n months
+ add_months(date '2005-05-31',1)
+ 2005-06-30
+
+
+
+
age(timestamp, timestamp)
interval
Subtract arguments, producing a symbolic> result that
***************
*** 5099,5104 ****
--- 5108,5121 ----
+ last_day(date)
+ date
+ Returns last day of the month based on a date value
+ last_day(date '2005-05-24')
+ 2005-05-31
+
+
+
localtime
time
Time of day; see
***************
*** 5117,5122 ****
--- 5134,5147 ----
+ next_day(date, text)
+ date
+ Returns the first weekday that is greather than a date value.
+ next_day(date '2005-05-24', 'monday')
+ 2005-05-30
+
+
+
now()
timestamp with time zone
Current date and time (equivalent to
***************
*** 5128,5133 ****
--- 5153,5169 ----
+ months_between(date, date)
+ float8
+ Returns the number of months between date1 and date2. If
+ a fractional month is calculated, the months_between function
+ calculates the fraction based on a 31-day month.
+ months_between(date '1995-02-02', date '1995-01-01')
+ 1.03225806451613
+
+
+
+
timeofday()
text
Current date and time; see last)
+ {
+ *n = pg_tolower((unsigned char) *n);
+ last = i;
+ }
+
+ if (*n != *p)
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ /********************************************************************
+ *
+ * next_day
+ *
+ * Syntax:
+ *
+ * date next_day(date value, text weekday)
+ *
+ * Purpose:
+ *
+ * Returns the first weekday that is greater than a date value.
+ *
+ ********************************************************************/
+
+
+ Datum next_day (PG_FUNCTION_ARGS)
+ {
+
+ DateADT day = PG_GETARG_DATEADT(0);
+ text *day_txt = PG_GETARG_TEXT_P(1);
+ int off;
+
+ int d = seq_search(VARDATA(day_txt), days, VARATT_SIZEP(day_txt) - VARHDRSZ);
+ CHECK_SEQ_SEARCH(d, "DAY/Day/day");
+
+ off = d - j2day(day+POSTGRES_EPOCH_JDATE);
+
+ PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off);
+ }
+
+ /********************************************************************
+ *
+ * last_day
+ *
+ * Syntax:
+ *
+ * date last_day(date value)
+ *
+ * Purpose:
+ *
+ * Returns last day of the month based on a date value
+ *
+ ********************************************************************/
+
+
+ Datum last_day (PG_FUNCTION_ARGS)
+ {
+ DateADT day = PG_GETARG_DATEADT(0);
+ DateADT result;
+ int y, m, d;
+ j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+ result = date2j(y, m+1, 1) - POSTGRES_EPOCH_JDATE;
+
+ PG_RETURN_DATEADT(result - 1);
+ }
+
+ /********************************************************************
+ *
+ * months_between
+ *
+ * Syntax:
+ *
+ * float8 months_between(date date1, date date2)
+ *
+ * Purpose:
+ *
+ * Returns the number of months between date1 and date2. If
+ * a fractional month is calculated, the months_between function
+ * calculates the fraction based on a 31-day month.
+ *
+ ********************************************************************/
+
+
+ Datum months_between (PG_FUNCTION_ARGS)
+ {
+ DateADT date1 = PG_GETARG_DATEADT(0);
+ DateADT date2 = PG_GETARG_DATEADT(1);
+
+ int y1, m1, d1;
+ int y2, m2, d2;
+
+ float8 result;
+
+ j2date(date1 + POSTGRES_EPOCH_JDATE, &y1, &m1, &d1);
+ j2date(date2 + POSTGRES_EPOCH_JDATE, &y2, &m2, &d2);
+
+ result = (y1 - y2) * 12 + (m1 - m2) + (d1 - d2) / 31.0;
+
+ PG_RETURN_FLOAT8(result);
+
+ }
+
+ /********************************************************************
+ *
+ * add_months
+ *
+ * Syntax:
+ *
+ * date add_months(date day, int val)
+ *
+ * Purpose:
+ *
+ * Returns a date plus n months.
+ *
+ ********************************************************************/
+
+
+ Datum add_months (PG_FUNCTION_ARGS)
+ {
+ DateADT day = PG_GETARG_DATEADT(0);
+ int n = PG_GETARG_INT32(1);
+ int y, m, d;
+ DateADT last_day, result;
+
+ j2date(day + POSTGRES_EPOCH_JDATE, &y, &m, &d);
+ result = date2j(y, m+n, d) - POSTGRES_EPOCH_JDATE;
+
+ if (d > 28)
+ {
+ m += 2;
+ if (m > 12)
+ {
+ ++y; m -= 12;
+ }
+ last_day = date2j(y, m, 1) - POSTGRES_EPOCH_JDATE - 1;
+ if (last_day < result)
+ result = last_day;
+ }
+
+ PG_RETURN_DATEADT (result);
+ }
diff -c -r --new-file pgsql.old/src/include/catalog/pg_proc.h pgsql.new/src/include/catalog/pg_proc.h
*** pgsql.old/src/include/catalog/pg_proc.h 2005-05-20 03:29:55.000000000 +0200
--- pgsql.new/src/include/catalog/pg_proc.h 2005-05-24 13:55:16.000000000 +0200
***************
*** 2160,2166 ****
DATA(insert OID = 1689 ( flatfile_update_trigger PGNSP PGUID 12 f f t f v 0 2279 "" _null_ _null_ _null_ flatfile_update_trigger - _null_ ));
DESCR("update flat-file copy of a shared catalog");
! /* Oracle Compatibility Related Functions - By Edmund Mergl */
DATA(insert OID = 868 ( strpos PGNSP PGUID 12 f f t f i 2 23 "25 25" _null_ _null_ _null_ textpos - _null_ ));
DESCR("find position of substring");
DATA(insert OID = 870 ( lower PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ lower - _null_ ));
--- 2160,2166 ----
DATA(insert OID = 1689 ( flatfile_update_trigger PGNSP PGUID 12 f f t f v 0 2279 "" _null_ _null_ _null_ flatfile_update_trigger - _null_ ));
DESCR("update flat-file copy of a shared catalog");
! /* Oracle Compatibility Related Functions - By Edmund Mergl , Pavel Stehule */
DATA(insert OID = 868 ( strpos PGNSP PGUID 12 f f t f i 2 23 "25 25" _null_ _null_ _null_ textpos - _null_ ));
DESCR("find position of substring");
DATA(insert OID = 870 ( lower PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ lower - _null_ ));
***************
*** 2195,2200 ****
--- 2195,2208 ----
DESCR("trim selected characters from both ends of string");
DATA(insert OID = 885 ( btrim PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ btrim1 - _null_ ));
DESCR("trim spaces from both ends of string");
+ DATA(insert OID = 901 ( next_day PGNSP PGUID 12 f f t f i 2 1082 "1082 25" _null_ _null_ _null_ next_day - _null_ ));
+ DESCR("return the first weekday that is greater than a date value");
+ DATA(insert OID = 902 ( last_day PGNSP PGUID 12 f f t f i 1 1082 "1082" _null_ _null_ _null_ last_day - _null_ ));
+ DESCR("last day of the month");
+ DATA(insert OID = 903 ( months_between PGNSP PGUID 12 f f t f i 2 701 "1082 1082" _null_ _null_ _null_ months_between - _null_ ));
+ DESCR("returns the number of months between date1 and date2");
+ DATA(insert OID = 904 ( add_months PGNSP PGUID 12 f f t f i 2 1082 "1082 23" _null_ _null_ _null_ add_months - _null_ ));
+ DESCR("returns a date plus n months");
DATA(insert OID = 936 ( substring PGNSP PGUID 12 f f t f i 3 25 "25 23 23" _null_ _null_ _null_ text_substr - _null_ ));
DESCR("return portion of string");
diff -c -r --new-file pgsql.old/src/include/utils/builtins.h pgsql.new/src/include/utils/builtins.h
*** pgsql.old/src/include/utils/builtins.h 2005-05-20 03:29:55.000000000 +0200
--- pgsql.new/src/include/utils/builtins.h 2005-05-24 13:16:51.000000000 +0200
***************
*** 649,654 ****
--- 649,658 ----
extern Datum chr (PG_FUNCTION_ARGS);
extern Datum repeat(PG_FUNCTION_ARGS);
extern Datum ascii(PG_FUNCTION_ARGS);
+ extern Datum next_day(PG_FUNCTION_ARGS);
+ extern Datum last_day(PG_FUNCTION_ARGS);
+ extern Datum months_between(PG_FUNCTION_ARGS);
+ extern Datum add_months(PG_FUNCTION_ARGS);
/* inet_net_ntop.c */
extern char *inet_net_ntop(int af, const void *src, int bits,
diff -c -r --new-file pgsql.old/src/test/regress/expected/oracle.out pgsql.new/src/test/regress/expected/oracle.out
*** pgsql.old/src/test/regress/expected/oracle.out 1970-01-01 01:00:00.000000000 +0100
--- pgsql.new/src/test/regress/expected/oracle.out 2005-05-24 17:04:22.000000000 +0200
***************
*** 0 ****
--- 1,87 ----
+ --
+ -- test built-in date type oracle compatibility functions
+ --
+ SELECT add_months ('2003-08-01', 3);
+ add_months
+ ------------
+ 2003-11-01
+ (1 row)
+
+ SELECT add_months ('2003-08-01', -3);
+ add_months
+ ------------
+ 2003-05-01
+ (1 row)
+
+ SELECT add_months ('2003-08-21', -3);
+ add_months
+ ------------
+ 2003-05-21
+ (1 row)
+
+ SELECT add_months ('2003-01-31', 1);
+ add_months
+ ------------
+ 2003-02-28
+ (1 row)
+
+ SELECT last_day (to_date('2003/03/15', 'yyyy/mm/dd'));
+ last_day
+ ------------
+ 2003-03-31
+ (1 row)
+
+ SELECT last_day (to_date('2003/02/03', 'yyyy/mm/dd'));
+ last_day
+ ------------
+ 2003-02-28
+ (1 row)
+
+ SELECT last_day (to_date('2004/02/03', 'yyyy/mm/dd'));
+ last_day
+ ------------
+ 2004-02-29
+ (1 row)
+
+ SELECT next_day ('2003-08-01', 'TUESDAY');
+ next_day
+ ------------
+ 2003-08-05
+ (1 row)
+
+ SELECT next_day ('2003-08-06', 'WEDNESDAY');
+ next_day
+ ------------
+ 2003-08-13
+ (1 row)
+
+ SELECT next_day ('2003-08-06', 'SUNDAY');
+ next_day
+ ------------
+ 2003-08-10
+ (1 row)
+
+ SELECT months_between (to_date ('2003/01/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd'));
+ months_between
+ -------------------
+ -2.41935483870968
+ (1 row)
+
+ SELECT months_between (to_date ('2003/07/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd'));
+ months_between
+ ------------------
+ 3.58064516129032
+ (1 row)
+
+ SELECT months_between (to_date ('2003/07/02', 'yyyy/mm/dd'), to_date ('2003/07/02', 'yyyy/mm/dd'));
+ months_between
+ ----------------
+ 0
+ (1 row)
+
+ SELECT months_between (to_date ('2003/08/02', 'yyyy/mm/dd'), to_date ('2003/06/02', 'yyyy/mm/dd'));
+ months_between
+ ----------------
+ 2
+ (1 row)
+
diff -c -r --new-file pgsql.old/src/test/regress/sql/oracle.sql pgsql.new/src/test/regress/sql/oracle.sql
*** pgsql.old/src/test/regress/sql/oracle.sql 1970-01-01 01:00:00.000000000 +0100
--- pgsql.new/src/test/regress/sql/oracle.sql 2005-05-24 16:41:33.000000000 +0200
***************
*** 0 ****
--- 1,21 ----
+ --
+ -- test built-in date type oracle compatibility functions
+ --
+
+ SELECT add_months ('2003-08-01', 3);
+ SELECT add_months ('2003-08-01', -3);
+ SELECT add_months ('2003-08-21', -3);
+ SELECT add_months ('2003-01-31', 1);
+
+ SELECT last_day (to_date('2003/03/15', 'yyyy/mm/dd'));
+ SELECT last_day (to_date('2003/02/03', 'yyyy/mm/dd'));
+ SELECT last_day (to_date('2004/02/03', 'yyyy/mm/dd'));
+
+ SELECT next_day ('2003-08-01', 'TUESDAY');
+ SELECT next_day ('2003-08-06', 'WEDNESDAY');
+ SELECT next_day ('2003-08-06', 'SUNDAY');
+
+ SELECT months_between (to_date ('2003/01/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd'));
+ SELECT months_between (to_date ('2003/07/01', 'yyyy/mm/dd'), to_date ('2003/03/14', 'yyyy/mm/dd'));
+ SELECT months_between (to_date ('2003/07/02', 'yyyy/mm/dd'), to_date ('2003/07/02', 'yyyy/mm/dd'));
+ SELECT months_between (to_date ('2003/08/02', 'yyyy/mm/dd'), to_date ('2003/06/02', 'yyyy/mm/dd'));