diff -c -r --new-file pgsql.03/doc/src/sgml/func.sgml pgsql/doc/src/sgml/func.sgml *** pgsql.03/doc/src/sgml/func.sgml 2005-06-07 00:49:35.000000000 +0200 --- pgsql/doc/src/sgml/func.sgml 2005-06-07 22:51:07.000000000 +0200 *************** *** 5099,5104 **** --- 5099,5112 ---- + 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 **** --- 5125,5138 ---- + 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 diff -c -r --new-file pgsql.03/src/backend/utils/adt/oracle_compat.c pgsql/src/backend/utils/adt/oracle_compat.c *** pgsql.03/src/backend/utils/adt/oracle_compat.c 2005-06-06 15:29:18.000000000 +0200 --- pgsql/src/backend/utils/adt/oracle_compat.c 2005-06-07 22:30:08.000000000 +0200 *************** *** 31,36 **** --- 31,38 ---- #include "utils/builtins.h" #include "utils/pg_locale.h" #include "mb/pg_wchar.h" + #include "utils/date.h" + #include "utils/nabstime.h" /* *************** *** 48,53 **** --- 50,71 ---- #define USE_WIDE_UPPER_LOWER #endif + /* + * External (defined in PgSQL datetime.c (timestamp utils)) + */ + + extern char *days[]; + + #define CHECK_SEQ_SEARCH(_l, _s) \ + do { \ + if ((_l) < 0) { \ + ereport(ERROR, \ + (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \ + errmsg("invalid value for %s", (_s)))); \ + } \ + } while (0) + + static text *dotrim(const char *string, int stringlen, const char *set, int setlen, bool doltrim, bool dortrim); *************** *** 1157,1159 **** --- 1175,1273 ---- PG_RETURN_TEXT_P(result); } + + /******************************************************************** + * + * next_day + * + * Syntax: + * + * date next_day(date value, text weekday) + * + * Purpose: + * + * Returns the first weekday that is greater than a date value. + * + ********************************************************************/ + + /* + * Search const value in char array + * + */ + + static int + seq_search(char *name, char **array, int max) + { + char *p, *n, **a; + int last, i; + + if (!*name) + return -1; + + *name = pg_toupper((unsigned char) *name); + for (last = 0, a = array; *a != NULL; a++) + { + if (*name != **a) + continue; + + for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++) + { + if (i == max) + return a - array; + if (*p == '\0') + break; + if (i > last) + { + *n = pg_tolower((unsigned char) *n); + last = i; + } + + if (*n != *p) + break; + } + } + + return -1; + } + + + 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); + } diff -c -r --new-file pgsql.03/src/include/catalog/pg_proc.h pgsql/src/include/catalog/pg_proc.h *** pgsql.03/src/include/catalog/pg_proc.h 2005-06-06 15:29:40.000000000 +0200 --- pgsql/src/include/catalog/pg_proc.h 2005-06-07 22:19:39.000000000 +0200 *************** *** 2196,2201 **** --- 2196,2206 ---- 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 = 1248 ( 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 = 1250 ( 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 = 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"); DATA(insert OID = 937 ( substring PGNSP PGUID 12 f f t f i 2 25 "25 23" _null_ _null_ _null_ text_substr_no_len - _null_ )); diff -c -r --new-file pgsql.03/src/include/utils/builtins.h pgsql/src/include/utils/builtins.h *** pgsql.03/src/include/utils/builtins.h 2005-06-06 15:29:46.000000000 +0200 --- pgsql/src/include/utils/builtins.h 2005-06-07 22:31:34.000000000 +0200 *************** *** 649,654 **** --- 649,656 ---- 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); /* inet_net_ntop.c */ extern char *inet_net_ntop(int af, const void *src, int bits, diff -c -r --new-file pgsql.03/src/test/regress/expected/oracle.out pgsql/src/test/regress/expected/oracle.out *** pgsql.03/src/test/regress/expected/oracle.out 2005-06-07 00:55:32.000000000 +0200 --- pgsql/src/test/regress/expected/oracle.out 2005-06-07 22:50:54.000000000 +0200 *************** *** 72,74 **** --- 72,109 ---- b (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) diff -c -r --new-file pgsql.03/src/test/regress/expected/oracle.out~ pgsql/src/test/regress/expected/oracle.out~ *** pgsql.03/src/test/regress/expected/oracle.out~ 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/expected/oracle.out~ 2005-06-07 00:55:32.000000000 +0200 *************** *** 0 **** --- 1,74 ---- + SELECT least(1,10,20,30); + least + ------- + 1 + (1 row) + + SELECT least('a','b','c','d'); + least + ------- + a + (1 row) + + SELECT least('2004-05-22'::date, '2004-05-10'::date); + least + ------------ + 2004-05-10 + (1 row) + + SELECT greatest(1,10,20,30); + greatest + ---------- + 30 + (1 row) + + SELECT greatest('a','b','c','d'); + greatest + ---------- + d + (1 row) + + SELECT greatest('2004-05-22'::date, '2004-05-10'::date); + greatest + ------------ + 2004-05-22 + (1 row) + + SELECT decode('a','n',10,'m',20,'a',30); + decode + -------- + 30 + (1 row) + + SELECT decode('a','n'); + ERROR: Function Decode needs minimal three arguments + SELECT decode('a','n',10,'m',20,'o',30,40); + decode + -------- + 40 + (1 row) + + SELECT decode(2,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + decode + ------------ + 2004-04-01 + (1 row) + + SELECT decode(null,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + decode + -------- + + (1 row) + + SELECT decode(4,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + decode + -------- + + (1 row) + + SELECT decode(null,'a','a',null,'b'); + decode + -------- + b + (1 row) + diff -c -r --new-file pgsql.03/src/test/regress/sql/oracle.sql pgsql/src/test/regress/sql/oracle.sql *** pgsql.03/src/test/regress/sql/oracle.sql 2005-06-07 00:52:13.000000000 +0200 --- pgsql/src/test/regress/sql/oracle.sql 2005-06-07 22:49:53.000000000 +0200 *************** *** 13,15 **** --- 13,23 ---- SELECT decode(null,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); SELECT decode(4,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); SELECT decode(null,'a','a',null,'b'); + + 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'); diff -c -r --new-file pgsql.03/src/test/regress/sql/oracle.sql~ pgsql/src/test/regress/sql/oracle.sql~ *** pgsql.03/src/test/regress/sql/oracle.sql~ 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/sql/oracle.sql~ 2005-06-07 00:52:13.000000000 +0200 *************** *** 0 **** --- 1,15 ---- + SELECT least(1,10,20,30); + SELECT least('a','b','c','d'); + SELECT least('2004-05-22'::date, '2004-05-10'::date); + + SELECT greatest(1,10,20,30); + SELECT greatest('a','b','c','d'); + SELECT greatest('2004-05-22'::date, '2004-05-10'::date); + + SELECT decode('a','n',10,'m',20,'a',30); + SELECT decode('a','n'); + SELECT decode('a','n',10,'m',20,'o',30,40); + SELECT decode(2,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + SELECT decode(null,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + SELECT decode(4,1,'2004-01-01'::date,2,'2004-04-01'::date,3,'2004-07-01'::date); + SELECT decode(null,'a','a',null,'b');