Skip to content

Commit cd4bfdf

Browse files
committed
Initial commit
1 parent e03b52c commit cd4bfdf

8 files changed

+200
-1
lines changed

Diff for: LICENSE

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
daterange_inclusive is released under a PostgreSQL-like License, a liberal Open Source license, similar to the BSD or MIT licenses.
2+
3+
Portions Copyright (c) 2025, Postgres Professional
4+
5+
Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies.
6+
7+
IN NO EVENT SHALL POSTGRES PROFESSIONAL BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF POSTGRES PROFESSIONAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8+
9+
POSTGRES PROFESSIONAL SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND POSTGRES PROFESSIONAL HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

Diff for: Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
EXTENSION=daterange_inclusive
2+
MODULE_big=daterange_inclusive
3+
OBJS = daterange_inclusive.o
4+
PGFILEDESC = "daterange_inclusive - daterange with inclusive upper bound"
5+
DATA = "daterange_inclusive--1.0.sql"
6+
7+
REGRESS="daterange_inclusive"
8+
ifdef USE_PGXS
9+
PGXS := $(shell $(PG_CONFIG) --pgxs)
10+
include $(PGXS)
11+
endif
12+
13+

Diff for: README.md

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,29 @@
11
# daterange_inclusive
2-
A datarange type with inclusive upper bound
2+
A PostgreSQL datarange type with inclusive upper bound
3+
4+
The daterange type, as well as other range types, is by default output with non-exclusive upper range.
5+
This extension defines a type which is the same but with inclusive upper range.
6+
Such behaviour is more convenient in some practical use cases.
7+
8+
See example:
9+
10+
```
11+
CREATE EXTENSION daterange_inclusive;
12+
SELECT daterange('[2024-01-01,2024-06-01]');
13+
daterange
14+
-------------------------
15+
[2024-01-01,2024-06-02)
16+
17+
SELECT daterange_inclusive('[2024-01-01,2024-06-01]');
18+
daterange_inclusive
19+
-------------------------
20+
[2024-01-01,2024-06-01]
21+
```
22+
23+
## Building
24+
25+
```
26+
USE_PGXS=1 PG_CONFIG=/path_to_pgconfig make install
27+
```
28+
29+

Diff for: daterange_inclusive--1.0.sql

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CREATE TYPE daterange_inclusive;
2+
3+
CREATE FUNCTION date_minus(date1 date, date2 date) RETURNS float AS $$
4+
SELECT cast(date1 - date2 AS float);
5+
$$ LANGUAGE sql IMMUTABLE;
6+
7+
CREATE FUNCTION daterange_inclusive_canonical(dr daterange_inclusive) RETURNS daterange_inclusive AS 'MODULE_PATHNAME'
8+
LANGUAGE C STRICT IMMUTABLE;
9+
10+
CREATE TYPE daterange_inclusive AS RANGE (
11+
SUBTYPE = date,
12+
SUBTYPE_DIFF = date_minus,
13+
CANONICAL = daterange_inclusive_canonical
14+
);
15+
16+
CREATE CAST (daterange AS daterange_inclusive) WITH INOUT AS IMPLICIT;
17+
CREATE CAST (daterange_inclusive AS daterange) WITH INOUT AS IMPLICIT;
18+

Diff for: daterange_inclusive.c

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "postgres.h"
2+
#include "utils/rangetypes.h"
3+
#include "utils/date.h"
4+
#include "utils/fmgrprotos.h"
5+
6+
PG_MODULE_MAGIC;
7+
8+
PG_FUNCTION_INFO_V1(daterange_inclusive_canonical);
9+
10+
Datum
11+
daterange_inclusive_canonical(PG_FUNCTION_ARGS)
12+
{
13+
RangeType *r = PG_GETARG_RANGE_P(0);
14+
Node *escontext = fcinfo->context;
15+
TypeCacheEntry *typcache;
16+
RangeBound lower;
17+
RangeBound upper;
18+
bool empty;
19+
20+
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
21+
22+
range_deserialize(typcache, r, &lower, &upper, &empty);
23+
24+
if (empty)
25+
PG_RETURN_RANGE_P(r);
26+
27+
if (!lower.infinite && !DATE_NOT_FINITE(DatumGetDateADT(lower.val)) &&
28+
!lower.inclusive)
29+
{
30+
DateADT bnd = DatumGetDateADT(lower.val);
31+
32+
bnd++;
33+
if (unlikely(!IS_VALID_DATE(bnd)))
34+
ereturn(escontext, (Datum) 0,
35+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
36+
errmsg("date out of range")));
37+
lower.val = DateADTGetDatum(bnd);
38+
lower.inclusive = true;
39+
}
40+
41+
if (!upper.infinite && !DATE_NOT_FINITE(DatumGetDateADT(upper.val)) &&
42+
!upper.inclusive)
43+
{
44+
DateADT bnd = DatumGetDateADT(upper.val);
45+
46+
bnd--;
47+
if (unlikely(!IS_VALID_DATE(bnd)))
48+
ereturn(escontext, (Datum) 0,
49+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
50+
errmsg("date out of range")));
51+
upper.val = DateADTGetDatum(bnd);
52+
upper.inclusive = true;
53+
}
54+
55+
PG_RETURN_RANGE_P(range_serialize(typcache, &lower, &upper,
56+
false, escontext));
57+
}
58+

Diff for: daterange_inclusive.control

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# daterange_inclusive extension
2+
comment = 'daterange with inclusive upper bound'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/daterange_inclusive'
5+
relocatable = true
6+
trusted = true
7+

Diff for: expected/daterange_inclusive.out

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
CREATE EXTENSION daterange_inclusive;
2+
SELECT daterange_inclusive('2024-01-01' , '2024-06-01', '[]');
3+
daterange_inclusive
4+
-------------------------
5+
[01-01-2024,06-01-2024]
6+
(1 row)
7+
8+
SELECT daterange_inclusive('2024-01-01' , '2024-06-01', '[)');
9+
daterange_inclusive
10+
-------------------------
11+
[01-01-2024,05-31-2024]
12+
(1 row)
13+
14+
SELECT '[2025-01-01,2025-02-02]'::daterange::daterange_inclusive;
15+
daterange_inclusive
16+
-------------------------
17+
[01-01-2025,02-02-2025]
18+
(1 row)
19+
20+
SELECT '[2025-01-01,2025-02-02)'::daterange::daterange_inclusive;
21+
daterange_inclusive
22+
-------------------------
23+
[01-01-2025,02-01-2025]
24+
(1 row)
25+
26+
SELECT '[2025-01-01,2025-02-02]'::daterange_inclusive::daterange;
27+
daterange
28+
-------------------------
29+
[01-01-2025,02-03-2025)
30+
(1 row)
31+
32+
SELECT '[2025-01-01,2025-02-02)'::daterange_inclusive::daterange;
33+
daterange
34+
-------------------------
35+
[01-01-2025,02-02-2025)
36+
(1 row)
37+
38+
CREATE TABLE x (y daterange_inclusive);
39+
INSERT INTO x SELECT daterange_inclusive(d::date, (d + '1month'::interval)::date, '[]') FROM generate_series('2015-01-01'::date,'2025-02-02', '1day') d;
40+
INSERT INTO x SELECT daterange_inclusive(d::date, NULL::date, '[)') FROM generate_series('2015-01-01'::date,'2025-02-02', '1day') d;
41+
SELECT COUNT(*) FROM x;
42+
count
43+
-------
44+
7372
45+
(1 row)
46+
47+
CREATE INDEX ON x USING gist (y);
48+
INSERT INTO x SELECT '[2024-01-01,)'::daterange::daterange_inclusive;
49+
DROP EXTENSION daterange_inclusive CASCADE;
50+
NOTICE: drop cascades to column y of table x

Diff for: sql/daterange_inclusive.sql

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CREATE EXTENSION daterange_inclusive;
2+
SELECT daterange_inclusive('2024-01-01' , '2024-06-01', '[]');
3+
SELECT daterange_inclusive('2024-01-01' , '2024-06-01', '[)');
4+
SELECT '[2025-01-01,2025-02-02]'::daterange::daterange_inclusive;
5+
SELECT '[2025-01-01,2025-02-02)'::daterange::daterange_inclusive;
6+
SELECT '[2025-01-01,2025-02-02]'::daterange_inclusive::daterange;
7+
SELECT '[2025-01-01,2025-02-02)'::daterange_inclusive::daterange;
8+
9+
CREATE TABLE x (y daterange_inclusive);
10+
INSERT INTO x SELECT daterange_inclusive(d::date, (d + '1month'::interval)::date, '[]') FROM generate_series('2015-01-01'::date,'2025-02-02', '1day') d;
11+
INSERT INTO x SELECT daterange_inclusive(d::date, NULL::date, '[)') FROM generate_series('2015-01-01'::date,'2025-02-02', '1day') d;
12+
SELECT COUNT(*) FROM x;
13+
CREATE INDEX ON x USING gist (y);
14+
INSERT INTO x SELECT '[2024-01-01,)'::daterange::daterange_inclusive;
15+
16+
DROP EXTENSION daterange_inclusive CASCADE;
17+

0 commit comments

Comments
 (0)