Programmering

MySQL – mangel på integritet

3. oktober 2009 · 1 Kommentar

MySQL gjør mye rart. Her har vi en ganske normal tabell, med kolonner som krever en verdi og med kolonner av forskjellige datatyper. Fire av kolonnene i tabellen kan ta default verdier, resten kan det ikke.


mysql> DESC user_status;
+-------------------+--------------+------+-----+---------+-------+
| Field             | Type         | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+-------+
| uid               | int(10)      | NO   | PRI | NULL    |       |
| verified          | tinyint(1)   | NO   |     | 0       |       |
| registered_nick   | tinyint(1)   | NO   |     | 0       |       |
| first_time        | tinyint(1)   | NO   |     | 1       |       |
| registration_date | datetime     | NO   |     | NULL    |       |
| verification_code | int(10)      | NO   |     | NULL    |       |
| nick              | varchar(32)  | NO   |     | NULL    |       |
| active            | tinyint(1)   | NO   |     | 1       |       |
| ban_reason        | varchar(255) | NO   |     | NULL    |       |
| logincount        | int(11)      | NO   |     | NULL    |       |
| lastlogin         | datetime     | NO   |     | NULL    |       |
+-------------------+--------------+------+-----+---------+-------+

Så legger vi inn en rad i tabellen. Legg merke til at vi bare legger inn data i noen av kolonnene.


INSERT INTO user_status(
  uid, verified, registration_date,
  verification_code, nick)
VALUES(1, 1, NOW(), "asd", "ut");

Så får jeg en suksessmelding tilbake fra MySQL, jippi. Eller vent, det står noe om at det er generert tre advarsler. Ok tenker jeg, så jeg får vel finne ut hva disse advarslene er.


mysql> SHOW WARNINGS;
+---------+------+------------------------------------------------------------------------+
| Level   | Code | Message                                                                |
+---------+------+------------------------------------------------------------------------+
| Warning | 1364 | Field 'ban_reason' doesn't have a default value                        |
| Warning | 1364 | Field 'logincount' doesn't have a default value                        |
| Warning | 1364 | Field 'lastlogin' doesn't have a default value                         |
| Warning | 1366 | Incorrect integer value: 'asd' for column 'verification_code' at row 1 |
+---------+------+------------------------------------------------------------------------+

Det at MySQL gir blaffen i påkrevde kolonner visste jeg egentlig, og jeg blir sinna hver gang jeg tenker på det. Så egentlig var de første advarslene godt kjente for meg.

Det som virkelig overrasket meg var,

Hva?! Tillater MySQL meg å opprette en rad i en tabell med noe data i en kollonne med en annen datatype?

MySQL tillater meg faktisk å sende inn tekststrengen “asd” inn kolonnen “verification_code” som er deklarert som et heltall. Hva i alle dager? Hvilken verdi har MySQL satt inn i tabellen min da? Dette må undersøkes.


mysql> SELECT * FROM user_status;
+-----+----------+-----------------+------------+---------------------+-------------------+------+--------+------------+------------+---------------------+
| uid | verified | registered_nick | first_time | registration_date   | verification_code | nick | active | ban_reason | logincount | lastlogin           |
+-----+----------+-----------------+------------+---------------------+-------------------+------+--------+------------+------------+---------------------+
|   1 |        1 |               0 |          1 | 2009-09-29 17:08:57 |                 0 | ut   |      1 |            |          0 | 0000-00-00 00:00:00 |
+-----+----------+-----------------+------------+---------------------+-------------------+------+--------+------------+------------+---------------------+

Den satte inn tallet “0″ i verification_code-kolonnen. Hvordan MySQL fant ut at det var en smart idé vet jeg ikke. Kolonnen er av type heltall, den krever en verdi og er deklarert uten noen default verdi. Jeg sender inn tekststrengen “asd”.

I et scriptspråk som PHP eller Perl evalueres denne strengen til en bolsk sann verdi. Så kanskje kunne heltallsrepresentasjonen av strengen vært “1″. Derimot er det ikke sikkert at kolonnen representerer en bolsk verdi, for da ville jeg vel brukt en datatype som bit eller bool, ikke sant? Det eneste fornuftige å gjøre er faktisk å ikke tillate verdien og forhindre meg i å opprette raden.

Det jeg stusser litt på, og blir lei meg over, er den manglende forståelsen av integritet i MySQL. Hvis jeg forsøker å opprette en rad i en tabell uten å sende inn alle påkrevde felt, så burde jeg ikke få lov til å opprette raden. Så enkelt kan det gjøres.

MySQL må ikke tro at den er smartere enn meg.