This topic describes the background, data types, and usage of the ip4r extension.
Applicability
The following versions of PolarDB for PostgreSQL are supported:
PostgreSQL 17 (minor engine version 2.0.17.6.4.0 or later)
PostgreSQL 16 (minor engine version 2.0.16.9.9.0 or later)
PostgreSQL 15 (minor engine version 2.0.15.14.6.0 or later)
PostgreSQL 14 (minor engine version 2.0.14.9.13.0 or later)
PostgreSQL 11 (minor engine version 2.0.11.9.36.0 or later)
You can view the minor engine version in the console or by running the SHOW polardb_version; statement. If your minor engine version does not meet the requirements, upgrade the minor engine version.
Background information
ip4r is a third-party extension supported by PolarDB for PostgreSQL and . It provides data types for storing IPv4 and IPv6 addresses. Unlike the built-in inet and cidr data types in PostgreSQL, ip4r supports index scans for the contains operator >>=. In addition, ip4r has the following advantages over the built-in network data types of PostgreSQL:
Clearer semantics: It distinguishes between a network block and a specific IP address within a network block.
Lower overhead: PostgreSQL uses variable-length data types to store IPv6 data. This creates significant overhead when you need to store only IPv4 data. In contrast,
ip4ruses fixed-length data types for single addresses.
Data types
ip4r provides a variety of data types to store and represent IPv4 or IPv6 data:
Data type | Description |
ip4 | A single IPv4 address. |
ip4r | An arbitrary IPv4 address range. |
ip6 | A single IPv6 address. |
ip6r | An arbitrary IPv6 address range. |
ipaddress | A single IPv4 or IPv6 address. |
iprange | An arbitrary IPv4 or IPv6 address range. |
Single-address data types and type conversions
The following three data types are used to store single IP addresses:
ip4: Accepts input in thennn.nnn.nnn.nnnformat. The data is stored as a 32-bit unsigned integer.ip6: Accepts input in the standard hexadecimal format for an IPv6 address. The data is stored as two 64-bit values.ipaddress: Accepts input in either theip4orip6format.
For these three data types, ip4r provides the following type conversion rules:
In the following table, ipX represents any of the three data types described above.
Source type | Target type | Format |
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) |
Address range data types and type conversions
The following three data types are used to store a range of IP addresses:
ip4r: Stores an IPv4 address range. For example,192.0.2.100-192.0.2.200. The range192.0.2.0/24is equivalent to192.0.2.0-192.0.2.255.ip6r: Stores an IPv6 address range. For example,2001::1234-2001::2000:0000. The range2001::/112is equivalent to2001::-2001::ffff.iprange: Accepts input in either theip4rorip6rformat.
For these three data types, ip4r provides the following type conversion rules:
In the following table, ipXr represents any of the three data types described above.
Source type | Target type | Format |
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 extension
CREATE EXTENSION ip4r;Create a test table and import data
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 operator
EXPLAIN (COSTS OFF) SELECT * FROM ipranges WHERE r >>= '5555::' ORDER BY r;The following result is returned:
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)Uninstall the extension
DROP EXTENSION ip4r;