This topic describes the background, data types, and usage of the ip4r extension.
Applicability
The following versions of PolarDB for PostgreSQL (Compatible with Oracle) are supported:
Oracle syntax compatibility 2.0 (minor engine version 2.0.14.9.13.0 or later)
Oracle syntax compatibility 1.0 (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, you must upgrade the minor engine version.
Background information
ip4r is a third-party extension supported by PolarDB for PostgreSQL (Compatible with Oracle) that provides data types for storing IPv4 and IPv6 addresses. Unlike PostgreSQL's built-in network data types such as inet/cidr, ip4r supports index scans for the contains operator >>=. In addition, ip4r has the following features compared to the built-in network data types of PostgreSQL:
Clearer semantics: It distinguishes between a network block and a specific IP address within that block.
Lower overhead: PostgreSQL uses variable-length data types to support IPv6 data. This creates significant overhead in scenarios where you only need to store IPv4 data.
ip4ruses fixed-length data types for single addresses.
Data types
ip4r provides a variety of data types for storing and representing 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: The input must be in thennn.nnn.nnn.nnnformat. The data is stored as a 32-bit unsigned integer.ip6: The input must be in the standard hexadecimal representation of an IPv6 address. The data is stored as two 64-bit values.ipaddress: The input must be in either theip4orip6format.
ip4r provides type conversions for these three data types. The rules are as follows:
In the following table, ipX represents one 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 IP address ranges:
ip4r: Stores an IPv4 address range. For example,192.0.2.100-192.0.2.200.192.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.2001::/112is equivalent to2001::-2001::ffff.iprange: The input must be in either theip4rorip6rformat.
ip4r provides type conversions for these three data types. The rules are as follows:
In the following table, ipXr represents one 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;