Datum next_day(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *day_txt = PG_GETARG_TEXT_PP(1); const char *str = VARDATA_ANY(day_txt); int len = VARSIZE_ANY_EXHDR(day_txt); int off; int d = -1; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY /* Check mru_weekdays first for performance. */ if (mru_weekdays) { if ((d = weekday_search(mru_weekdays, str, len)) >= 0) goto found; else mru_weekdays = NULL; } #endif /* * Oracle uses only 3 heading characters of the input. * Ignore all trailing characters. */ if (len >= 3 && (d = ora_seq_prefix_search(str, ora_days, 3)) >= 0) goto found; #ifdef ENABLE_INTERNATIONALIZED_WEEKDAY do { int i; int encoding = GetDatabaseEncoding(); for (i = 0; i < lengthof(WEEKDAYS); i++) { if (encoding == WEEKDAYS[i].encoding) { if ((d = weekday_search(&WEEKDAYS[i], str, len)) >= 0) { mru_weekdays = &WEEKDAYS[i]; goto found; } } } } while(0); #endif CHECK_SEQ_SEARCH(-1, "DAY/Day/day"); found: off = d - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); }
Datum plvdate_unset_nonbizday_dow (PG_FUNCTION_ARGS) { text *day_txt = PG_GETARG_TEXT_PP(0); int d = ora_seq_search(VARDATA_ANY(day_txt), ora_days, VARSIZE_ANY_EXHDR(day_txt)); CHECK_SEQ_SEARCH(d, "DAY/Day/day"); nonbizdays = (nonbizdays | (1 << d)) ^ (1 << d); PG_RETURN_VOID(); }
Datum ora_date_round(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); text *fmt = PG_GETARG_TEXT_PP(1); DateADT result; int f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); result = _ora_date_round(day, f); PG_RETURN_DATEADT(result); }
Datum plvdate_default_holidays (PG_FUNCTION_ARGS) { text *country = PG_GETARG_TEXT_PP(0); int c = ora_seq_search(VARDATA_ANY(country), states, VARSIZE_ANY_EXHDR(country)); CHECK_SEQ_SEARCH(c, "STATE/State/state"); nonbizdays = defaults_ci[c].nonbizdays; use_easter = defaults_ci[c].use_easter; exceptions_c = 0; holidays_c = defaults_ci[c].holidays_c; memcpy(holidays, defaults_ci[c].holidays, holidays_c*sizeof(holiday_desc)); PG_RETURN_VOID(); }
/* next_day(date, integer) is not documented in Oracle manual, but ... */ Datum next_day_by_index(PG_FUNCTION_ARGS) { DateADT day = PG_GETARG_DATEADT(0); int idx = PG_GETARG_INT32(1); int off; /* * off is 1..7 (Sun..Sat). * * TODO: It should be affected by NLS_TERRITORY. For example, * 1..7 should be interpreted as Mon..Sun in GERMAN. */ CHECK_SEQ_SEARCH((idx < 1 || 7 < idx) ? -1 : 0, "DAY/Day/day"); /* j2day returns 0..6 as Sun..Sat */ off = (idx - 1) - j2day(day+POSTGRES_EPOCH_JDATE); PG_RETURN_DATEADT((off <= 0) ? day+off+7 : day + off); }
Datum plvdate_set_nonbizday_dow (PG_FUNCTION_ARGS) { unsigned char check; text *day_txt = PG_GETARG_TEXT_PP(0); int d = ora_seq_search(VARDATA_ANY(day_txt), ora_days, VARSIZE_ANY_EXHDR(day_txt)); CHECK_SEQ_SEARCH(d, "DAY/Day/day"); check = nonbizdays | (1 << d); if (check == 0x7f) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("nonbizday registeration error"), errdetail("Constraint violation."), errhint("One day in week have to be bizday."))); nonbizdays = nonbizdays | (1 << d); PG_RETURN_VOID(); }
/* * redotz is used only for timestamp with time zone */ static void tm_trunc(struct pg_tm *tm, text *fmt, bool *redotz) { int f; f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); tm->tm_sec = 0; switch (f) { CASE_fmt_IYYY CASE_fmt_WW CASE_fmt_W CASE_fmt_IW CASE_fmt_DAY CASE_fmt_CC j2date(_ora_date_trunc(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday), f) + POSTGRES_EPOCH_JDATE, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_YYYY tm->tm_mon = 1; CASE_fmt_Q tm->tm_mon = (3*((tm->tm_mon - 1)/3)) + 1; CASE_fmt_MON tm->tm_mday = 1; CASE_fmt_DDD tm->tm_hour = 0; *redotz = true; /* for all cases >= DAY */ CASE_fmt_HH tm->tm_min = 0; } }
static void tm_round(struct pg_tm *tm, text *fmt, bool *redotz) { int f; bool rounded = true; f = ora_seq_search(VARDATA_ANY(fmt), date_fmt, VARSIZE_ANY_EXHDR(fmt)); CHECK_SEQ_SEARCH(f, "round/trunc format string"); /* set rounding rule */ switch (f) { CASE_fmt_IYYY NOT_ROUND_MDAY(tm->tm_mday < 8 && tm->tm_mon == 1); NOT_ROUND_MDAY(tm->tm_mday == 30 && tm->tm_mon == 6); if (tm->tm_mday >= 28 && tm->tm_mon == 12 && tm->tm_hour >= 12) { DateADT isoyear = iso_year(tm->tm_year+1, 1, 8); DateADT day0 = DATE2J(tm->tm_year+1,1,1); DateADT dayc = DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday); if ((isoyear <= day0) || (day0 <= dayc + 2)) { rounded = false; } } break; CASE_fmt_YYYY NOT_ROUND_MDAY(tm->tm_mday == 30 && tm->tm_mon == 6); break; CASE_fmt_MON NOT_ROUND_MDAY(tm->tm_mday == 15); break; CASE_fmt_Q NOT_ROUND_MDAY(tm->tm_mday == 15 && tm->tm_mon == ((tm->tm_mon-1)/3)*3+2); break; CASE_fmt_WW CASE_fmt_IW /* last day in year */ NOT_ROUND_MDAY(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday) == (DATE2J(tm->tm_year+1, 1,1) - 1)); break; CASE_fmt_W /* last day in month */ NOT_ROUND_MDAY(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday) == (DATE2J(tm->tm_year, tm->tm_mon+1,1) - 1)); break; } switch (f) { /* easier convert to date */ CASE_fmt_IW CASE_fmt_DAY CASE_fmt_IYYY CASE_fmt_WW CASE_fmt_W CASE_fmt_CC CASE_fmt_MON CASE_fmt_YYYY CASE_fmt_Q ROUND_MDAY(tm); j2date(_ora_date_round(DATE2J(tm->tm_year, tm->tm_mon, tm->tm_mday), f) + POSTGRES_EPOCH_JDATE, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_DDD tm->tm_mday += (tm->tm_hour >= 12)?1:0; tm->tm_hour = 0; tm->tm_min = 0; *redotz = true; break; CASE_fmt_MI tm->tm_min += (tm->tm_sec >= 30)?1:0; break; CASE_fmt_HH tm->tm_hour += (tm->tm_min >= 30)?1:0; tm->tm_min = 0; break; } tm->tm_sec = 0; }