Spring naar hoofdtekst

Debuggen van een zwijgzame MariaDB

Geplaatst op door ,
Laatste aanpassing op .

Inleiding

Dezer dagen vraagt een gemiddelde Ubuntu installatie met regelmaat voor een upgrade naar versie 18.04 LTS (Long Term Support), een uitgave met verlengde ondersteuning (tot vijf jaar) voor een deel van de geleverde software. Aangezien ik tot nu toe vrij tevreden was over Ubuntu, besloot ik er dan maar meteen een frisse herinstallatie van te maken.

In de afgelopen jaren had ik een tekstbestand gevuld met commando's en geheugensteuntjes die ik als leidraad kon gebruiken bij de installatie. Zo zou ik zeker geen belangrijke zaken vergeten te installeren of te configureren. Daaronder ook de MySQL-databaseserver en de koppeling naar PHP.

Gelijkvloerse drempel

Bij het inrichten van mijn webapplicaties op http://localhost/ bleek dat ze de verbinding met de database niet konden maken. In eerdere versies van MySQL en Ubuntu verscheen er tijdens de installatie een venster met de vraag om een wachtwoord. Nu was die vraag niet gesteld. Wat bleek? Er was een blanco wachtwoord voor de beheerdersaccount (root) ingesteld.

Aldus dacht ik slim te zijn en met een eerder geschreven artikel het wachtwoord opnieuw in te stellen. Jammer genoeg werkten deze instructies niet meer. Wat nu?

Root-toegang

Met behulp van onderstaande commando's kon ik de root-account toch weer met een wachtwoord laten verbinden. In de shell opende ik een MySQL-client met beheerdersrechten (sudo):

$ sudo mysql -u root

Bij de standaard installatie wordt de authenticatieplugin auth_socket gebruikt. Hierbij speelt het wachtwoord totaal geen rol. In plaats daarvan wordt de gebruikersnaam uit de shell vergeleken met de gebruikersnaam in de database. Met de volgende queries wordt deze manier van authenticatie uitgeschakeld:

use mysql;
update user set plugin='' where User='root';
flush privileges;
\q;

Tot slot volgt het opnieuw instellen van het root-wachtwoord, met nog een aantal verdere acties ter betere beveiliging van de databaseserver. Dit commando wordt ten strengste aanbevolen, zeker als een server 'live', in productie is.

$ sudo mysql_secure_installation

Overstap

Al geruime tijd zijn de merknaam en ontwikkeling van MySQL in handen van Oracle, een groot commercieel softwarebedrijf uit de Verenigde Staten. Omdat een deel van de ontwikkelaars zich niet kon vinden in de koers van dat bedrijf, hebben ze de broncode geforkt. Vanaf dat moment was er een alternatieve databaseserver genaamd MariaDB. De installatie verloopt zonder problemen, maar let wel op bovengenoemd akkefietje met het root-wachtwoord:

$ sudo apt install mariadb-server

Debugging

Na de overstap voerde ik de scripts uit, om alle bestaande databases terug in te lezen. Bij één van mijn applicaties ging dit niet naar behoren. Ik zag geen enkele foutmelding tijdens het importeren, maar er werd ook geen data getoond in de applicatie. Wat was hier aan de hand?

Het enige directe verschil tussen deze en mijn voorgaande applicaties was het gebruik van PHP Data Objects, oftewel PDO. Bij het inlezen van de SQL-scripts maakte ik gebruik van PDO's exec()-commando; niet wetende dat deze functie eigenlijk bedoeld is om slechts één statement uit te voeren.

Dat bleek toen ik met de oude vertrouwde var_dump(); die(); al debuggend op zoek ging naar waarom bepaalde stored procedures niet werden geïmporteerd. Ook ontbrak er een complete tabel; terwijl anderen zonder problemen, inclusief data voorhanden waren.

Unieke tekenreeks

Door het stap voor stap importeren vond ik de boosdoener. MariaDB beklaagde zich over een UNIQUE-sleutel die ik op een VARCHAR(400)-veld had gelegd met de volgende foutmelding:

1071 - Specified key was too long; max key length is 767 bytes

De oplossing was even eenvoudig als elegant. Ik maakte er een VARCHAR(255) van en paste tenslotte alle procedures die met de betreffende tabel in aanraking kwamen aan. Gelukkig was er op dat moment geen enkele rij met méér dan 255 tekens in het betreffende veld.

Debug-hulp

Uit deze zoektocht blijkt maar weer eens, hoe belangrijk een effectieve debugger kan zijn voor iedere software-ontwikkelaar. Ik zocht en vond een mogelijkheid om bij de eerst optredende fout direct de uitvoering te stoppen, en de betreffende melding te tonen. Ik verwerkte dit stuk code tot een eigen implementatie van exec() genaamd execMulti():

private static $_instance = null;

public static function getInstance()
{
    if (is_null(self::$_instance)) {
        $dsn = 'mysql:host='.DBHOSTNAME.';charset=utf8';
        self::$_instance = new \PDO($dsn, DBUSERNAME, DBPASSWORD);

        $createSQL = sprintf(
            'CREATE DATABASE IF NOT EXISTS `%1$s` DEFAULT CHARACTER SET '.
            'utf8 DEFAULT COLLATE utf8_general_ci; USE `%1$s`;',
            DBNAME
        );
        self::$_instance->execMulti($createSQL);
    }
    return self::$_instance;
}

public static function execMulti(string $queries, string &$errorMessage = null)
{
    $db = self::getInstance();
    $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
    $db->setAttribute(\PDO::ATTR_EMULATE_PREPARES, 1);

    $stmt = $db->prepare($queries);
    $stmt->execute();
    $i = 1;

    do {
        $i++;
    } while ($stmt->nextRowset());

    $error = $stmt->errorInfo();
    if ($error[0] != "00000") {
        $errorMessage = "Query $i failed: ".$error[2].PHP_EOL;
        return false;
    }
    return true;
}

Inhoudsopgave

Atom-feed Atom-feed van FWiePs weblog

Artikelen


Doorzoek de onderstaande categorieën om de lijst met artikelen te filteren.