./PaxHeaders/pg_rrule-master0000644000000000000000000000006214137770177013344 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/0000755000175000017500000000000014137770177012370 5ustar00niknikpg_rrule-master/PaxHeaders/.gitignore0000644000000000000000000000006214137770177015254 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/.gitignore0000644000175000017500000000063614137770177014365 0ustar00niknik# C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.moc moc_*.cpp qrc_*.cpp ui_*.h Makefile* *-build-* # QtCreator *.autosave #QtCtreator Qml *.qmlproject.user *.qmlproject.user.* # Build build/ # PGXN results/ *.so tmp/ *.o regression.diffs regression.out /sql/ extension_name =>--* !/sql/<%= extension_name =>--*--*.sql pg_rrule-master/PaxHeaders/.template0000644000000000000000000000006214137770177015100 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/.template0000644000175000017500000000000414137770177014176 0ustar00nikniksql pg_rrule-master/PaxHeaders/LICENSE0000644000000000000000000000006214137770177014271 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/LICENSE0000644000175000017500000000206714137770177013402 0ustar00niknikThe MIT License (MIT) Copyright (c) 2014 petropavel13 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pg_rrule-master/PaxHeaders/META.json0000644000000000000000000000006214137770177014705 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/META.json0000644000175000017500000000110014137770177014001 0ustar00niknik{ "name": "pg_rrule", "abstract": "RRULE field type for PostgreSQL", "description": "", "version": "0.1.0", "maintainer": "petropavel", "license": "MIT", "provides": { "pg_rrule": { "abstract": "RRULE field type for PostgreSQL", "file": "sql/pg_rrule.sql", "docfile": "doc/pg_rrule.md", "version": "0.1.0" } }, "release_status": "beta", "generated_by": "petropavel", "meta-spec": { "version": "1.0.0", "url": "http://pgxn.org/meta/spec.txt" } } pg_rrule-master/PaxHeaders/Makefile0000644000000000000000000000006214137770177014724 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/Makefile0000644000175000017500000000232114137770177014026 0ustar00niknikEXTENSION = pg_rrule EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") DATA = $(filter-out $(wildcard sql/*--*.sql),$(wildcard sql/*.sql)) DOCS = $(wildcard doc/*.md) TESTS = $(wildcard test/sql/*.sql) REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) REGRESS_OPTS = --inputdir=test --load-language=plpgsql # # Uncoment the MODULES line if you are adding C files # to your extention. # MODULE_big = pg_rrule OBJS = $(patsubst %.c,%.o,$(wildcard src/*.c)) PG_CONFIG = pg_config PG91 = $(shell $(PG_CONFIG) --version | grep -qE " 8\.| 9\.0" && echo no || echo yes) ifeq ($(PG91),yes) all: sql/$(EXTENSION)--$(EXTVERSION).sql sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql cp $< $@ DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql EXTRA_CLEAN = sql/$(EXTENSION)--$(EXTVERSION).sql endif PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) src/pg_rrule.o: CFLAGS += $(shell pkg-config --cflags libical) pg_rrule.so: SHLIB_LINK += $(shell pkg-config --libs libical) sql/pg_rrule.sql: sql/pg_rrule.sql.in sed 's,MODULE_PATHNAME,$$libdir/$(@:sql/%.sql=%),g' $< >$@ pg_rrule-master/PaxHeaders/README.md0000644000000000000000000000006214137770177014543 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/README.md0000644000175000017500000000735714137770177013663 0ustar00niknikpg_rrule ======== Usage Get RRULE parameter get_PARAMNAME. Example. Get freq param: ```sql SELECT get_freq('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z'::rrule); get_freq ---------- WEEKLY (1 row) ``` Example. Get byday param: ```sql SELECT get_byday('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=MO,TH,SU'::rrule); get_byday ----------- {2,5,1} (1 row) ``` Example. Expand RRULE with timezone: ```sql SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02+00'::timestamp with time zone) ); unnest ------------------------ 2019-12-07 10:51:02+00 2019-12-14 10:51:02+00 2019-12-21 10:51:02+00 2019-12-28 10:51:02+00 (4 rows) ``` Example. Expand RRULE without timezone: ```sql SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02'::timestamp) ); unnest --------------------- 2019-12-07 10:51:02 2019-12-14 10:51:02 2019-12-21 10:51:02 2019-12-28 10:51:02 (4 rows) ``` Simple building: -------- ```sh cd src/ qmake pg_rrule.pro make ``` Simple install (Linux): ```sh cp libpg_rrule.so /usr/lib/postgresql/pg_rrule.so cp pg_rrule.control /usr/share/postgresql/extension/ cp sql/pg_rrule.sql /usr/share/postgresql/extension/pg_rrule--0.2.0.sql ``` Simple install (OS X): ```sh #TODO ``` Install extension (Postgresql): ```sql CREATE EXTENSION pg_rrule; ``` Building (A long description (not tested)) To build it, just do this: make make installcheck make install If you encounter an error such as: "Makefile", line 8: Need an operator You need to use GNU make, which may well be installed on your system as `gmake`: gmake gmake install gmake installcheck If you encounter an error such as: make: pg_config: Command not found Be sure that you have `pg_config` installed and in your path. If you used a package management system such as RPM to install PostgreSQL, be sure that the `-devel` package is also installed. If necessary tell the build process where to find it: env PG_CONFIG=/path/to/pg_config make && make installcheck && make install And finally, if all that fails (and if you're on PostgreSQL 8.1 or lower, it likely will), copy the entire distribution directory to the `contrib/` subdirectory of the PostgreSQL source tree and try it there without `pg_config`: env NO_PGXS=1 make && make installcheck && make install If you encounter an error such as: ERROR: must be owner of database regression You need to run the test suite using a super user, such as the default "postgres" super user: make installcheck PGUSER=postgres Once pg_rrule is installed, you can add it to a database. If you're running PostgreSQL 9.1.0 or greater, it's a simple as connecting to a database as a super user and running: CREATE EXTENSION pg_rrule; If you've upgraded your cluster to PostgreSQL 9.1 and already had pg_rrule installed, you can upgrade it to a properly packaged extension with: CREATE EXTENSION pg_rrule FROM unpackaged; For versions of PostgreSQL less than 9.1.0, you'll need to run the installation script: psql -d mydb -f /path/to/pgsql/share/contrib/pg_rrule.sql If you want to install pg_rrule and all of its supporting objects into a specific schema, use the `PGOPTIONS` environment variable to specify the schema, like so: PGOPTIONS=--search_path=extensions psql -d mydb -f pg_rrule.sql Dependencies ------------ The `pg_rrule` has libical as dependency. Copyright and License --------------------- Copyright (c) 2014 petropavel. pg_rrule-master/PaxHeaders/doc0000644000000000000000000000006214137770177013754 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/doc/0000755000175000017500000000000014137770177013135 5ustar00niknikpg_rrule-master/doc/PaxHeaders/pg_rrule.md0000644000000000000000000000006214137770177016172 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/doc/pg_rrule.md0000644000175000017500000000253314137770177015301 0ustar00niknikpg_rrule ======== Synopsis -------- RRULE field type for PostgreSQL Description ----------- Usage ----- SELECT 'FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule; rrule ------------------------------------------------------------------------------ FREQ=WEEKLY;UNTIL=20200101T045102Z;BYSECOND=2;BYMINUTE=51;BYHOUR=10;BYDAY=SA (1 row) SELECT * FROM unnest( rrule_get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02+00'::timestamp with time zone) ); unnest ------------------------ 2019-12-07 10:51:02+00 2019-12-14 10:51:02+00 2019-12-21 10:51:02+00 2019-12-28 10:51:02+00 (4 rows) SELECT * FROM unnest( rrule_get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02'::timestamp) ); unnest --------------------- 2019-12-07 10:51:02 2019-12-14 10:51:02 2019-12-21 10:51:02 2019-12-28 10:51:02 (4 rows) Support ------- There is issues tracker? Github? Put this information here. Author ------ petropavel Copyright and License --------------------- Copyright (c) 2014 petropavel. pg_rrule-master/PaxHeaders/pg_rrule.control0000644000000000000000000000006214137770177016505 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/pg_rrule.control0000644000175000017500000000022314137770177015606 0ustar00niknik# pg_rrule extension comment = 'RRULE field type for PostgreSQL' default_version = '0.2.0' relocatable = true module_pathname = '$libdir/pg_rrule' pg_rrule-master/PaxHeaders/sql0000644000000000000000000000006214137770177014006 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/sql/0000755000175000017500000000000014137770177013167 5ustar00niknikpg_rrule-master/sql/PaxHeaders/pg_rrule.sql.in0000644000000000000000000000006214137770177017030 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/sql/pg_rrule.sql.in0000644000175000017500000001001014137770177016124 0ustar00niknik/* * Author: petropavel * Created at: 2014-09-14 23:36:11 +0600 * */ -- -- This is a example code genereted automaticaly -- by pgxn-utils. SET client_min_messages = warning; CREATE TYPE rrule; CREATE OR REPLACE FUNCTION rrule_in(cstring) RETURNS rrule AS 'MODULE_PATHNAME', 'pg_rrule_in' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION rrule_out(rrule) RETURNS cstring AS 'MODULE_PATHNAME', 'pg_rrule_out' LANGUAGE C IMMUTABLE STRICT; CREATE TYPE rrule ( input = rrule_in, output = rrule_out, internallength = 2760 -- TODO: check sizeof(icalrecurrencetype) on 32-bit machine ); CREATE CAST (text AS rrule) WITH INOUT; CREATE CAST (varchar AS rrule) WITH INOUT; CREATE OR REPLACE FUNCTION get_occurrences(rrule, timestamp with time zone) RETURNS timestamp with time zone[] AS 'MODULE_PATHNAME', 'pg_rrule_get_occurrences_dtstart_tz' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION get_occurrences(rrule, timestamp with time zone, timestamp with time zone) RETURNS timestamp with time zone[] AS 'MODULE_PATHNAME', 'pg_rrule_get_occurrences_dtstart_until_tz' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION get_occurrences(rrule, timestamp) RETURNS timestamp[] AS 'MODULE_PATHNAME', 'pg_rrule_get_occurrences_dtstart' LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION get_occurrences(rrule, timestamp, timestamp) RETURNS timestamp[] AS 'MODULE_PATHNAME', 'pg_rrule_get_occurrences_dtstart_until' LANGUAGE C IMMUTABLE STRICT; /* FREQ */ CREATE OR REPLACE FUNCTION get_freq(rrule) RETURNS text AS 'MODULE_PATHNAME', 'pg_rrule_get_freq_rrule' LANGUAGE C IMMUTABLE STRICT; /* UNTIL */ CREATE OR REPLACE FUNCTION get_until(rrule) RETURNS timestamp AS 'MODULE_PATHNAME', 'pg_rrule_get_until_rrule' LANGUAGE C IMMUTABLE STRICT; /* UNTIL TZ */ CREATE OR REPLACE FUNCTION get_untiltz(rrule) RETURNS timestamp with time zone AS 'MODULE_PATHNAME', 'pg_rrule_get_untiltz_rrule' LANGUAGE C IMMUTABLE STRICT; /* COUNT */ CREATE OR REPLACE FUNCTION get_count(rrule) RETURNS int4 AS 'MODULE_PATHNAME', 'pg_rrule_get_count_rrule' LANGUAGE C IMMUTABLE STRICT; /* INTERVAL */ CREATE OR REPLACE FUNCTION get_interval(rrule) RETURNS int2 AS 'MODULE_PATHNAME', 'pg_rrule_get_interval_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYSECOND */ CREATE OR REPLACE FUNCTION get_bysecond(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_bysecond_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYMINUTE */ CREATE OR REPLACE FUNCTION get_byminute(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_byminute_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYHOUR */ CREATE OR REPLACE FUNCTION get_byhour(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_byhour_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYDAY */ CREATE OR REPLACE FUNCTION get_byday(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_byday_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYMONTHDAY */ CREATE OR REPLACE FUNCTION get_bymonthday(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_bymonthday_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYYEARDAY */ CREATE OR REPLACE FUNCTION get_byyearday(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_byyearday_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYWEEKNO */ CREATE OR REPLACE FUNCTION get_byweekno(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_byweekno_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYMONTH */ CREATE OR REPLACE FUNCTION get_bymonth(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_bymonth_rrule' LANGUAGE C IMMUTABLE STRICT; /* BYSETPOS */ CREATE OR REPLACE FUNCTION get_bysetpos(rrule) RETURNS int2[] AS 'MODULE_PATHNAME', 'pg_rrule_get_bysetpos_rrule' LANGUAGE C IMMUTABLE STRICT; /* WKST */ CREATE OR REPLACE FUNCTION get_wkst(rrule) RETURNS text AS 'MODULE_PATHNAME', 'pg_rrule_get_wkst_rrule' LANGUAGE C IMMUTABLE STRICT; pg_rrule-master/sql/PaxHeaders/uninstall_pg_rrule.sql0000644000000000000000000000006214137770177020514 xustar0020 atime=1635774591 30 ctime=1714476153.171237598 pg_rrule-master/sql/uninstall_pg_rrule.sql0000644000175000017500000000033714137770177017623 0ustar00niknik/* * Author: petropavel * Created at: 2014-09-14 23:36:11 +0600 * */ -- -- This is a example code genereted automaticaly -- by pgxn-utils. SET client_min_messages = warning; BEGIN; DROP TYPE rrule CASCADE; COMMIT; pg_rrule-master/PaxHeaders/src0000644000000000000000000000006214137770177013776 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/src/0000755000175000017500000000000014137770177013157 5ustar00niknikpg_rrule-master/src/PaxHeaders/pg_rrule.c0000644000000000000000000000006214137770177016036 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/src/pg_rrule.c0000644000175000017500000004524014137770177015147 0ustar00niknik#include "pg_rrule.h" #include #include #include // oids #include // get_typlenbyvalalign #include "utils/builtins.h" // cstring_to_text const char* icalrecur_freq_to_string(icalrecurrencetype_frequency kind); // no public definition in ical.h const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind); // no public definition in ical.h Datum pg_rrule_in(PG_FUNCTION_ARGS) { const char* const rrule_str = PG_GETARG_CSTRING(0); struct icalrecurrencetype recurrence = icalrecurrencetype_from_string(rrule_str); const icalerrorenum err = icalerrno; if (err != ICAL_NO_ERROR) { icalerror_clear_errno(); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Can't parse RRULE. iCal error: %s. RRULE \"%s\".", icalerror_strerror(err), rrule_str), errhint("You need to omit \"RRULE:\" part of expression (if present)"))); } if (recurrence.freq == ICAL_NO_RECURRENCE) { // libical 1.0 won't round trip this, so we treat it as an error. ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Invalid RRULE frequency. RRULE \"%s\".", rrule_str))); } struct icalrecurrencetype* recurrence_ref = palloc(sizeof(struct icalrecurrencetype)); (*recurrence_ref) = recurrence; PG_RETURN_POINTER(recurrence_ref); } Datum pg_rrule_out(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); char* const rrule_str = icalrecurrencetype_as_string(recurrence_ref); const icalerrorenum err = icalerrno; if (err != ICAL_NO_ERROR) { icalerror_clear_errno(); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Can't convert RRULE to string. iCal error: %s", icalerror_strerror(err)), errhint("Please create new issue here: https://github.com/petropavel13/pg_rrule/issues/new"))); } const size_t str_bytes = sizeof(char) * (strlen(rrule_str) + 1); char* const rrule_str_copy = palloc(str_bytes); memcpy(rrule_str_copy, rrule_str, str_bytes); PG_RETURN_CSTRING(rrule_str_copy); } Datum pg_rrule_get_occurrences_dtstart_tz(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); TimestampTz dtstart_ts = PG_GETARG_TIMESTAMPTZ(1); long int gmtoff = 0; icaltimezone* ical_tz = NULL; if (pg_get_timezone_offset(session_timezone, &gmtoff)) { ical_tz = icaltimezone_get_builtin_timezone_from_offset(gmtoff, pg_get_timezone_name(session_timezone)); } if (ical_tz == NULL) { elog(WARNING, "Can't get timezone from current session! Fallback to UTC."); ical_tz = icaltimezone_get_utc_timezone(); } pg_time_t dtstart_ts_pg_time_t = timestamptz_to_time_t(dtstart_ts); struct icaltimetype dtstart = icaltime_from_timet_with_zone((time_t)dtstart_ts_pg_time_t, 0, ical_tz); // it's safe ? time_t may be double, float, etc... return pg_rrule_get_occurrences_rrule(*recurrence_ref, dtstart, true); } Datum pg_rrule_get_occurrences_dtstart_until_tz(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); TimestampTz dtstart_ts = PG_GETARG_TIMESTAMPTZ(1); TimestampTz until_ts = PG_GETARG_TIMESTAMPTZ(2); long int gmtoff = 0; icaltimezone* ical_tz = NULL; if (pg_get_timezone_offset(session_timezone, &gmtoff)) { ical_tz = icaltimezone_get_builtin_timezone_from_offset(gmtoff, pg_get_timezone_name(session_timezone)); } if (ical_tz == NULL) { elog(WARNING, "Can't get timezone from current session! Fallback to UTC."); ical_tz = icaltimezone_get_utc_timezone(); } pg_time_t dtstart_ts_pg_time_t = timestamptz_to_time_t(dtstart_ts); pg_time_t until_ts_pg_time_t = timestamptz_to_time_t(until_ts); struct icaltimetype dtstart = icaltime_from_timet_with_zone((time_t)dtstart_ts_pg_time_t, 0, ical_tz); // it's safe ? time_t may be double, float, etc... struct icaltimetype until = icaltime_from_timet_with_zone((time_t)until_ts_pg_time_t, 0, ical_tz); // it's safe ? time_t may be double, float, etc... return pg_rrule_get_occurrences_rrule_until(*recurrence_ref, dtstart, until, true); } Datum pg_rrule_get_occurrences_dtstart(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); Timestamp dtstart_ts = PG_GETARG_TIMESTAMP(1); pg_time_t dtstart_ts_pg_time_t = timestamptz_to_time_t(dtstart_ts); struct icaltimetype dtstart = icaltime_from_timet_with_zone((time_t)dtstart_ts_pg_time_t, 0, icaltimezone_get_utc_timezone()); // it's safe ? time_t may be double, float, etc... return pg_rrule_get_occurrences_rrule(*recurrence_ref, dtstart, false); } Datum pg_rrule_get_occurrences_dtstart_until(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); Timestamp dtstart_ts = PG_GETARG_TIMESTAMP(1); Timestamp until_ts = PG_GETARG_TIMESTAMPTZ(2); pg_time_t dtstart_ts_pg_time_t = timestamptz_to_time_t(dtstart_ts); pg_time_t until_ts_pg_time_t = timestamptz_to_time_t(until_ts); struct icaltimetype dtstart = icaltime_from_timet_with_zone((time_t)dtstart_ts_pg_time_t, 0, icaltimezone_get_utc_timezone()); // it's safe ? time_t may be double, float, etc... struct icaltimetype until = icaltime_from_timet_with_zone((time_t)until_ts_pg_time_t, 0, icaltimezone_get_utc_timezone()); // it's safe ? time_t may be double, float, etc... return pg_rrule_get_occurrences_rrule_until(*recurrence_ref, dtstart, until, false); } /* FREQ */ Datum pg_rrule_get_freq_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); if (recurrence_ref->freq == ICAL_NO_RECURRENCE) { PG_RETURN_NULL(); } const char* const freq_string = icalrecur_freq_to_string(recurrence_ref->freq); PG_RETURN_TEXT_P(cstring_to_text(freq_string)); } /* UNTIL */ Datum pg_rrule_get_until_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); if (icaltime_is_null_time(recurrence_ref->until)) { PG_RETURN_NULL(); } pg_time_t until_pg_time_t = (pg_time_t)icaltime_as_timet_with_zone(recurrence_ref->until, icaltimezone_get_utc_timezone()); // it's safe ? time_t may be double, float, etc... PG_RETURN_TIMESTAMP(time_t_to_timestamptz(until_pg_time_t)); } /* UNTIL TZ */ Datum pg_rrule_get_untiltz_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); if (icaltime_is_null_time(recurrence_ref->until)) { PG_RETURN_NULL(); } long int gmtoff = 0; icaltimezone* ical_tz = NULL; if (pg_get_timezone_offset(session_timezone, &gmtoff)) { ical_tz = icaltimezone_get_builtin_timezone_from_offset(gmtoff, pg_get_timezone_name(session_timezone)); } if (ical_tz == NULL) { elog(WARNING, "Can't get timezone from current session! Fallback to UTC."); ical_tz = icaltimezone_get_utc_timezone(); } pg_time_t until_pg_time_t = (pg_time_t)icaltime_as_timet_with_zone(recurrence_ref->until, ical_tz); // it's safe ? time_t may be double, float, etc... PG_RETURN_TIMESTAMP(time_t_to_timestamptz(until_pg_time_t)); } /* COUNT */ Datum pg_rrule_get_count_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); PG_RETURN_INT32(recurrence_ref->count); } /* INTERVAL */ Datum pg_rrule_get_interval_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); PG_RETURN_INT16(recurrence_ref->interval); } /* BYSECOND */ Datum pg_rrule_get_bysecond_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_SECOND_SIZE && recurrence_ref->by_second[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_second[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYMINUTE */ Datum pg_rrule_get_byminute_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_MINUTE_SIZE && recurrence_ref->by_minute[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_minute[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYHOUR */ Datum pg_rrule_get_byhour_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_HOUR_SIZE && recurrence_ref->by_hour[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_hour[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYDAY */ Datum pg_rrule_get_byday_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_DAY_SIZE && recurrence_ref->by_day[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_day[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYMONTHDAY */ Datum pg_rrule_get_bymonthday_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_MONTHDAY_SIZE && recurrence_ref->by_month_day[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_month_day[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYYEARDAY */ Datum pg_rrule_get_byyearday_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_YEARDAY_SIZE && recurrence_ref->by_year_day[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_year_day[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYWEEKNO */ Datum pg_rrule_get_byweekno_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_WEEKNO_SIZE && recurrence_ref->by_week_no[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_week_no[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYMONTH */ Datum pg_rrule_get_bymonth_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_MONTH_SIZE && recurrence_ref->by_month[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_month[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* BYSETPOS */ Datum pg_rrule_get_bysetpos_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); unsigned int cnt = 0; for (; cnt < ICAL_BY_SETPOS_SIZE && recurrence_ref->by_set_pos[cnt] != ICAL_RECURRENCE_ARRAY_MAX; ++cnt); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { datum_elems[i] = Int16GetDatum(recurrence_ref->by_set_pos[i]); } int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(INT2OID, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, INT2OID, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } /* WKST */ Datum pg_rrule_get_wkst_rrule(PG_FUNCTION_ARGS) { struct icalrecurrencetype* recurrence_ref = (struct icalrecurrencetype*)PG_GETARG_POINTER(0); if (recurrence_ref->week_start == ICAL_NO_WEEKDAY) { PG_RETURN_NULL(); } const char* const wkst_string = icalrecur_weekday_to_string(recurrence_ref->week_start); PG_RETURN_TEXT_P(cstring_to_text(wkst_string)); } Datum pg_rrule_get_occurrences_rrule(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, bool use_tz) { return pg_rrule_get_occurrences_rrule_until(recurrence, dtstart, icaltime_null_time(), use_tz); } Datum pg_rrule_get_occurrences_rrule_until(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, struct icaltimetype until, bool use_tz) { time_t* times_array = NULL; unsigned int cnt = 0; pg_rrule_rrule_to_time_t_array_until(recurrence, dtstart, until, ×_array, &cnt); pg_time_t* pg_times_array = palloc(sizeof(pg_time_t) * cnt); unsigned int i; for (i = 0; i < cnt; ++i) { pg_times_array[i] = (pg_time_t)times_array[i]; // it's safe ? time_t may be double, float, etc... } free(times_array); Datum* const datum_elems = palloc(sizeof(Datum) * cnt); if (use_tz) { for (i = 0; i < cnt; ++i) { datum_elems[i] = TimestampTzGetDatum(time_t_to_timestamptz(pg_times_array[i])); } } else { for (i = 0; i < cnt; ++i) { datum_elems[i] = TimestampGetDatum(time_t_to_timestamptz(pg_times_array[i])); } } pfree(pg_times_array); int16 typlen; bool typbyval; char typalign; const Oid ts_oid = use_tz ? TIMESTAMPTZOID : TIMESTAMPOID; get_typlenbyvalalign(ts_oid, &typlen, &typbyval, &typalign); ArrayType* result_array = construct_array(datum_elems, cnt, ts_oid, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result_array); } void pg_rrule_rrule_to_time_t_array(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, time_t** const out_array, unsigned int* const out_count) { pg_rrule_rrule_to_time_t_array_until(recurrence, dtstart, icaltime_null_time(), out_array, out_count); } void pg_rrule_rrule_to_time_t_array_until(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, struct icaltimetype until, time_t** const out_array, unsigned int* const out_count) { icalrecur_iterator* const recur_iterator = icalrecur_iterator_new(recurrence, dtstart); icalarray* const icaltimes_list = icalarray_new(sizeof(icaltimetype), 32); struct icaltimetype ical_time = icalrecur_iterator_next(recur_iterator); if (icaltime_is_null_time(until)) { while (icaltime_is_null_time(ical_time) == false) { icalarray_append(icaltimes_list, &ical_time); ical_time = icalrecur_iterator_next(recur_iterator); } } else { while (icaltime_is_null_time(ical_time) == false && icaltime_compare(ical_time, until) != 1 ) { // while ical_time <= until icalarray_append(icaltimes_list, &ical_time); ical_time = icalrecur_iterator_next(recur_iterator); } } icalrecur_iterator_free(recur_iterator); const unsigned int cnt = (*out_count) = icaltimes_list->num_elements; time_t* times_array = (*out_array) = malloc(sizeof(time_t) * cnt); unsigned int i = 0; for (i = 0; i < cnt; ++i) { ical_time = (*(icaltimetype*)icalarray_element_at(icaltimes_list, i)); times_array[i] = icaltime_as_timet_with_zone(ical_time, dtstart.zone); } icalarray_free(icaltimes_list); } pg_rrule-master/src/PaxHeaders/pg_rrule.h0000644000000000000000000000006214137770177016043 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/src/pg_rrule.h0000644000175000017500000000705114137770177015152 0ustar00niknik#ifndef PG_RRULE_H #define PG_RRULE_H #include #include #include PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(pg_rrule_in); Datum pg_rrule_in(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_rrule_out); Datum pg_rrule_out(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_rrule_get_occurrences_dtstart_tz); Datum pg_rrule_get_occurrences_dtstart_tz(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_rrule_get_occurrences_dtstart_until_tz); Datum pg_rrule_get_occurrences_dtstart_until_tz(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_rrule_get_occurrences_dtstart); Datum pg_rrule_get_occurrences_dtstart(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_rrule_get_occurrences_dtstart_until); Datum pg_rrule_get_occurrences_dtstart_until(PG_FUNCTION_ARGS); /* FREQ */ PG_FUNCTION_INFO_V1(pg_rrule_get_freq_rrule); Datum pg_rrule_get_freq_rrule(PG_FUNCTION_ARGS); /* UNTIL */ PG_FUNCTION_INFO_V1(pg_rrule_get_until_rrule); Datum pg_rrule_get_until_rrule(PG_FUNCTION_ARGS); /* UNTIL TZ */ PG_FUNCTION_INFO_V1(pg_rrule_get_untiltz_rrule); Datum pg_rrule_get_untiltz_rrule(PG_FUNCTION_ARGS); /* COUNT */ PG_FUNCTION_INFO_V1(pg_rrule_get_count_rrule); Datum pg_rrule_get_count_rrule(PG_FUNCTION_ARGS); /* INTERVAL */ PG_FUNCTION_INFO_V1(pg_rrule_get_interval_rrule); Datum pg_rrule_get_interval_rrule(PG_FUNCTION_ARGS); /* BYSECOND */ PG_FUNCTION_INFO_V1(pg_rrule_get_bysecond_rrule); Datum pg_rrule_get_bysecond_rrule(PG_FUNCTION_ARGS); /* BYMINUTE */ PG_FUNCTION_INFO_V1(pg_rrule_get_byminute_rrule); Datum pg_rrule_get_byminute_rrule(PG_FUNCTION_ARGS); /* BYHOUR */ PG_FUNCTION_INFO_V1(pg_rrule_get_byhour_rrule); Datum pg_rrule_get_byhour_rrule(PG_FUNCTION_ARGS); /* BYDAY */ PG_FUNCTION_INFO_V1(pg_rrule_get_byday_rrule); Datum pg_rrule_get_byday_rrule(PG_FUNCTION_ARGS); /* BYMONTHDAY */ PG_FUNCTION_INFO_V1(pg_rrule_get_bymonthday_rrule); Datum pg_rrule_get_bymonthday_rrule(PG_FUNCTION_ARGS); /* BYYEARDAY */ PG_FUNCTION_INFO_V1(pg_rrule_get_byyearday_rrule); Datum pg_rrule_get_byyearday_rrule(PG_FUNCTION_ARGS); /* BYWEEKNO */ PG_FUNCTION_INFO_V1(pg_rrule_get_byweekno_rrule); Datum pg_rrule_get_byweekno_rrule(PG_FUNCTION_ARGS); /* BYMONTH */ PG_FUNCTION_INFO_V1(pg_rrule_get_bymonth_rrule); Datum pg_rrule_get_bymonth_rrule(PG_FUNCTION_ARGS); /* BYSETPOS */ PG_FUNCTION_INFO_V1(pg_rrule_get_bysetpos_rrule); Datum pg_rrule_get_bysetpos_rrule(PG_FUNCTION_ARGS); /* WKST */ PG_FUNCTION_INFO_V1(pg_rrule_get_wkst_rrule); Datum pg_rrule_get_wkst_rrule(PG_FUNCTION_ARGS); Datum pg_rrule_get_occurrences_rrule(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, bool use_tz); Datum pg_rrule_get_occurrences_rrule_until(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, struct icaltimetype until, bool use_tz); void pg_rrule_rrule_to_time_t_array(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, time_t** const out_array, unsigned int* const out_count); void pg_rrule_rrule_to_time_t_array_until(struct icalrecurrencetype recurrence, struct icaltimetype dtstart, struct icaltimetype until, time_t** const out_array, unsigned int* const out_count); #endif // PG_RRULE_H pg_rrule-master/src/PaxHeaders/pg_rrule.pro0000644000000000000000000000006214137770177016414 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/src/pg_rrule.pro0000644000175000017500000000116314137770177015521 0ustar00niknikTEMPLATE = lib CONFIG += console CONFIG -= app_bundle CONFIG -= qt macx { INCLUDEPATH += "/usr/local/include/server/" \ "/usr/local/include/" LIBS += -L/usr/local/lib/ -lical -lpq QMAKE_LFLAGS_SHLIB -= -dynamiclib QMAKE_LFLAGS_VERSION = "" QMAKE_LFLAGS_COMPAT_VERSION = "" QMAKE_LFLAGS_SONAME = "" QMAKE_LFLAGS = -bundle -flat_namespace -undefined suppress QMAKE_EXTENSION_SHLIB = so } unix:!macx { INCLUDEPATH += $$system(pg_config --includedir-server) LIBS += -lpq -lical QMAKE_CFLAGS = -fpic } SOURCES += \ pg_rrule.c HEADERS += \ pg_rrule.h pg_rrule-master/PaxHeaders/test0000644000000000000000000000006214137770177014166 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/test/0000755000175000017500000000000014137770177013347 5ustar00niknikpg_rrule-master/test/PaxHeaders/expected0000644000000000000000000000006214137770177015767 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/test/expected/0000755000175000017500000000000014137770177015150 5ustar00niknikpg_rrule-master/test/expected/PaxHeaders/base.out0000644000000000000000000000006214137770177017507 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/test/expected/base.out0000644000175000017500000000221614137770177016614 0ustar00niknik\set ECHO 0 SELECT 'FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z'::rrule; rrule ------------------------------------ FREQ=WEEKLY;UNTIL=20200101T045102Z (1 row) SELECT get_byday('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=MO,TH,SU'::rrule); get_byday ----------- {2,5,1} (1 row) SELECT get_freq('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z'::rrule); get_freq ---------- WEEKLY (1 row) SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02+00'::timestamp with time zone) ); unnest ------------------------ 2019-12-07 10:51:02+00 2019-12-14 10:51:02+00 2019-12-21 10:51:02+00 2019-12-28 10:51:02+00 (4 rows) SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02'::timestamp) ); unnest --------------------- 2019-12-07 10:51:02 2019-12-14 10:51:02 2019-12-21 10:51:02 2019-12-28 10:51:02 (4 rows) ROLLBACK; pg_rrule-master/test/PaxHeaders/sql0000644000000000000000000000007414137770177014770 xustar0030 atime=1714476153.174570979 30 ctime=1714476153.174570979 pg_rrule-master/test/sql/0000755000175000017500000000000014137770177014146 5ustar00niknikpg_rrule-master/test/sql/PaxHeaders/base.sql0000644000000000000000000000006214137770177016475 xustar0020 atime=1635774591 30 ctime=1714476153.174570979 pg_rrule-master/test/sql/base.sql0000644000175000017500000000136214137770177015603 0ustar00niknik\set ECHO 0 BEGIN; \i sql/pg_rrule.sql \set ECHO all SELECT 'FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z'::rrule; SELECT get_byday('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=MO,TH,SU'::rrule); SELECT get_freq('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z'::rrule); SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02+00'::timestamp with time zone) ); SELECT * FROM unnest( get_occurrences('FREQ=WEEKLY;INTERVAL=1;WKST=MO;UNTIL=20200101T045102Z;BYDAY=SA;BYHOUR=10;BYMINUTE=51;BYSECOND=2'::rrule, '2019-12-07 10:51:02'::timestamp) ); ROLLBACK;