This topic presents the background information, data types, and usage of the ip4r
extension.
Prerequisites
A PolarDB for PostgreSQL cluster that runs one of the following versions is created:
PostgreSQL 14 (revision version 14.9.13.0 or later)
PostgreSQL 11 (revision version 1.1.36 or later)
You can execute one of the following statements to view the revision version of a PolarDB for PostgreSQL cluster:
PostgreSQL 14
SELECT version();
PostgreSQL 11
SHOW polar_version;
Overview
ip4r
is a third-party extension supported by PolarDB for PostgreSQL. It offers data types to store IPv4 or IPv6 addresses. Different from the inet
/cidr
data types offered by PostgreSQL, the ip4r
extension supports index scans when a query uses the >>=
(contains or equals) operator. In addition, the ip4r
extension has the following advantages over the built-in network address types of PostgreSQL:
Less semantic overload: It offers specialized data types for handling a netblock and a particular IP address.
Lower overheads: PostgreSQL uses variable-length data types to store both IPv6 and IPv4 addresses. This leads to large overheads in use cases that involve IPv4 addresses only. The
ip4r
extension offers fixed-length data types tailored for IPv4 or IPv6 addresses.
Data type
ip4r
provides a wide range of data types to store and represent IPv4 and IPv6 addresses:
Data type | Description |
ip4 | A single IPv4 address |
ip4r | An IPv4 netblock |
ip6 | A single IPv6 address |
ip6r | An IPv6 netblock |
ipaddress | A single IPv4 or IPv6 address |
iprange | An IPv4 or IPv6 netblock |
Data types for single IP addresses and type conversion
The following three data types are used to store single IP addresses:
ip4
: Accepts input in the form ofnnn.nnn.nnn.nnn
. It stores an IP address as a 32-bit unsigned integer.ip6
: Accepts input in the form of standard hexadecimal representation for an IPv6 address. It stores an IP address as two 64-bit values.ipaddress
: Accepts input which is valid for eitherip4
orip6
.
The following table describes type conversions for the preceding three types in ip4r
.
ipX
in the table represents any of the preceding three data types.
Source type | Destination type | Syntax |
ipX | text | text(ipX) or ipX::text (explicit) |
text | ipX | ipX(text) or text::ipX (explicit) |
ipX | cidr | cidr(ipX) or ipX::cidr (assignment) |
inet | ipX | ipX(inet) or inet::ipX (assignment) |
ipX | numeric | to_numeric(ipX) or ipX::numeric (explicit) |
numeric | ipX | ipX(numeric) or bigint::ipX (explicit) |
ip4 | bigint | to_bigint(ip4) or ip4::bigint (explicit) |
bigint | ip4 | ip4(bigint) or bigint::ip4 (explicit) |
ip4 | float8 | to_double(ip4) or ip4::float8 (explicit) |
float8 | ip4 | ip4(float8) or float8::ip4 (explicit) |
ipX | varbit | to_bit(ipX) or ipX::varbit (explicit) |
bit(32) | ip4 | ip4(bit) or bit::ip4 (explicit) |
bit(128) | ip6 | ip6(bit) or bit::ip6 (explicit) |
varbit | ipX | ipX(varbit) or varbit::ipX (explicit) |
ipX | bytea | to_bytea(ipX) or ipX::bytea (explicit) |
bytea | ipX | ipX(bytea) or bytea::ipX (explicit) |
ipX | ipXr | ipXr(ipX) or ipX::ipXr (implicit) |
ip4 | ipaddress | ipaddress(ip4) or ip4::ipaddress (implicit) |
ip6 | ipaddress | ipaddress(ip6) or ip6::ipaddress (implicit) |
ipaddress | ip4 | ip4(ipaddress) or ipaddress::ip4 (assignment) |
ipaddress | ip6 | ip6(ipaddress) or ipaddress::ip6 (assignment) |
Data types for netblocks and type conversion
The following three data types are used to store a netblock:
ip4r
: Used to store an IPv4 netblock, such as192.0.2.100–192.0.2.200
. Also accepts input in the form of CIDR blocks such as192.0.2.0/24
, which is equivalent to192.0.2.0–192.0.2.255
.ip6r
: Used to store an IPv6 netblock, such as2001::1234–2001::2000:0000
. Also accepts input in the form of CIDR blocks such as2001::/112
, which is equivalent to2001::–2001::ffff
.iprange
: Accepts input which is valid for eitherip4r
orip6r
.
The following table describes type conversions for the preceding three types in ip4r
.
ipXr
represents any of the above three data types.
Source type | Destination type | Syntax |
ipX | ipXr | ipXr(ipX) or ipX::ipXr (implicit) |
ipXr | text | text(ipXr) or ipXr::text (explicit) |
text | ipXr | ipXr(text) or text::ipXr (explicit) |
ipXr | cidr | cidr(ipXr) or ipXr::cidr (explicit) |
cidr | ipXr | ipXr(cidr) or cidr::ipXr (assignment) |
ipXr | varbit | to_bit(ipXr) or ipXr::varbit (explicit) |
varbit | ip4r | ip4r(varbit) or varbit::ip4r (explicit) |
varbit | ip6r | ip6r(varbit) or varbit::ip6r (explicit) |
Usage
Create the ip4r extension
CREATE EXTENSION ip4r;
Create a test table and import data to the table
CREATE TABLE ipranges (r iprange, r4 ip4r, r6 ip6r);
INSERT INTO ipranges
SELECT r, null, r
FROM (
SELECT ip6r(regexp_replace(ls, E'(....(?!$))', E'\\1:', 'g')::ip6,
regexp_replace(substring(ls FOR n + 1) || substring(us FROM n + 2),
E'(....(?!$))', E'\\1:', 'g')::ip6) AS r
FROM (
SELECT md5(i || ' lower 1') AS ls,
md5(i || ' upper 1') AS us,
(i % 11) + (i/11 % 11) + (i/121 % 11) AS n
FROM generate_series(1,13310) i) s1) s2;
Create a GiST index
CREATE INDEX ipranges_r ON ipranges USING gist (r);
Use the >>= (contains or equals) operator
EXPLAIN (COSTS OFF) SELECT * FROM ipranges WHERE r >>= '5555::' ORDER BY r;
QUERY PLAN
-----------------------------------------------------
Sort
Sort Key: r
-> Bitmap Heap Scan on ipranges
Recheck Cond: (r >>= '5555::'::iprange)
-> Bitmap Index Scan on ipranges_r
Index Cond: (r >>= '5555::'::iprange)
(6 rows)
Remove the extension
DROP EXTENSION ip4r;