All Products
Search
Document Center

PolarDB:ip4r (network address storage)

Last Updated:Mar 28, 2026

The ip4r extension provides optimized data types for storing and querying IPv4 and IPv6 addresses in PolarDB for PostgreSQL.

Applicability

The following versions of PolarDB for PostgreSQL support ip4r:

PostgreSQL versionMinimum minor engine version
PostgreSQL 172.0.17.6.4.0
PostgreSQL 162.0.16.9.9.0
PostgreSQL 152.0.15.14.6.0
PostgreSQL 142.0.14.9.13.0
PostgreSQL 112.0.11.9.36.0
View the minor engine version in the console or by running SHOW polardb_version;. If your minor engine version does not meet the requirements, upgrade the minor engine version.

Why use ip4r

PostgreSQL's built-in inet and cidr types cover basic network address storage, but ip4r addresses two limitations that matter for production workloads:

Index support for containment queries. The built-in types have poor support for queries of the form column >>= parameter—finding which IP address ranges contain a given IP address. ip4r uses GiST indexes to make these containment lookups efficient.

Clearer semantics and lower overhead. The built-in inet type combines two distinct concepts: a network block and a specific IP address within that block. ip4r separates these clearly. It also uses fixed-length data types for single IP addresses, reducing the overhead that variable-length types impose when you only need to store IPv4 data.

Data types

ip4r provides six data types:

Data typeDescription
ip4A single IPv4 address
ip4rAn arbitrary IPv4 address range
ip6A single IPv6 address
ip6rAn arbitrary IPv6 address range
ipaddressA single IPv4 or IPv6 address
iprangeAn arbitrary IPv4 or IPv6 address range

Single-address types

Three types store a single IP address:

  • ip4: Accepts input in nnn.nnn.nnn.nnn format. Stored as a 32-bit unsigned integer.

  • ip6: Accepts input in standard hexadecimal format. Stored as two 64-bit values.

  • ipaddress: Accepts either ip4 or ip6 format.

In the conversion table below, ipX represents any of these three types.

Source typeTarget typeFormat
ipXtexttext(ipX) or ipX::text (explicit)
textipXipX(text) or text::ipX (explicit)
ipXcidrcidr(ipX) or ipX::cidr (assignment)
inetipXipX(inet) or inet::ipX (assignment)
ipXnumericto_numeric(ipX) or ipX::numeric (explicit)
numericipXipX(numeric) or bigint::ipX (explicit)
ip4bigintto_bigint(ip4) or ip4::bigint (explicit)
bigintip4ip4(bigint) or bigint::ip4 (explicit)
ip4float8to_double(ip4) or ip4::float8 (explicit)
float8ip4ip4(float8) or float8::ip4 (explicit)
ipXvarbitto_bit(ipX) or ipX::varbit (explicit)
bit(32)ip4ip4(bit) or bit::ip4 (explicit)
bit(128)ip6ip6(bit) or bit::ip6 (explicit)
varbitipXipX(varbit) or varbit::ipX (explicit)
ipXbyteato_bytea(ipX) or ipX::bytea (explicit)
byteaipXipX(bytea) or bytea::ipX (explicit)
ipXipXripXr(ipX) or ipX::ipXr (implicit)
ip4ipaddressipaddress(ip4) or ip4::ipaddress (implicit)
ip6ipaddressipaddress(ip6) or ip6::ipaddress (implicit)
ipaddressip4ip4(ipaddress) or ipaddress::ip4 (assignment)
ipaddressip6ip6(ipaddress) or ipaddress::ip6 (assignment)

Address range types

Three types store a range of IP addresses:

  • ip4r: Stores an IPv4 address range. For example, 192.0.2.100-192.0.2.200. The CIDR notation 192.0.2.0/24 is equivalent to 192.0.2.0-192.0.2.255.

  • ip6r: Stores an IPv6 address range. For example, 2001::1234-2001::2000:0000. The CIDR notation 2001::/112 is equivalent to 2001::-2001::ffff.

  • iprange: Accepts either ip4r or ip6r format.

In the conversion table below, ipXr represents any of these three types.

Source typeTarget typeFormat
ipXipXripXr(ipX) or ipX::ipXr (implicit)
ipXrtexttext(ipXr) or ipXr::text (explicit)
textipXripXr(text) or text::ipXr (explicit)
ipXrcidrcidr(ipXr) or ipXr::cidr (explicit)
cidripXripXr(cidr) or cidr::ipXr (assignment)
ipXrvarbitto_bit(ipXr) or ipXr::varbit (explicit)
varbitip4rip4r(varbit) or varbit::ip4r (explicit)
varbitip6rip6r(varbit) or varbit::ip6r (explicit)

Usage

Install the extension

CREATE EXTENSION ip4r;

Create a table and load test 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);

Query with the contains operator

The following query uses the GiST index to find all ranges that contain the address 5555:::

EXPLAIN (COSTS OFF) SELECT * FROM ipranges WHERE r >>= '5555::' ORDER BY r;

The query plan confirms index use:

                     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;