メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
IP アドレスが特定のサブネットに含まれる行をすべて見つけるには、数値化した IP の値を範囲と比較する必要があります。MySQL の標準的なアプローチは、INET_ATON() を使ったビット演算です。VillageSQL の INET 型はネットワーク関数を提供し、同じクエリをより読みやすくし、IPv4 と IPv6 の両方で機能させます。

標準的なアプローチ: ビット単位の範囲チェック

IPv4 の場合、INET_ATON() はアドレスを符号なし 32 ビット整数に変換します。サブネットへの所属チェックはビット単位の AND です。(ip & netmask) == network_address であれば、その IP はサブネット内にあります。
どちらも IPv4 では機能します。BETWEEN のアプローチは読みやすいです。ビット演算の形式は、サブネットのパラメータが変数である場合に組み合わせやすくなります。 どちらのアプローチも IPv6 では機能しません。INET_ATON() は IPv4 しか扱いません。

VillageSQL の場合: INET 列に対するネットワーク関数

VillageSQL の vsql_network_address 拡張機能は、「このアドレスはあのサブネットの中にあるか」に直接答える包含述語、つまり inet_contained_by()、inet_contains()、および inet_overlaps() を提供します。加えて、チェックを手で組み立てるための inet_network()、inet_set_masklen()、および inet_compare() も提供します。これらはすべて、IPv4 と IPv6 の両方の INET 列で機能します。

サブネットの包含クエリ

保存された IP が特定のサブネットに属するかを確認するには、アドレスをサブネットのプレフィックス長でマスクし、その結果を対象のネットワークと比較します。
サブネットを変数から受け取るパラメータ化した形式は次のとおりです。

包含述語

この拡張機能は、PostgreSQL の 5 つの包含述語を関数として提供します。これらは 2 つの INET 値を受け取り、1、0、または NULL を返します。 上のサブネットクエリは、1 回の呼び出しになります。
比較されるのは各値のネットワーク部分だけで、2 つのプレフィックス長のうち短いほうまでが対象です。 そのため 192.168.1.5/24 と 192.168.1.9/24 は同じネットワークであり、厳密な形式はこれらに対して 0 を返し、_or_equals の形式は 1 を返します。 ファミリーの異なる 2 つのアドレスが一致することはありません。IPv4 の値を IPv6 の値と比較すると、 エラーを発生させるのではなく 0 を返します。これは PostgreSQL と同じです。 両方の引数は INET でなければなりません。CIDR 値は強制変換されません。
上の例のように、代わりにサブネットに inet_from_string() を使ってください。これらの 関数は vsql_network_address 0.0.5 で追加されました。

inet_compare による範囲ベースの包含

行ごとにネットワークを再計算しない代替手段です。ブロードキャストアドレスが分かっている場合に便利です。

IPv6 のサブネットクエリ(同じパターン)

同じ inet_network() のアプローチが、何も変更せずに IPv6 でも機能します。

ネットワークテーブルのパターン

よくある用途です。許可された CIDR を持つ networks テーブルがあり、受信した IP がそのいずれかに含まれるかを確認します。

標準と VillageSQL の比較

よくある質問

VillageSQL には PostgreSQL の << 包含演算子がありますか?

その動作は、演算子ではなく関数として存在します。<< には inet_contained_by()、>> には inet_contains()、<<= と >>= には _or_equals の各バリアント、&& には inet_overlaps() です。包含述語を参照してください。

サブネットクエリはインデックスを使いますか?

cidr_to_string(inet_network(inet_set_masklen(...))) のパターンはインデックススキャンを使いません。すべての行に対してネットワークアドレスを再計算します。大きなテーブルでは、inet_compare の範囲アプローチのほうがインデックスを活用しやすくなります。クエリを ip_address 列に対する範囲として表現するためです。

サブネットを保存して、同時に包含をクエリできますか?

はい。ホストアドレスとサブネットの両方を INET 列に保存し、inet_contained_by(host_ip, subnet) で比較します。サブネットが CIDR 列にある場合は、先に変換してください。包含述語は両側に INET を取り、CIDR を強制変換しません。

トラブルシューティング

関連項目