PostgreSQL Network Veri Tipleri

PostgreSQL Network Veri Tipleri

Veritabanlarımızda IPv4, IPv6 ve MAC bilgilerini depolamak için network veri tipleri daha elverişlidir. Çünkü veri tipi network veri tiplerinden biri olarak tanımlanan sütunlara, yalnızca buna uygun veri girişi yapılabilir. Böylece, ağ adreslerini depolarken, veri girişinde verinin uygunluğunu kontrol etmemiz kolaylaşır.

4 adet network veri tipi vardır:
  • INET
  • CIDR
  • MACADDR
  • MACADDR8
Bunlara ek olarak 1 adet de uzantı(extension) vardır:
  •  IP4R
Hepsini ayrı ayrı inceleyelim:

1. INET

Bu veri tipi, IPv4 ve IPv6 host adreslerini ve isteğe bağlı olarak alt ağını (subnet) tutmak için kullanılmaktadır. Alt ağ, host adresindeki ağ adresi bitlerinin sayısıyla temsil edilir. Eğer ağ maskesi 32 ve adres IPv4 ise, değer subnet değildir, sadece tek bir host'u gösterir. IPv6'da ise adres uzunluğu 128 bittir. Bu sayede, 128 bit bir host adresi belirtebilir.
Bir örnekle INET veri tipini inceleyelim:

Öncelikle inet_ornek isimli, inet veri tipli bir tablo oluşturalım:
CREATE TABLE inet_ornek (ip inet);

İçerisine ip adresi ve ağ maskesi olan bir değer girelim:
INSERT INTO inet_ornek VALUES ('192.168.24.0/24');

Bu örnekte de ağ maskesi olmayan bir ip adresi ekleyelim:
 INSERT INTO inet_ornek VALUES ('192.168.24.0');
Bu örnekte de random bir ağ maskesine sahip bir ip değeri girelim:
INSERT INTO inet_ornek VALUES ('192.168/8');

Bu üç verimiz de tablomuza başarılı bir şekilde eklenmiştir. Sonucu SELECT sorgusu ile görebiliriz:
SELECT * FROM inet_ornek;
       ip
-----------------
 192.168.24.0/24
 192.168.24.0
 192.168.0.0/8
(3 rows)

Bir örnek ile de ağ adresi olmadan bir ip adresi eklemeyi deneyelim:

INSERT INTO inet_ornek VALUES ('192.10');
ERROR:  invalid input syntax for type inet: "192.10"
LINE 1: INSERT INTO inet_ornek VALUES ('192.10');
                                       ^
Başka bir örnek ile de host adresine izin verilen bit sayısını aşan bir ağ maskesi girmeyi deneyelim:

INSERT INTO inet_ornek VALUES ('192.24/24');
ERROR:  invalid input syntax for type inet: "192.24/24"
LINE 1: INSERT INTO inet_ornek VALUES ('192.24/24');
                                       ^
Bu iki örnek, INET veri tipinin kullanılması tavsiye edilmeyen durumlardır. Bir ağı temsil eden IPv4 ve IPv6 adreslerini tutuyorsak CIDR veri tipinin kullanılması daha uygun olabilir.

2. CIDR

Bu veri tipi, IPv4 ve IPv6 ağ özelliklerini tutar. Veri giriş ve çıkışları, Sınıfsız İnternet Alan Adı Yönlendirme ( Classless Internet Domain Routing) kurallarına göre format alır.
INET'den farkı, veri girişi sırasında ağ maskesinin sağ tarafında sınıf olmayan bitlerin olup olmadığını kontrol etmesidir. Eğer varsa, PostgreSQL bize hata mesajı döndürecek ve hiçbir değer eklenmeyecektir. Ayrıca, ağ maskesi olmayan veriler girersek, otomatik olarak ağ maskesi oluşturur.
Bir örnekle cidr veri tipini inceleyelim:

Öncelikle cidr_ornek isimle, cidr veri tipli bir tablo oluşturalım:
CREATE TABLE cidr_ornek (ip cidr);

Ağ maskesi ile birlikte bir ip adresi girelim:
INSERT INTO cidr_ornek VALUES ('128.1.2/24');

Şimdi de, ağ maskesine sahip olmayan veriler girelim:
 INSERT INTO cidr_ornek VALUES ('192.168.10.40');
INSERT INTO cidr_ornek VALUES ('192.168');

PostgreSQL bu verileri de tablomuza ekleyeceki, ağ maskelerini de ip adreslerine göre otomatik oluşturacaktır.

Eğer, girilen ip adresine uygun olmayan bir ağ maskesi girmeyi denersek, PostgreSQL bize ağaşıdaki gibi hata verecek ve veriyi tablomuza eklemeyecektir:
INSERT INTO cidr_ornek VALUES ('128.1.2/16');

ERROR:  invalid cidr value: "128.1.2/16"
LINE 1: INSERT INTO cidr_ornek VALUES ('128.1.2/16');
                                       ^
Son olarak SELECT sorgusu ile tablomuzu görelim:
SELECT * FROM cidr_ornek ;

        ip
------------------
 128.1.2.0/24
 192.168.10.40/32
 192.168.1.0/24
 10.0.0.0/8
(4 rows)

Yukarıda bahsettiğim gibi, ağ maskesi olmayanlara otomatik olarak ağ maskesi eklendi, ağ maskesi girilen ip adresine uygun olmayanlar tablomuza eklenmedi.

INET ile CIDR arasındaki fark nedir?

Bu iki veri tipi aynı işleve sahip gibi görünse de, aralarında önemli bir fark vardır. INET, ağ maskesinin sağ tarafındaki sıfır olmayan bitleri kabul eder, fakat CIDR bunu kabul etmez. 
Örnek:

İlk örnekte INET veri tipine sahip sütuna 192.168.0.5/24 değerini ekleyebiliyoruz, fakat CIDR veri tipine sahip sütun bize hata veriyor.

INSERT INTO inet_ornek VALUES ('192.168.0.5/24');
INSERT 0 1

INSERT INTO cidr_ornek VALUES ('192.168.0.5/24');
ERROR:  invalid cidr value: "192.168.0.1/24"
LINE 1: INSERT INTO cidr_ornek VALUES ('192.168.0.5/24');
                                       ^
DETAIL:  Value has bits set to right of mask.

3. MACADDR

Bu veri tipi, MAC adreslerini tutmak için kullanılır. Veri tipi macaddr olan bir sütuna veri girmenin birden fazla örneği vardır. Bir örnekle hepsini görelim:

Öncelikle ismi macaddr_ornek, veri tipi macaddr olan bir tablo oluşturalım:
CREATE TABLE macaddr_ornek (mac_adresi macaddr);

Aşağıdaki örneklerde gördüğümüz tüm formatlardaki veriyi bu veri tipi kabul eder.

INSERT INTO macaddr_ornek VALUES ('58:6C:74:12:24:12');
INSERT INTO macaddr_ornek VALUES ('58-6C-74-12-24-12');
INSERT INTO macaddr_ornek VALUES ('586C74:122412');
INSERT INTO macaddr_ornek VALUES ('586C74-122412');
INSERT INTO macaddr_ornek VALUES ('586C.7412.2412');
INSERT INTO macaddr_ornek VALUES ('586C-7412-2412');
INSERT INTO macaddr_ornek VALUES ('586C74122412');

Fakat, veriyi hangi formatta girersek girelim, çıktısı ilk örnekteki gibi olacaktır. SELECT sorgusu ile bunu görebiliriz:
SELECT * FROM macadrr_ornek ;
    mac_adresi
-------------------
 58:6c:74:12:24:12
 58:6c:74:12:24:12
 58:6c:74:12:24:12
 58:6c:74:12:24:12
 58:6c:74:12:24:12
 58:6c:74:12:24:12
 58:6c:74:12:24:12
(7 rows)

4. MACADDR8:

Bu veri tipi, MAC adresini EUI-64 formatına göre tutar. Bu veri tipi, 6 bit ve 8 bit uzunluğundaki MAC adreslerinin iki türünü de kabul eder, fakat ikisini de 8 bit olarak tutar. 
Örnek:

Öncelikle, macaddr8_ornek isimli, macaddr8 veri tipli bir tablo oluşturalım:

CREATE TABLE macaddr8_ornek (mac_adresi macaddr8);

Bu veri tipinde de, macaddr veri tipinde olduğu gibi, veri girişinin birçok formatı vardır. Aşağıdaki örneklerin hepsi, bu veri tipinin 8 bitlik veri giriş örnekleridir:

INSERT INTO macaddr8_ornek VALUES ('06:00:2b:58:7d:03:02:10');
INSERT INTO macaddr8_ornek VALUES ('06-00-2b-58-7d-03-02-10');
INSERT INTO macaddr8_ornek VALUES ('06002b:587d030210');
INSERT INTO macaddr8_ornek VALUES ('06002b-587d030210');
INSERT INTO macaddr8_ornek VALUES ('0600.2b58.7d03.0210');
INSERT INTO macaddr8_ornek VALUES ('0600-2b58-7d03-0210');
INSERT INTO macaddr8_ornek VALUES ('06002b58:7d030210');
INSERT INTO macaddr8_ornek VALUES ('06002b587d030210');

Bu örnekler de, 6 bitlik veri giriş örnekleridir:

INSERT INTO macaddr8_ornek VALUES ('06:00:2b:58:7d:03');
INSERT INTO macaddr8_ornek VALUES ('06-00-2b-58-7d-03');
INSERT INTO macaddr8_ornek VALUES ('06002b:587d03');
INSERT INTO macaddr8_ornek VALUES ('06002b-587d03');
INSERT INTO macaddr8_ornek VALUES ('0600.2b58.7d03');
INSERT INTO macaddr8_ornek VALUES ('0600-2b58-7d03');
INSERT INTO macaddr8_ornek VALUES ('06002b:587d03');
INSERT INTO macaddr8_ornek VALUES ('06002b587d03');

6 bitlik veri girersek, PostgreSQL bu veriyi 8 bit'e tamamlamak için ne yapar?

Böyle bir durumda, 4. ve 5. bitlerin olduğu yerlere sırasıyle 'ff' ve 'ff' değerleri otomatik olarak, PostgreSQL tarafından girilir. SELECT sorgusu ile sonucu görelim:
 SELECT * FROM macaddr8_ornek ;
       mac_adresi
-------------------------
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:58:7d:03:02:10
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
 06:00:2b:ff:fe:58:7d:03
(17 rows)

MACADDR ve MACADDR8  arasındaki fark nedir?

MACADDR veri tipi sadece 6 bitlik (12 karakterlik) MAC adreslerini tutar. MACADDR8 veri tipi ise, bunun yanında 8 bitlik(16 karakterlik) MAC adreslerini de tutar. Ayrıca, 6 bitlik verileri 8 bit'e çevirir ve o şekilde tutar.

CIDR ve INET veri tiplerine ek olarak bir uzantı: IP4R

IP4R nedir?
IP4R, tablolarda IPv4 ve IPv6 adreslerini tutmayı sağlayani 6 farklı veri tipini destekleyen bir PostgreSQL uzantısıdır. Henüz resmi bir uzantı olmadığı için kullanmadan önce sunucunuza kurmanız gerekmektedir.

Neden IP4R kullanılır?
Veri tabanlarında, ağ adresi tutmak için halihazırda INET ve CIDR olmak üzere 2 adet veri tipi vardır. Fakat bu 2 veri tipi, kullanıcıların tüm ihtiyaçlarını karşılamadığı için, IP4R extention'ı geliştirildi. Örneğin, CIDR ve INET veri tipleri, dizinde arama yapmak için yeterli desteğe sahip değildir.

IP4R'nin desteklediği veri tipleri:
-ip4: tek bir IPv4 adresi
-ip4r: isteğe bağlı IPv4 adresleri aralığı
-ip6: tek bir IPv6 adresi
-ip6r: isteğe bağlı IPv6 adresleri aralığı
-ipaddress: tek bir IPv4 veya IPv6 adresi
-iprange: isteğe bağlı bir IPv4 aralığı veya IPv6 adresi

IP4R'nin en yaygın olan operatörleri:
 Operatör     | Açıklama
------------|-------------------------------------------
  a = b            | kesinlikle eşit
  a <> b          | kesinlikle eşit olmayan
  a >>= b        | a, b'yi kapsar veya b'ye eşittir
  a >> b          | a kesinlikle b'yi içerir
  a <<= b        | a, b'nin içindedir ya da b'ye eşittir
  a << b          | a kesinlikle b'nin içindedir
  a && b         | a ve b'nin çakışması


IP4R'nin Kurulumu: 
Aşağıdaki komut, sunucumuza IP4R'nin kurulum komutudur:
yum install ip4r10
Not:  Her dağıtım için bu komut farklılık göstermektedir. Yukarıdaki komut Centos için geçerlidir.

Bir örnek ile IP4R uzantısının temel kullanımını inceleyelim:

Öncelikle, IP4R uzantısını oluşturalım:
CREATE EXTENTION ip4r;

Dah sonra, IP adreslerini tutacağımız sütununun veri tipi IP4R olan bir tablo oluşturalım:
CREATE TABLE ip_range (range ip4r, description text);

Yalnızca IP'leri tutacağımız sütunun indeksini oluşturalım:
CREATE INDEX ip_range_idx ON ip_range(range);

Ve bu sütuna veriler girelim:
INSERT INTO ip_range(range) VALUES ('10.15.26.3');
INSERT INTO ip_range(range) VALUES ('102.15.2.45');
INSERT INTO ip_range(range) VALUES ('10.105.42.2');
INSERT INTO ip_range(range) VALUES ('20.102.2.0');

Tablomuz aşağıdaki gibidir:
 SELECT * FROM ip_range;
    range    | description
-------------+-------------
 10.15.26.3  |
 102.15.2.45 |
 10.105.42.2 |
 20.102.2.0  |

(4 rows)

Bu örnekte de 'gist' indeksinin kullanımını görelim:

Sütunlarından biri ip4r veri tipli olan bir tablo oluşturalım:
CREATE TABLE ip_range_2 (range ip4r, description text);

'range' isimli sütunun indeksini oluşturalım. Bu işlemi yaparken 'gist' indeksini kullanalım:
CREATE INDEX range_idx ON ip_range_2 USING gist(range);

Tablomuza bazı veriler girelim:
INSERT INTO ip_range_2(range) VALUES ('127.0.0.1');
INSERT INTO ip_range_2(range) VALUES ('10.0.0.0');
INSERT INTO ip_range_2(range) VALUES ('10.0.0.0/8');
INSERT INTO ip_range_2(range) VALUES ('188.165.145.2');
INSERT INTO ip_range_2(range) VALUES ('18.165.145.2');

INSERT INTO ip_range_2(range) VALUES ('23.5.56.12');

Tablomuzun son hali aşağıdaki gibidir:

 SELECT * FROM ip_range_2;
     range     | description
---------------+-------------
 127.0.0.1     |
 10.0.0.0      |
 10.0.0.0/8    |
 188.165.145.2 |
 18.165.145.2  |
 23.5.56.12    |
(6 rows)

İlk tablomuzdaki belirli bir aralıkta olan tüm IP'leri, aşağıdaki komutla görebiliriz:

SELECT * FROM ip_range WHERE range BETWEEN '10.0.0.0' AND '10.255.255.255';
    range     | description
--------------+-------------
 10.15.26.3   |
 10.105.42.2  |
(2 rows)

Bu örnekte de ilk tablomuzdaki, IP'si '10.15.26.3' dışındakileri görebiliriz:

SELECT * FROM ip_range WHERE range <> '10.15.26.3';
    range    | description
-------------+-------------
 102.15.2.45 |
 10.105.42.2 |
 20.102.2.0  |
(3 rows)

Bu örnekte de ikinci tablomuzdaki IP'si '18.165.145.2' olan satırımızı görebiliriz:

SELECT * FROM ip_ranges WHERE range <<= '18.165.145.2';
    range     | description
--------------+-------------
 18.165.145.2 |
(1 row)

Yorumlar