xref: /plugin/struct/action/migration.php (revision ba662a609884bbbecde8cffec91014be306b652b)
18f259467SAndreas Gohr<?php
2d6d97f60SAnna Dabrowska
37234bfb1Ssplitbrainuse dokuwiki\Extension\ActionPlugin;
47234bfb1Ssplitbrainuse dokuwiki\Extension\EventHandler;
57234bfb1Ssplitbrainuse dokuwiki\Extension\Event;
67234bfb1Ssplitbrainuse dokuwiki\plugin\sqlite\SQLiteDB;
77234bfb1Ssplitbrain
88f259467SAndreas Gohr/**
98f259467SAndreas Gohr * DokuWiki Plugin struct (Action Component)
108f259467SAndreas Gohr *
118f259467SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
128f259467SAndreas Gohr * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
138f259467SAndreas Gohr */
148f259467SAndreas Gohr/**
158f259467SAndreas Gohr * Class action_plugin_struct_migration
168f259467SAndreas Gohr *
178f259467SAndreas Gohr * Handle migrations that need more than just SQL
188f259467SAndreas Gohr */
197234bfb1Ssplitbrainclass action_plugin_struct_migration extends ActionPlugin
20d6d97f60SAnna Dabrowska{
218f259467SAndreas Gohr    /**
228f259467SAndreas Gohr     * @inheritDoc
238f259467SAndreas Gohr     */
247234bfb1Ssplitbrain    public function register(EventHandler $controller)
25d6d97f60SAnna Dabrowska    {
26748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'BEFORE', $this, 'handleMigrations');
278f259467SAndreas Gohr    }
288f259467SAndreas Gohr
298f259467SAndreas Gohr    /**
308f259467SAndreas Gohr     * Call our custom migrations when defined
318f259467SAndreas Gohr     *
325e29103aSannda     * @param Event $event
338f259467SAndreas Gohr     * @param $param
348f259467SAndreas Gohr     */
357234bfb1Ssplitbrain    public function handleMigrations(Event $event, $param)
36d6d97f60SAnna Dabrowska    {
3779b29326SAnna Dabrowska        if ($event->data['adapter']->getDbname() !== 'struct') {
383eafcbabSMichael Große            return;
393eafcbabSMichael Große        }
408f259467SAndreas Gohr        $to = $event->data['to'];
418f259467SAndreas Gohr
427234bfb1Ssplitbrain        if (is_callable([$this, "migration$to"])) {
438f259467SAndreas Gohr            $event->preventDefault();
447234bfb1Ssplitbrain            $event->result = call_user_func([$this, "migration$to"], $event->data['adapter']);
458f259467SAndreas Gohr        }
468f259467SAndreas Gohr    }
478f259467SAndreas Gohr
488f259467SAndreas Gohr    /**
498f259467SAndreas Gohr     * Executes Migration 12
508f259467SAndreas Gohr     *
518f259467SAndreas Gohr     * Add a latest column to all existing multi tables
528f259467SAndreas Gohr     *
537234bfb1Ssplitbrain     * @param SQLiteDB $sqlite
548f259467SAndreas Gohr     * @return bool
558f259467SAndreas Gohr     */
5679b29326SAnna Dabrowska    protected function migration12($sqlite)
57d6d97f60SAnna Dabrowska    {
588f259467SAndreas Gohr        /** @noinspection SqlResolve */
598f259467SAndreas Gohr        $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'multi_%'";
6079b29326SAnna Dabrowska        $tables = $sqlite->queryAll($sql);
618f259467SAndreas Gohr
628f259467SAndreas Gohr        foreach ($tables as $row) {
6366164365SAndreas Gohr            $table = $row['name']; // no escaping needed, it's our own tables
6466164365SAndreas Gohr            $sql = "ALTER TABLE $table ADD COLUMN latest INT DEFAULT 1";
6566164365SAndreas Gohr            $sqlite->query($sql);
668f259467SAndreas Gohr        }
678f259467SAndreas Gohr
688f259467SAndreas Gohr        return true;
698f259467SAndreas Gohr    }
7076a74c23SAnna Dabrowska
7176a74c23SAnna Dabrowska    /**
7276a74c23SAnna Dabrowska     * Executes Migration 16
7376a74c23SAnna Dabrowska     *
7476a74c23SAnna Dabrowska     * Unifies previous page and lookup schema types
7576a74c23SAnna Dabrowska     *
767234bfb1Ssplitbrain     * @param SQLiteDB $sqlite
7776a74c23SAnna Dabrowska     * @return bool
7876a74c23SAnna Dabrowska     */
7979b29326SAnna Dabrowska    protected function migration16($sqlite)
8076a74c23SAnna Dabrowska    {
8176a74c23SAnna Dabrowska        // get tables and their SQL definitions
8276a74c23SAnna Dabrowska        $sql = "SELECT sql, name FROM sqlite_master
8376a74c23SAnna Dabrowska                WHERE type = 'table'
8476a74c23SAnna Dabrowska                AND (name LIKE 'data_%' OR name LIKE 'multi_%')";
8579b29326SAnna Dabrowska        $tables = $sqlite->queryAll($sql);
8676a74c23SAnna Dabrowska
8776a74c23SAnna Dabrowska        // get latest versions of schemas with islookup property
8876a74c23SAnna Dabrowska        $sql = "SELECT MAX(id) AS id, tbl, islookup FROM schemas
8976a74c23SAnna Dabrowska                    GROUP BY tbl
9076a74c23SAnna Dabrowska            ";
9179b29326SAnna Dabrowska        $schemas = $sqlite->queryAll($sql);
9276a74c23SAnna Dabrowska
9376a74c23SAnna Dabrowska        $ok = true;
9476a74c23SAnna Dabrowska
9576a74c23SAnna Dabrowska        // Step 1: move original data to temporary tables and create new ones with modified schemas
9676a74c23SAnna Dabrowska        foreach ($tables as $table) {
9776a74c23SAnna Dabrowska            $name = $table['name'];
9876a74c23SAnna Dabrowska            $sql = $table['sql'];
9976a74c23SAnna Dabrowska
10076a74c23SAnna Dabrowska            // move original data to temp_*
10176a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query("ALTER TABLE $name RENAME TO temp_$name");
10276a74c23SAnna Dabrowska
10376a74c23SAnna Dabrowska            // update pid definitions
10476a74c23SAnna Dabrowska            $sql = preg_replace('/pid (\w* ?NOT NULL|\w* ?PRIMARY KEY)/', 'pid TEXT DEFAULT ""', $sql);
10576a74c23SAnna Dabrowska
10676a74c23SAnna Dabrowska            // add rid and new primary key to regular tables
10776a74c23SAnna Dabrowska            $cnt = 0;
10876a74c23SAnna Dabrowska            $sql = preg_replace('/(PRIMARY KEY ?\([^\)]+?)(\))/', ' rid INTEGER, $1, rid $2', $sql, -1, $cnt);
10976a74c23SAnna Dabrowska            // add rid and new primary key to lookup tables
11076a74c23SAnna Dabrowska            if (!$cnt) {
11176a74c23SAnna Dabrowska                $sql = str_replace(')', ', rid INTEGER, PRIMARY KEY(pid,rid) )', $sql);
11276a74c23SAnna Dabrowska            }
11376a74c23SAnna Dabrowska
11476a74c23SAnna Dabrowska            // create the new table
11576a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query($sql);
11676a74c23SAnna Dabrowska            if (!$ok) return false;
11776a74c23SAnna Dabrowska        }
11876a74c23SAnna Dabrowska
11976a74c23SAnna Dabrowska        // Step 2: transfer data back from original tables (temp_*)
12076a74c23SAnna Dabrowska        foreach ($schemas as $schema) {
12176a74c23SAnna Dabrowska            $name = $schema['tbl'];
12276a74c23SAnna Dabrowska            $sid = $schema['id'];
12376a74c23SAnna Dabrowska            $isLookup = $schema['islookup'];
12476a74c23SAnna Dabrowska
12576a74c23SAnna Dabrowska            if (!$isLookup) {
12676a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO data_%s SELECT *, 0 FROM temp_data_%s', $name, $name);
12776a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
12876a74c23SAnna Dabrowska                if (!$ok) return false;
12976a74c23SAnna Dabrowska
13076a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO multi_%s SELECT *, 0 FROM temp_multi_%s', $name, $name);
13176a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
13276a74c23SAnna Dabrowska                if (!$ok) return false;
13376a74c23SAnna Dabrowska            } else {
13476a74c23SAnna Dabrowska                // transfer pid to rid
13576a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO data_%s SELECT *, pid FROM temp_data_%s', $name, $name);
13676a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
13776a74c23SAnna Dabrowska                if (!$ok) return false;
13876a74c23SAnna Dabrowska
13976a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO multi_%s SELECT *, pid FROM temp_multi_%s', $name, $name);
14076a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
14176a74c23SAnna Dabrowska                if (!$ok) return false;
14276a74c23SAnna Dabrowska
14376a74c23SAnna Dabrowska                // all lookup data has empty pids at this point
14476a74c23SAnna Dabrowska                $s = "UPDATE data_$name SET pid = ''";
14576a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
14676a74c23SAnna Dabrowska                if (!$ok) return false;
14776a74c23SAnna Dabrowska
14876a74c23SAnna Dabrowska                $s = "UPDATE multi_$name SET pid = ''";
14976a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
15076a74c23SAnna Dabrowska                if (!$ok) return false;
15176a74c23SAnna Dabrowska            }
15276a74c23SAnna Dabrowska
15376a74c23SAnna Dabrowska            // introduce composite ids in lookup columns
154544dca1bSAnna Dabrowska            $s = $this->getLookupColsSql($sid);
15579b29326SAnna Dabrowska            $cols = $sqlite->queryAll($s);
15676a74c23SAnna Dabrowska
15776a74c23SAnna Dabrowska            if ($cols) {
15876a74c23SAnna Dabrowska                foreach ($cols as $col) {
15976a74c23SAnna Dabrowska                    $colno = $col['COL'];
160e361da24SAnna Dabrowska                    $colname = "col$colno";
161ef747633SAnna Dabrowska                    // lookup fields pointing to pages have to be migrated first!
162ef747633SAnna Dabrowska                    // they rely on a simplistic not-a-number check, and already migrated lookups pass the test!
16317a3a578SAndreas Gohr                    $f = 'UPDATE data_%s
16417a3a578SAndreas Gohr                             SET %s = \'["\'||%s||\'",0]\'
16517a3a578SAndreas Gohr                           WHERE %s != \'\'
16617a3a578SAndreas Gohr                             AND CAST(%s AS DECIMAL) != %s';
167e361da24SAnna Dabrowska                    $s = sprintf($f, $name, $colname, $colname, $colname, $colname, $colname);
168e361da24SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
169e361da24SAnna Dabrowska                    if (!$ok) return false;
17076a74c23SAnna Dabrowska                    // multi_
17117a3a578SAndreas Gohr                    $f = 'UPDATE multi_%s
17217a3a578SAndreas Gohr                             SET value = \'["\'||value||\'",0]\'
17317a3a578SAndreas Gohr                           WHERE colref = %s
17417a3a578SAndreas Gohr                             AND CAST(value AS DECIMAL) != value';
175e361da24SAnna Dabrowska                    $s = sprintf($f, $name, $colno);
17676a74c23SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
17776a74c23SAnna Dabrowska                    if (!$ok) return false;
178ef747633SAnna Dabrowska
179ef747633SAnna Dabrowska                    // simple lookup fields
18017a3a578SAndreas Gohr                    $s = "UPDATE data_$name
18117a3a578SAndreas Gohr                             SET col$colno = '[" . '""' . ",'||col$colno||']'
18217a3a578SAndreas Gohr                           WHERE col$colno != ''
18317a3a578SAndreas Gohr                             AND CAST(col$colno AS DECIMAL) = col$colno";
184ef747633SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
185ef747633SAnna Dabrowska                    if (!$ok) return false;
186ef747633SAnna Dabrowska                    // multi_
18717a3a578SAndreas Gohr                    $s = "UPDATE multi_$name
18817a3a578SAndreas Gohr                             SET value = '[" . '""' . ",'||value||']'
18917a3a578SAndreas Gohr                           WHERE colref=$colno
19017a3a578SAndreas Gohr                             AND CAST(value AS DECIMAL) = value";
191ef747633SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
192ef747633SAnna Dabrowska                    if (!$ok) return false;
19376a74c23SAnna Dabrowska                }
19476a74c23SAnna Dabrowska            }
19576a74c23SAnna Dabrowska        }
19676a74c23SAnna Dabrowska
19776a74c23SAnna Dabrowska        // Step 3: delete temp_* tables
19876a74c23SAnna Dabrowska        foreach ($tables as $table) {
19976a74c23SAnna Dabrowska            $name = $table['name'];
20076a74c23SAnna Dabrowska            $s = "DROP TABLE temp_$name";
20176a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query($s);
20276a74c23SAnna Dabrowska            if (!$ok) return false;
20376a74c23SAnna Dabrowska        }
20476a74c23SAnna Dabrowska
20576a74c23SAnna Dabrowska        // Step 4: remove islookup in schemas table
20676a74c23SAnna Dabrowska        $sql = "SELECT sql FROM sqlite_master
20776a74c23SAnna Dabrowska                WHERE type = 'table'
20876a74c23SAnna Dabrowska                AND name = 'schemas'";
20979b29326SAnna Dabrowska        $t = $sqlite->queryAll($sql);
21076a74c23SAnna Dabrowska        $sql = $t[0]['sql'];
21176a74c23SAnna Dabrowska        $sql = str_replace('islookup INTEGER,', '', $sql);
21276a74c23SAnna Dabrowska
21376a74c23SAnna Dabrowska        $s = 'ALTER TABLE schemas RENAME TO temp_schemas';
21476a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($s);
21576a74c23SAnna Dabrowska        if (!$ok) return false;
21676a74c23SAnna Dabrowska
21776a74c23SAnna Dabrowska        // create a new table without islookup
21876a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($sql);
21976a74c23SAnna Dabrowska        if (!$ok) return false;
22076a74c23SAnna Dabrowska
22176a74c23SAnna Dabrowska        $s = 'INSERT INTO schemas SELECT id, tbl, ts, user, comment, config FROM temp_schemas';
22276a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($s);
22376a74c23SAnna Dabrowska
22479b29326SAnna Dabrowska        return $ok;
22576a74c23SAnna Dabrowska    }
226544dca1bSAnna Dabrowska
227544dca1bSAnna Dabrowska    /**
228544dca1bSAnna Dabrowska     * Executes Migration 17
229544dca1bSAnna Dabrowska     *
230544dca1bSAnna Dabrowska     * Fixes lookup data not correctly migrated by #16
231544dca1bSAnna Dabrowska     * All lookups were presumed to reference lookup data, not pages, so the migrated value
232544dca1bSAnna Dabrowska     * was always ["", <previous-pid-aka-new-rid>]. For page references it is ["<previous-pid>", 0]
233544dca1bSAnna Dabrowska     *
2347234bfb1Ssplitbrain     * @param SQLiteDB $sqlite
235544dca1bSAnna Dabrowska     * @return bool
236544dca1bSAnna Dabrowska     */
23779b29326SAnna Dabrowska    protected function migration17($sqlite)
238544dca1bSAnna Dabrowska    {
239544dca1bSAnna Dabrowska        $sql = "SELECT MAX(id) AS id, tbl FROM schemas
240544dca1bSAnna Dabrowska                    GROUP BY tbl
241544dca1bSAnna Dabrowska            ";
24279b29326SAnna Dabrowska        $schemas = $sqlite->queryAll($sql);
243544dca1bSAnna Dabrowska
244544dca1bSAnna Dabrowska        $ok = true;
245544dca1bSAnna Dabrowska
246544dca1bSAnna Dabrowska        foreach ($schemas as $schema) {
247544dca1bSAnna Dabrowska            // find lookup columns
248544dca1bSAnna Dabrowska            $name = $schema['tbl'];
249544dca1bSAnna Dabrowska            $sid = $schema['id'];
250544dca1bSAnna Dabrowska            $s = $this->getLookupColsSql($sid);
25179b29326SAnna Dabrowska            $cols = $sqlite->queryAll($s);
252544dca1bSAnna Dabrowska
253544dca1bSAnna Dabrowska            if ($cols) {
2545e29103aSannda                $colnames = array_map(static fn($c) => 'col' . $c['COL'], $cols);
255544dca1bSAnna Dabrowska
256544dca1bSAnna Dabrowska                // data_ tables
257544dca1bSAnna Dabrowska                $s = 'SELECT pid, rid, rev, ' . implode(', ', $colnames) . " FROM data_$name";
25879b29326SAnna Dabrowska                $allValues = $sqlite->queryAll($s);
259544dca1bSAnna Dabrowska
260544dca1bSAnna Dabrowska                if (!empty($allValues)) {
261544dca1bSAnna Dabrowska                    foreach ($allValues as $row) {
2627234bfb1Ssplitbrain                        [$pid, $rid, $rev, $colref, $rowno, $fixes] = $this->getFixedValues($row);
263544dca1bSAnna Dabrowska                        // now fix the values
264544dca1bSAnna Dabrowska                        if (!empty($fixes)) {
26517a3a578SAndreas Gohr                            $sql = "UPDATE data_$name
26617a3a578SAndreas Gohr                                       SET " . implode(', ', $fixes) . "
26717a3a578SAndreas Gohr                                     WHERE pid = ?
26817a3a578SAndreas Gohr                                       AND rid = ?
26917a3a578SAndreas Gohr                                       AND rev = ?";
270544dca1bSAnna Dabrowska                            $params = [$pid, $rid, $rev];
271544dca1bSAnna Dabrowska                            $ok = $ok && $sqlite->query($sql, $params);
272544dca1bSAnna Dabrowska                        }
273544dca1bSAnna Dabrowska                    }
274544dca1bSAnna Dabrowska                }
275544dca1bSAnna Dabrowska
276544dca1bSAnna Dabrowska                // multi_ tables
277544dca1bSAnna Dabrowska                $s = "SELECT colref, pid, rid, rev, row, value FROM multi_$name";
27879b29326SAnna Dabrowska                $allValues = $sqlite->queryAll($s);
279544dca1bSAnna Dabrowska
280544dca1bSAnna Dabrowska                if (!empty($allValues)) {
281544dca1bSAnna Dabrowska                    foreach ($allValues as $row) {
2827234bfb1Ssplitbrain                        [$pid, $rid, $rev, $colref, $rowno, $fixes] = $this->getFixedValues($row);
283544dca1bSAnna Dabrowska                        // now fix the values
284544dca1bSAnna Dabrowska                        if (!empty($fixes)) {
28517a3a578SAndreas Gohr                            $sql = "UPDATE multi_$name
28617a3a578SAndreas Gohr                                       SET " . implode(', ', $fixes) . "
28717a3a578SAndreas Gohr                                     WHERE pid = ?
28817a3a578SAndreas Gohr                                       AND rid = ?
28917a3a578SAndreas Gohr                                       AND rev = ?
29017a3a578SAndreas Gohr                                       AND colref = ?
29117a3a578SAndreas Gohr                                       AND row = ?";
292544dca1bSAnna Dabrowska                            $params = [$pid, $rid, $rev, $colref, $rowno];
293544dca1bSAnna Dabrowska                            $ok = $ok && $sqlite->query($sql, $params);
294544dca1bSAnna Dabrowska                        }
295544dca1bSAnna Dabrowska                    }
296544dca1bSAnna Dabrowska                }
297544dca1bSAnna Dabrowska            }
298544dca1bSAnna Dabrowska        }
299544dca1bSAnna Dabrowska
30079b29326SAnna Dabrowska        return $ok;
301544dca1bSAnna Dabrowska    }
302544dca1bSAnna Dabrowska
303544dca1bSAnna Dabrowska    /**
304bbd79bccSAnna Dabrowska     * Removes a temp table left over by migration 16
305bbd79bccSAnna Dabrowska     *
3067234bfb1Ssplitbrain     * @param SQLiteDB $sqlite
307bbd79bccSAnna Dabrowska     * @return bool
308bbd79bccSAnna Dabrowska     */
30979b29326SAnna Dabrowska    protected function migration18($sqlite)
310bbd79bccSAnna Dabrowska    {
311bbd79bccSAnna Dabrowska        $ok = true;
312bbd79bccSAnna Dabrowska
313bbd79bccSAnna Dabrowska        $sql = 'DROP TABLE IF EXISTS temp_schemas';
314bbd79bccSAnna Dabrowska        $ok = $ok && $sqlite->query($sql);
315bbd79bccSAnna Dabrowska
31679b29326SAnna Dabrowska        return $ok;
317bbd79bccSAnna Dabrowska    }
31866164365SAndreas Gohr
319fc6ac2e5SAnna Dabrowska    /**
320fc6ac2e5SAnna Dabrowska     * Executes Migration 19
321fc6ac2e5SAnna Dabrowska     *
322fc6ac2e5SAnna Dabrowska     * Add "published" column to all existing tables
323fc6ac2e5SAnna Dabrowska     *
3247234bfb1Ssplitbrain     * @param SQLiteDB $sqlite
325fc6ac2e5SAnna Dabrowska     * @return bool
326fc6ac2e5SAnna Dabrowska     */
32779b29326SAnna Dabrowska    protected function migration19($sqlite)
328fc6ac2e5SAnna Dabrowska    {
329fc6ac2e5SAnna Dabrowska        $ok = true;
330fc6ac2e5SAnna Dabrowska
331fc6ac2e5SAnna Dabrowska        /** @noinspection SqlResolve */
332fc6ac2e5SAnna Dabrowska        $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND (name LIKE 'data_%' OR name LIKE 'multi_%')";
33379b29326SAnna Dabrowska        $tables = $sqlite->queryAll($sql);
334fc6ac2e5SAnna Dabrowska
335fc6ac2e5SAnna Dabrowska        foreach ($tables as $row) {
33666164365SAndreas Gohr            $table = $row['name']; // no escaping needed, it's our own tables
33766164365SAndreas Gohr            $sql = "ALTER TABLE $table ADD COLUMN published INT DEFAULT NULL";
33866164365SAndreas Gohr            $ok = $ok && $sqlite->query($sql);
339fc6ac2e5SAnna Dabrowska        }
34079b29326SAnna Dabrowska        return $ok;
341fc6ac2e5SAnna Dabrowska    }
342fc6ac2e5SAnna Dabrowska
34352637a9cSAnna Dabrowska    /**
34452637a9cSAnna Dabrowska     * Executes Migration 20
34552637a9cSAnna Dabrowska     *
34652637a9cSAnna Dabrowska     * Adds indexes on "latest" and "published".
34752637a9cSAnna Dabrowska     * Those fields are not part of (autoindexed) primary key, but are used in many queries.
34852637a9cSAnna Dabrowska     *
34952637a9cSAnna Dabrowska     * @param SQLiteDB $sqlite
35052637a9cSAnna Dabrowska     * @return bool
35152637a9cSAnna Dabrowska     */
35252637a9cSAnna Dabrowska    protected function migration20($sqlite)
35352637a9cSAnna Dabrowska    {
35452637a9cSAnna Dabrowska        $ok = true;
35552637a9cSAnna Dabrowska
35652637a9cSAnna Dabrowska        /** @noinspection SqlResolve */
35752637a9cSAnna Dabrowska        $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND (name LIKE 'data_%' OR name LIKE 'multi_%')";
35852637a9cSAnna Dabrowska        $tables = $sqlite->queryAll($sql);
35952637a9cSAnna Dabrowska
36052637a9cSAnna Dabrowska        foreach ($tables as $row) {
36152637a9cSAnna Dabrowska            $table = $row['name']; // no escaping needed, it's our own tables
36252637a9cSAnna Dabrowska            $sql = "CREATE INDEX idx_$table" . "_latest ON $table(latest);";
36352637a9cSAnna Dabrowska            $ok = $ok && $sqlite->query($sql);
36452637a9cSAnna Dabrowska            $sql = "CREATE INDEX idx_$table" . "_published ON $table(published);";
36552637a9cSAnna Dabrowska            $ok = $ok && $sqlite->query($sql);
36652637a9cSAnna Dabrowska        }
36752637a9cSAnna Dabrowska        return $ok;
36852637a9cSAnna Dabrowska    }
36952637a9cSAnna Dabrowska
370bbd79bccSAnna Dabrowska
371bbd79bccSAnna Dabrowska    /**
372544dca1bSAnna Dabrowska     * Returns a select statement to fetch Lookup columns in the current schema
373544dca1bSAnna Dabrowska     *
374544dca1bSAnna Dabrowska     * @param int $sid Id of the schema
375544dca1bSAnna Dabrowska     * @return string SQL statement
376544dca1bSAnna Dabrowska     */
377544dca1bSAnna Dabrowska    protected function getLookupColsSql($sid)
378544dca1bSAnna Dabrowska    {
379544dca1bSAnna Dabrowska        return "SELECT C.colref AS COL, T.class AS TYPE
380544dca1bSAnna Dabrowska                FROM schema_cols AS C
381544dca1bSAnna Dabrowska                LEFT OUTER JOIN types AS T
382544dca1bSAnna Dabrowska                    ON C.tid = T.id
383544dca1bSAnna Dabrowska                WHERE C.sid = $sid
384544dca1bSAnna Dabrowska                AND TYPE LIKE '%Lookup'
385544dca1bSAnna Dabrowska            ";
386544dca1bSAnna Dabrowska    }
387544dca1bSAnna Dabrowska
388544dca1bSAnna Dabrowska    /**
389544dca1bSAnna Dabrowska     * Checks for improperly migrated values and returns an array with
390544dca1bSAnna Dabrowska     * "<column> = <fixed-value>" fragments to be used in the UPDATE statement.
391544dca1bSAnna Dabrowska     *
392544dca1bSAnna Dabrowska     * @param array $row
393544dca1bSAnna Dabrowska     * @return array
394544dca1bSAnna Dabrowska     */
395544dca1bSAnna Dabrowska    protected function getFixedValues($row)
396544dca1bSAnna Dabrowska    {
397544dca1bSAnna Dabrowska        $pid = $row['pid'];
398544dca1bSAnna Dabrowska        $rid = $row['rid'];
399544dca1bSAnna Dabrowska        $rev = $row['rev'];
400544dca1bSAnna Dabrowska        $colref = $row['colref'];
401544dca1bSAnna Dabrowska        $rowno = $row['row'];
402544dca1bSAnna Dabrowska        $fixes = [];
403544dca1bSAnna Dabrowska        $matches = [];
404544dca1bSAnna Dabrowska
405544dca1bSAnna Dabrowska        // check if anything needs to be fixed in data columns
406544dca1bSAnna Dabrowska        foreach ($row as $col => $value) {
407544dca1bSAnna Dabrowska            if (in_array($col, ['pid', 'rid', 'rev', 'colref', 'row'])) {
408544dca1bSAnna Dabrowska                continue;
409544dca1bSAnna Dabrowska            }
410544dca1bSAnna Dabrowska            preg_match('/^\["",(?<pid>.*?\D+.*?)\]$/', $value, $matches);
411544dca1bSAnna Dabrowska            if (!empty($matches['pid'])) {
412544dca1bSAnna Dabrowska                $fixes[$col] = '["' . $matches['pid'] . '",0]';
413544dca1bSAnna Dabrowska            }
414544dca1bSAnna Dabrowska        }
415544dca1bSAnna Dabrowska
416*ba662a60SAndreas Gohr        if ($fixes !== []) {
4175e29103aSannda            $fixes = array_map(static fn($set, $key) => "$key = '$set'", $fixes, array_keys($fixes));
418544dca1bSAnna Dabrowska        }
419544dca1bSAnna Dabrowska
420544dca1bSAnna Dabrowska        return [$pid, $rid, $rev, $colref, $rowno, $fixes];
421544dca1bSAnna Dabrowska    }
4228f259467SAndreas Gohr}
423