PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Normalisasi unicode di PostgreSQL 13

Kesetaraan Unicode

Unicode adalah binatang yang rumit. Salah satu dari banyak fitur anehnya adalah bahwa urutan codepoint yang berbeda bisa sama. Ini tidak terjadi dalam pengkodean lama. Dalam LATIN1, misalnya, satu-satunya yang sama dengan 'a' adalah 'a' dan satu-satunya yang sama dengan 'ä' adalah ''. Namun, dalam Unicode, karakter dengan tanda diakritik seringkali (tergantung pada karakter tertentu) dikodekan dengan cara yang berbeda:baik sebagai karakter yang telah dibuat sebelumnya, seperti yang dilakukan dalam pengkodean lama seperti LATIN1, atau didekomposisi, yang terdiri dari karakter dasar 'a ' diikuti oleh tanda diakritik di sini. Ini disebut kesetaraan kanonik . Keuntungan memiliki kedua opsi ini adalah Anda dapat, di satu sisi, dengan mudah mengonversi karakter dari pengkodean lama dan, di sisi lain, tidak perlu menambahkan setiap kombinasi aksen ke Unicode sebagai karakter terpisah. Tetapi skema ini mempersulit perangkat lunak yang menggunakan Unicode.

Selama Anda hanya melihat karakter yang dihasilkan, seperti di browser, Anda seharusnya tidak melihat perbedaan dan ini tidak masalah bagi Anda. Namun, dalam sistem basis data di mana pencarian dan pengurutan string merupakan fungsi fundamental dan kinerja kritis, segalanya bisa menjadi rumit.

Pertama, perpustakaan susunan yang digunakan perlu menyadari hal ini. Namun, sebagian besar pustaka sistem C termasuk glibc tidak. Jadi di glibc, ketika Anda mencari 'ä', Anda tidak akan menemukan ''. Lihat apa yang saya lakukan di sana? Yang kedua dikodekan secara berbeda tetapi mungkin terlihat sama untuk Anda baca. (Setidaknya begitulah cara saya memasukkannya. Mungkin telah diubah di suatu tempat di sepanjang jalan ke browser Anda.) Membingungkan. Jika Anda menggunakan ICU untuk pemeriksaan, maka ini berfungsi dan didukung sepenuhnya.

Kedua, ketika PostgreSQL membandingkan string untuk kesetaraan, itu hanya membandingkan byte, itu tidak mempertimbangkan kemungkinan bahwa string yang sama dapat direpresentasikan dengan cara yang berbeda. Ini secara teknis salah saat menggunakan Unicode, tetapi ini adalah pengoptimalan kinerja yang diperlukan. Untuk mengatasinya, Anda dapat menggunakan pengumpulan nondeterministik , sebuah fitur yang diperkenalkan di PostgreSQL 12. Sebuah susunan yang dideklarasikan seperti itu tidak bandingkan saja bytenya tetapi akan melakukan pra-pemrosesan yang diperlukan untuk dapat membandingkan atau hash string yang mungkin dikodekan dengan cara yang berbeda. Contoh:

CREATE COLLATION ndcoll (provider = icu, locale = 'und', deterministic = false);

Formulir normalisasi

Jadi, meskipun ada berbagai cara valid yang berbeda untuk menyandikan karakter Unicode tertentu, terkadang berguna untuk mengubah semuanya menjadi bentuk yang konsisten. Ini disebut normalisasi . Ada dua bentuk normalisasi :sepenuhnya tersusun , artinya kami mengonversi semua urutan codepoint ke karakter yang telah dibuat sebelumnya sebanyak mungkin, dan terurai sepenuhnya , artinya kami mengonversi semua titik kode ke bagian komponennya (huruf plus aksen) sebanyak mungkin. Dalam terminologi Unicode, bentuk-bentuk ini masing-masing dikenal sebagai NFC dan NFD. Ada beberapa detail lebih lanjut untuk ini, seperti menempatkan semua karakter yang digabungkan ke dalam urutan kanonik, tetapi itulah ide umumnya. Intinya adalah, ketika Anda mengubah string Unicode menjadi salah satu bentuk normalisasi, maka Anda dapat membandingkan atau meng-hash-nya bytewise tanpa harus khawatir tentang varian encoding. Yang mana yang Anda gunakan tidak masalah, selama seluruh sistem menyetujuinya.

Dalam praktiknya, sebagian besar dunia menggunakan NFC. Selain itu, banyak sistem yang rusak karena tidak menangani Unicode non-NFC dengan benar, termasuk sebagian besar fasilitas pengumpulan pustaka C, dan bahkan PostgreSQL secara default, seperti yang disebutkan di atas. Jadi memastikan bahwa semua Unicode dikonversi ke NFC adalah cara yang baik untuk memastikan interoperabilitas yang lebih baik.

Normalisasi di PostgreSQL

PostgreSQL 13 sekarang berisi dua fasilitas baru untuk menangani normalisasi Unicode:fungsi untuk menguji normalisasi, dan satu untuk mengubah ke bentuk normalisasi. Misalnya:

SELECT 'foo' IS NFC NORMALIZED;
SELECT 'foo' IS NFD NORMALIZED;
SELECT 'foo' IS NORMALIZED;  -- NFC is the default

SELECT NORMALIZE('foo', NFC);
SELECT NORMALIZE('foo', NFD);
SELECT NORMALIZE('foo');  -- NFC is the default

(Sintaksnya ditentukan dalam standar SQL.)

Salah satu opsi adalah menggunakan ini di domain, misalnya:

CREATE DOMAIN norm_text AS text CHECK (VALUE IS NORMALIZED);

Perhatikan bahwa normalisasi teks arbitrer tidak sepenuhnya murah. Jadi terapkan ini dengan bijaksana dan hanya di tempat yang benar-benar penting.

Perhatikan juga bahwa normalisasi tidak tertutup dalam rangkaian. Itu berarti bahwa menambahkan dua string yang dinormalisasi tidak selalu menghasilkan string yang dinormalisasi. Jadi, bahkan jika Anda menerapkan fungsi-fungsi ini dengan hati-hati dan juga memeriksa bahwa sistem Anda hanya menggunakan string yang dinormalisasi, mereka masih dapat "menyerbu" selama operasi yang sah. Jadi hanya dengan berasumsi bahwa string yang tidak dinormalisasi tidak dapat terjadi akan gagal; masalah ini harus ditangani dengan benar.

Karakter kompatibilitas

Ada kasus penggunaan lain untuk normalisasi. Unicode berisi beberapa bentuk alternatif huruf dan karakter lain, untuk berbagai tujuan warisan dan kompatibilitas. Misalnya, Anda dapat menulis Fraktur:

SELECT '𝔰𝔬𝔪𝔢𝔫𝔞𝔪𝔢';

Sekarang bayangkan aplikasi Anda memberikan nama pengguna atau pengidentifikasi lainnya, dan ada pengguna bernama 'somename' dan satu lagi bernama '𝔰𝔬𝔪𝔢𝔫𝔞𝔪𝔢' . Ini setidaknya akan membingungkan, tetapi mungkin merupakan risiko keamanan. Memanfaatkan kesamaan seperti itu sering digunakan dalam serangan phishing, URL palsu, dan masalah serupa. Jadi Unicode berisi dua bentuk normalisasi tambahan yang menyelesaikan kesamaan ini dan mengubah bentuk alternatif tersebut menjadi huruf dasar kanonik. Bentuk-bentuk ini disebut NFKC dan NFKD. Mereka sebaliknya sama seperti NFC dan NFD, masing-masing. Misalnya:

=> select normalize('𝔰𝔬𝔪𝔢𝔫𝔞𝔪𝔢', nfkc);
 normalize
-----------
 somename

Sekali lagi, menggunakan batasan centang mungkin sebagai bagian dari domain dapat bermanfaat:

CREATE DOMAIN username AS text CHECK (VALUE IS NFKC NORMALIZED OR VALUE IS NFKD NORMALIZED);

(Penormalan yang sebenarnya mungkin harus dilakukan di antarmuka antarmuka pengguna.)

Lihat juga RFC 3454 untuk penanganan string untuk mengatasi masalah tersebut.

Ringkasan

Masalah kesetaraan Unicode sering diabaikan tanpa konsekuensi. Dalam banyak konteks, sebagian besar data dalam bentuk NFC, jadi tidak ada masalah yang muncul. Namun, mengabaikan masalah ini dapat menyebabkan perilaku aneh, data yang tampaknya hilang, dan dalam beberapa situasi berisiko keamanan. Jadi kesadaran akan masalah ini penting bagi perancang basis data, dan alat yang dijelaskan dalam artikel ini dapat digunakan untuk menanganinya.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara memilih id dengan grup tanggal maksimum berdasarkan kategori di PostgreSQL?

  2. Bagaimana cara menandai nr baris tertentu dalam tabel pada akses bersamaan

  3. DAPATKAN DIAGNOSTIK dengan pernyataan COPY dalam fungsi Pl/pgsql

  4. PostgreSQL 12:Kunci Asing dan Tabel yang Dipartisi

  5. PostgreSQL 8.4 memberikan hak istimewa DML di semua tabel ke sebuah peran