VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
INET_ATON(). VillageSQL’s INET type provides network functions that make the same query more readable and work for both IPv4 and IPv6.
The Standard Approach: Bitwise Range Checks
For IPv4,INET_ATON() converts an address to an unsigned 32-bit integer. A subnet membership check is a bitwise AND: if (ip & netmask) == network_address, the IP is in the subnet.
BETWEEN approach is readable. The bitwise form is more composable when subnet parameters are variables.
Neither approach works for IPv6 — INET_ATON() only handles IPv4.
With VillageSQL: Network Functions on INET Columns
VillageSQL’svsql_network_address extension provides inet_network(), inet_set_masklen(), and inet_compare() — enough to do subnet containment checks on both IPv4 and IPv6 INET columns.
Subnet containment query
To check whether a stored IP belongs to a subnet, mask the address to the subnet’s prefix length and compare the result to the target network:Range-based containment with inet_compare
An alternative that avoids recomputing the network on every row — useful when you have the broadcast address available:IPv6 subnet queries (same pattern)
The sameinet_network() approach works for IPv6 without any changes:
Networks table pattern
A common use case: anetworks table with authorized CIDRs, and checking whether an incoming IP is in any of them.
Standard vs VillageSQL
| Approach | IPv6 | Readable | No manual calculation |
|---|---|---|---|
BETWEEN INET_ATON() | No | Moderate | Requires computing broadcast manually |
Bitwise AND with INET_ATON() | No | Low | Requires computing netmask manually |
inet_network() + inet_set_masklen() | Yes | High | Functions handle the math |
Frequently Asked Questions
Why doesn’t VillageSQL have a contains operator like PostgreSQL’s <<?
The current version provides functions rather than operators. The inet_network() + inet_set_masklen() pattern covers the same logic. Operator support may come in a future release.
Does the subnet query use the index?
Thecidr_to_string(inet_network(inet_set_masklen(...))) pattern does not use an index scan — it recomputes the network address for every row. For large tables, the inet_compare range approach is more index-friendly since it expresses the query as a range on the ip_address column.
Can I store subnets and query containment at the same time?
Yes. Store the host address in anINET column and the authorized subnet in a CIDR column. Compare them using inet_network(inet_set_masklen(host_ip, inet_masklen(subnet))) = cidr_to_string(subnet).
Troubleshooting
| Problem | Solution |
|---|---|
FUNCTION inet_network does not exist | Run INSTALL EXTENSION vsql_network_address |
| Subnet query returns no rows | Verify @network matches the expanded CIDR string — IPv6 CIDRs use expanded notation |
| Range query includes addresses outside the subnet | Check the broadcast address; for /24 the range is .0 to .255 |
| Mixed IPv4/IPv6 column returns wrong results | IPv4 and IPv6 addresses don’t overlap — the query returns correct results per-family |

