xref: /plugin/struct/action/migration.php (revision fc6ac2e560a8d00924bd642434731ce9aa18206d)
18f259467SAndreas Gohr<?php
2d6d97f60SAnna Dabrowska
38f259467SAndreas Gohr/**
48f259467SAndreas Gohr * DokuWiki Plugin struct (Action Component)
58f259467SAndreas Gohr *
68f259467SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
78f259467SAndreas Gohr * @author  Andreas Gohr, Michael Große <dokuwiki@cosmocode.de>
88f259467SAndreas Gohr */
98f259467SAndreas Gohr
108f259467SAndreas Gohr/**
118f259467SAndreas Gohr * Class action_plugin_struct_migration
128f259467SAndreas Gohr *
138f259467SAndreas Gohr * Handle migrations that need more than just SQL
148f259467SAndreas Gohr */
15d6d97f60SAnna Dabrowskaclass action_plugin_struct_migration extends DokuWiki_Action_Plugin
16d6d97f60SAnna Dabrowska{
178f259467SAndreas Gohr    /**
188f259467SAndreas Gohr     * @inheritDoc
198f259467SAndreas Gohr     */
20d6d97f60SAnna Dabrowska    public function register(Doku_Event_Handler $controller)
21d6d97f60SAnna Dabrowska    {
22748e747fSAnna Dabrowska        $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'BEFORE', $this, 'handleMigrations');
238f259467SAndreas Gohr    }
248f259467SAndreas Gohr
258f259467SAndreas Gohr    /**
268f259467SAndreas Gohr     * Call our custom migrations when defined
278f259467SAndreas Gohr     *
288f259467SAndreas Gohr     * @param Doku_Event $event
298f259467SAndreas Gohr     * @param $param
308f259467SAndreas Gohr     */
31748e747fSAnna Dabrowska    public function handleMigrations(Doku_Event $event, $param)
32d6d97f60SAnna Dabrowska    {
333eafcbabSMichael Große        if ($event->data['sqlite']->getAdapter()->getDbname() !== 'struct') {
343eafcbabSMichael Große            return;
353eafcbabSMichael Große        }
368f259467SAndreas Gohr        $to = $event->data['to'];
378f259467SAndreas Gohr
388f259467SAndreas Gohr        if (is_callable(array($this, "migration$to"))) {
398f259467SAndreas Gohr            $event->preventDefault();
408f259467SAndreas Gohr            $event->result = call_user_func(array($this, "migration$to"), $event->data['sqlite']);
418f259467SAndreas Gohr        }
428f259467SAndreas Gohr    }
438f259467SAndreas Gohr
448f259467SAndreas Gohr    /**
458f259467SAndreas Gohr     * Executes Migration 12
468f259467SAndreas Gohr     *
478f259467SAndreas Gohr     * Add a latest column to all existing multi tables
488f259467SAndreas Gohr     *
498f259467SAndreas Gohr     * @param helper_plugin_sqlite $sqlite
508f259467SAndreas Gohr     * @return bool
518f259467SAndreas Gohr     */
52d6d97f60SAnna Dabrowska    protected function migration12(helper_plugin_sqlite $sqlite)
53d6d97f60SAnna Dabrowska    {
548f259467SAndreas Gohr        /** @noinspection SqlResolve */
558f259467SAndreas Gohr        $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND name LIKE 'multi_%'";
568f259467SAndreas Gohr        $res = $sqlite->query($sql);
578f259467SAndreas Gohr        $tables = $sqlite->res2arr($res);
588f259467SAndreas Gohr        $sqlite->res_close($res);
598f259467SAndreas Gohr
608f259467SAndreas Gohr        foreach ($tables as $row) {
618f259467SAndreas Gohr            $sql = 'ALTER TABLE ? ADD COLUMN latest INT DEFAULT 1';
628f259467SAndreas Gohr            $sqlite->query($sql, $row['name']);
638f259467SAndreas Gohr        }
648f259467SAndreas Gohr
658f259467SAndreas Gohr        return true;
668f259467SAndreas Gohr    }
6776a74c23SAnna Dabrowska
6876a74c23SAnna Dabrowska    /**
6976a74c23SAnna Dabrowska     * Executes Migration 16
7076a74c23SAnna Dabrowska     *
7176a74c23SAnna Dabrowska     * Unifies previous page and lookup schema types
7276a74c23SAnna Dabrowska     *
7376a74c23SAnna Dabrowska     * @param helper_plugin_sqlite $sqlite
7476a74c23SAnna Dabrowska     * @return bool
7576a74c23SAnna Dabrowska     */
7676a74c23SAnna Dabrowska    protected function migration16(helper_plugin_sqlite $sqlite)
7776a74c23SAnna Dabrowska    {
7876a74c23SAnna Dabrowska        // get tables and their SQL definitions
7976a74c23SAnna Dabrowska        $sql = "SELECT sql, name FROM sqlite_master
8076a74c23SAnna Dabrowska                WHERE type = 'table'
8176a74c23SAnna Dabrowska                AND (name LIKE 'data_%' OR name LIKE 'multi_%')";
8276a74c23SAnna Dabrowska        $res = $sqlite->query($sql);
8376a74c23SAnna Dabrowska        $tables = $sqlite->res2arr($res);
8476a74c23SAnna Dabrowska        $sqlite->res_close($res);
8576a74c23SAnna Dabrowska
8676a74c23SAnna Dabrowska        // get latest versions of schemas with islookup property
8776a74c23SAnna Dabrowska        $sql = "SELECT MAX(id) AS id, tbl, islookup FROM schemas
8876a74c23SAnna Dabrowska                    GROUP BY tbl
8976a74c23SAnna Dabrowska            ";
9076a74c23SAnna Dabrowska        $res = $sqlite->query($sql);
9176a74c23SAnna Dabrowska        $schemas = $sqlite->res2arr($res);
9276a74c23SAnna Dabrowska
9376a74c23SAnna Dabrowska        $sqlite->query('BEGIN TRANSACTION');
9476a74c23SAnna Dabrowska        $ok = true;
9576a74c23SAnna Dabrowska
9676a74c23SAnna Dabrowska        // Step 1: move original data to temporary tables and create new ones with modified schemas
9776a74c23SAnna Dabrowska        foreach ($tables as $table) {
9876a74c23SAnna Dabrowska            $name = $table['name'];
9976a74c23SAnna Dabrowska            $sql = $table['sql'];
10076a74c23SAnna Dabrowska
10176a74c23SAnna Dabrowska            // move original data to temp_*
10276a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query("ALTER TABLE $name RENAME TO temp_$name");
10376a74c23SAnna Dabrowska
10476a74c23SAnna Dabrowska            // update pid definitions
10576a74c23SAnna Dabrowska            $sql = preg_replace('/pid (\w* ?NOT NULL|\w* ?PRIMARY KEY)/', 'pid TEXT DEFAULT ""', $sql);
10676a74c23SAnna Dabrowska
10776a74c23SAnna Dabrowska            // add rid and new primary key to regular tables
10876a74c23SAnna Dabrowska            $cnt = 0;
10976a74c23SAnna Dabrowska            $sql = preg_replace('/(PRIMARY KEY ?\([^\)]+?)(\))/', ' rid INTEGER, $1, rid $2', $sql, -1, $cnt);
11076a74c23SAnna Dabrowska            // add rid and new primary key to lookup tables
11176a74c23SAnna Dabrowska            if (!$cnt) {
11276a74c23SAnna Dabrowska                $sql = str_replace(')', ', rid INTEGER, PRIMARY KEY(pid,rid) )', $sql);
11376a74c23SAnna Dabrowska            }
11476a74c23SAnna Dabrowska
11576a74c23SAnna Dabrowska            // create the new table
11676a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query($sql);
11776a74c23SAnna Dabrowska            if (!$ok) return false;
11876a74c23SAnna Dabrowska        }
11976a74c23SAnna Dabrowska
12076a74c23SAnna Dabrowska        // Step 2: transfer data back from original tables (temp_*)
12176a74c23SAnna Dabrowska        foreach ($schemas as $schema) {
12276a74c23SAnna Dabrowska            $name = $schema['tbl'];
12376a74c23SAnna Dabrowska            $sid = $schema['id'];
12476a74c23SAnna Dabrowska            $isLookup = $schema['islookup'];
12576a74c23SAnna Dabrowska
12676a74c23SAnna Dabrowska            if (!$isLookup) {
12776a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO data_%s SELECT *, 0 FROM temp_data_%s', $name, $name);
12876a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
12976a74c23SAnna Dabrowska                if (!$ok) return false;
13076a74c23SAnna Dabrowska
13176a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO multi_%s SELECT *, 0 FROM temp_multi_%s', $name, $name);
13276a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
13376a74c23SAnna Dabrowska                if (!$ok) return false;
13476a74c23SAnna Dabrowska            } else {
13576a74c23SAnna Dabrowska                // transfer pid to rid
13676a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO data_%s SELECT *, pid FROM temp_data_%s', $name, $name);
13776a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
13876a74c23SAnna Dabrowska                if (!$ok) return false;
13976a74c23SAnna Dabrowska
14076a74c23SAnna Dabrowska                $s = sprintf('INSERT INTO multi_%s SELECT *, pid FROM temp_multi_%s', $name, $name);
14176a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
14276a74c23SAnna Dabrowska                if (!$ok) return false;
14376a74c23SAnna Dabrowska
14476a74c23SAnna Dabrowska                // all lookup data has empty pids at this point
14576a74c23SAnna Dabrowska                $s = "UPDATE data_$name SET pid = ''";
14676a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
14776a74c23SAnna Dabrowska                if (!$ok) return false;
14876a74c23SAnna Dabrowska
14976a74c23SAnna Dabrowska                $s = "UPDATE multi_$name SET pid = ''";
15076a74c23SAnna Dabrowska                $ok = $ok && $sqlite->query($s);
15176a74c23SAnna Dabrowska                if (!$ok) return false;
15276a74c23SAnna Dabrowska            }
15376a74c23SAnna Dabrowska
15476a74c23SAnna Dabrowska            // introduce composite ids in lookup columns
155544dca1bSAnna Dabrowska            $s = $this->getLookupColsSql($sid);
15676a74c23SAnna Dabrowska            $res = $sqlite->query($s);
15776a74c23SAnna Dabrowska            $cols = $sqlite->res2arr($res);
15876a74c23SAnna Dabrowska
15976a74c23SAnna Dabrowska            if ($cols) {
16076a74c23SAnna Dabrowska                foreach ($cols as $col) {
16176a74c23SAnna Dabrowska                    $colno = $col['COL'];
162e361da24SAnna Dabrowska                    $colname = "col$colno";
163ef747633SAnna Dabrowska                    // lookup fields pointing to pages have to be migrated first!
164ef747633SAnna Dabrowska                    // they rely on a simplistic not-a-number check, and already migrated lookups pass the test!
16517a3a578SAndreas Gohr                    $f = 'UPDATE data_%s
16617a3a578SAndreas Gohr                             SET %s = \'["\'||%s||\'",0]\'
16717a3a578SAndreas Gohr                           WHERE %s != \'\'
16817a3a578SAndreas Gohr                             AND CAST(%s AS DECIMAL) != %s';
169e361da24SAnna Dabrowska                    $s = sprintf($f, $name, $colname, $colname, $colname, $colname, $colname);
170e361da24SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
171e361da24SAnna Dabrowska                    if (!$ok) return false;
17276a74c23SAnna Dabrowska                    // multi_
17317a3a578SAndreas Gohr                    $f = 'UPDATE multi_%s
17417a3a578SAndreas Gohr                             SET value = \'["\'||value||\'",0]\'
17517a3a578SAndreas Gohr                           WHERE colref = %s
17617a3a578SAndreas Gohr                             AND CAST(value AS DECIMAL) != value';
177e361da24SAnna Dabrowska                    $s = sprintf($f, $name, $colno);
17876a74c23SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
17976a74c23SAnna Dabrowska                    if (!$ok) return false;
180ef747633SAnna Dabrowska
181ef747633SAnna Dabrowska                    // simple lookup fields
18217a3a578SAndreas Gohr                    $s = "UPDATE data_$name
18317a3a578SAndreas Gohr                             SET col$colno = '[" . '""' . ",'||col$colno||']'
18417a3a578SAndreas Gohr                           WHERE col$colno != ''
18517a3a578SAndreas Gohr                             AND CAST(col$colno AS DECIMAL) = col$colno";
186ef747633SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
187ef747633SAnna Dabrowska                    if (!$ok) return false;
188ef747633SAnna Dabrowska                    // multi_
18917a3a578SAndreas Gohr                    $s = "UPDATE multi_$name
19017a3a578SAndreas Gohr                             SET value = '[" . '""' . ",'||value||']'
19117a3a578SAndreas Gohr                           WHERE colref=$colno
19217a3a578SAndreas Gohr                             AND CAST(value AS DECIMAL) = value";
193ef747633SAnna Dabrowska                    $ok = $ok && $sqlite->query($s);
194ef747633SAnna Dabrowska                    if (!$ok) return false;
19576a74c23SAnna Dabrowska                }
19676a74c23SAnna Dabrowska            }
19776a74c23SAnna Dabrowska        }
19876a74c23SAnna Dabrowska
19976a74c23SAnna Dabrowska        // Step 3: delete temp_* tables
20076a74c23SAnna Dabrowska        foreach ($tables as $table) {
20176a74c23SAnna Dabrowska            $name = $table['name'];
20276a74c23SAnna Dabrowska            $s = "DROP TABLE temp_$name";
20376a74c23SAnna Dabrowska            $ok = $ok && $sqlite->query($s);
20476a74c23SAnna Dabrowska            if (!$ok) return false;
20576a74c23SAnna Dabrowska        }
20676a74c23SAnna Dabrowska
20776a74c23SAnna Dabrowska        // Step 4: remove islookup in schemas table
20876a74c23SAnna Dabrowska        $sql = "SELECT sql FROM sqlite_master
20976a74c23SAnna Dabrowska                WHERE type = 'table'
21076a74c23SAnna Dabrowska                AND name = 'schemas'";
21176a74c23SAnna Dabrowska        $res = $sqlite->query($sql);
21276a74c23SAnna Dabrowska        $t = $sqlite->res2arr($res);
21376a74c23SAnna Dabrowska        $sql = $t[0]['sql'];
21476a74c23SAnna Dabrowska        $sql = str_replace('islookup INTEGER,', '', $sql);
21576a74c23SAnna Dabrowska
21676a74c23SAnna Dabrowska        $s = 'ALTER TABLE schemas RENAME TO temp_schemas';
21776a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($s);
21876a74c23SAnna Dabrowska        if (!$ok) return false;
21976a74c23SAnna Dabrowska
22076a74c23SAnna Dabrowska        // create a new table without islookup
22176a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($sql);
22276a74c23SAnna Dabrowska        if (!$ok) return false;
22376a74c23SAnna Dabrowska
22476a74c23SAnna Dabrowska        $s = 'INSERT INTO schemas SELECT id, tbl, ts, user, comment, config FROM temp_schemas';
22576a74c23SAnna Dabrowska        $ok = $ok && $sqlite->query($s);
22676a74c23SAnna Dabrowska
22776a74c23SAnna Dabrowska        if (!$ok) {
22876a74c23SAnna Dabrowska            $sqlite->query('ROLLBACK TRANSACTION');
22976a74c23SAnna Dabrowska            return false;
23076a74c23SAnna Dabrowska        }
23176a74c23SAnna Dabrowska        $sqlite->query('COMMIT TRANSACTION');
23276a74c23SAnna Dabrowska        return true;
23376a74c23SAnna Dabrowska    }
234544dca1bSAnna Dabrowska
235544dca1bSAnna Dabrowska    /**
236544dca1bSAnna Dabrowska     * Executes Migration 17
237544dca1bSAnna Dabrowska     *
238544dca1bSAnna Dabrowska     * Fixes lookup data not correctly migrated by #16
239544dca1bSAnna Dabrowska     * All lookups were presumed to reference lookup data, not pages, so the migrated value
240544dca1bSAnna Dabrowska     * was always ["", <previous-pid-aka-new-rid>]. For page references it is ["<previous-pid>", 0]
241544dca1bSAnna Dabrowska     *
242544dca1bSAnna Dabrowska     * @param helper_plugin_sqlite $sqlite
243544dca1bSAnna Dabrowska     * @return bool
244544dca1bSAnna Dabrowska     */
245544dca1bSAnna Dabrowska    protected function migration17(helper_plugin_sqlite $sqlite)
246544dca1bSAnna Dabrowska    {
247544dca1bSAnna Dabrowska        $sql = "SELECT MAX(id) AS id, tbl FROM schemas
248544dca1bSAnna Dabrowska                    GROUP BY tbl
249544dca1bSAnna Dabrowska            ";
250544dca1bSAnna Dabrowska        $res = $sqlite->query($sql);
251544dca1bSAnna Dabrowska        $schemas = $sqlite->res2arr($res);
252544dca1bSAnna Dabrowska
253544dca1bSAnna Dabrowska        $sqlite->query('BEGIN TRANSACTION');
254544dca1bSAnna Dabrowska        $ok = true;
255544dca1bSAnna Dabrowska
256544dca1bSAnna Dabrowska        foreach ($schemas as $schema) {
257544dca1bSAnna Dabrowska            // find lookup columns
258544dca1bSAnna Dabrowska            $name = $schema['tbl'];
259544dca1bSAnna Dabrowska            $sid = $schema['id'];
260544dca1bSAnna Dabrowska            $s = $this->getLookupColsSql($sid);
261544dca1bSAnna Dabrowska            $res = $sqlite->query($s);
262544dca1bSAnna Dabrowska            $cols = $sqlite->res2arr($res);
263544dca1bSAnna Dabrowska
264544dca1bSAnna Dabrowska            if ($cols) {
265544dca1bSAnna Dabrowska                $colnames = array_map(function ($c) {
266544dca1bSAnna Dabrowska                    return 'col' . $c['COL'];
267544dca1bSAnna Dabrowska                }, $cols);
268544dca1bSAnna Dabrowska
269544dca1bSAnna Dabrowska                // data_ tables
270544dca1bSAnna Dabrowska                $s = 'SELECT pid, rid, rev, ' . implode(', ', $colnames) . " FROM data_$name";
271544dca1bSAnna Dabrowska                $res = $sqlite->query($s);
272544dca1bSAnna Dabrowska                $allValues = $sqlite->res2arr($res);
273544dca1bSAnna Dabrowska
274544dca1bSAnna Dabrowska                if (!empty($allValues)) {
275544dca1bSAnna Dabrowska                    foreach ($allValues as $row) {
276544dca1bSAnna Dabrowska                        list($pid, $rid, $rev, $colref, $rowno, $fixes) = $this->getFixedValues($row);
277544dca1bSAnna Dabrowska                        // now fix the values
278544dca1bSAnna Dabrowska                        if (!empty($fixes)) {
27917a3a578SAndreas Gohr                            $sql = "UPDATE data_$name
28017a3a578SAndreas Gohr                                       SET " . implode(', ', $fixes) . "
28117a3a578SAndreas Gohr                                     WHERE pid = ?
28217a3a578SAndreas Gohr                                       AND rid = ?
28317a3a578SAndreas Gohr                                       AND rev = ?";
284544dca1bSAnna Dabrowska                            $params = [$pid, $rid, $rev];
285544dca1bSAnna Dabrowska                            $ok = $ok && $sqlite->query($sql, $params);
286544dca1bSAnna Dabrowska                        }
287544dca1bSAnna Dabrowska                    }
288544dca1bSAnna Dabrowska                }
289544dca1bSAnna Dabrowska
290544dca1bSAnna Dabrowska                // multi_ tables
291544dca1bSAnna Dabrowska                $s = "SELECT colref, pid, rid, rev, row, value FROM multi_$name";
292544dca1bSAnna Dabrowska                $res = $sqlite->query($s);
293544dca1bSAnna Dabrowska                $allValues = $sqlite->res2arr($res);
294544dca1bSAnna Dabrowska
295544dca1bSAnna Dabrowska                if (!empty($allValues)) {
296544dca1bSAnna Dabrowska                    foreach ($allValues as $row) {
297544dca1bSAnna Dabrowska                        list($pid, $rid, $rev, $colref, $rowno, $fixes) = $this->getFixedValues($row);
298544dca1bSAnna Dabrowska                        // now fix the values
299544dca1bSAnna Dabrowska                        if (!empty($fixes)) {
30017a3a578SAndreas Gohr                            $sql = "UPDATE multi_$name
30117a3a578SAndreas Gohr                                       SET " . implode(', ', $fixes) . "
30217a3a578SAndreas Gohr                                     WHERE pid = ?
30317a3a578SAndreas Gohr                                       AND rid = ?
30417a3a578SAndreas Gohr                                       AND rev = ?
30517a3a578SAndreas Gohr                                       AND colref = ?
30617a3a578SAndreas Gohr                                       AND row = ?";
307544dca1bSAnna Dabrowska                            $params = [$pid, $rid, $rev, $colref, $rowno];
308544dca1bSAnna Dabrowska                            $ok = $ok && $sqlite->query($sql, $params);
309544dca1bSAnna Dabrowska                        }
310544dca1bSAnna Dabrowska                    }
311544dca1bSAnna Dabrowska                }
312544dca1bSAnna Dabrowska            }
313544dca1bSAnna Dabrowska        }
314544dca1bSAnna Dabrowska
315544dca1bSAnna Dabrowska        if (!$ok) {
316544dca1bSAnna Dabrowska            $sqlite->query('ROLLBACK TRANSACTION');
317544dca1bSAnna Dabrowska            return false;
318544dca1bSAnna Dabrowska        }
319544dca1bSAnna Dabrowska        $sqlite->query('COMMIT TRANSACTION');
320544dca1bSAnna Dabrowska        return true;
321544dca1bSAnna Dabrowska    }
322544dca1bSAnna Dabrowska
323544dca1bSAnna Dabrowska    /**
324bbd79bccSAnna Dabrowska     * Removes a temp table left over by migration 16
325bbd79bccSAnna Dabrowska     *
326bbd79bccSAnna Dabrowska     * @param helper_plugin_sqlite $sqlite
327bbd79bccSAnna Dabrowska     * @return bool
328bbd79bccSAnna Dabrowska     */
329bbd79bccSAnna Dabrowska    protected function migration18(helper_plugin_sqlite $sqlite)
330bbd79bccSAnna Dabrowska    {
331bbd79bccSAnna Dabrowska        $ok = true;
332bbd79bccSAnna Dabrowska        $sqlite->query('BEGIN TRANSACTION');
333bbd79bccSAnna Dabrowska
334bbd79bccSAnna Dabrowska        $sql = 'DROP TABLE IF EXISTS temp_schemas';
335bbd79bccSAnna Dabrowska        $ok = $ok && $sqlite->query($sql);
336bbd79bccSAnna Dabrowska
337bbd79bccSAnna Dabrowska        if (!$ok) {
338bbd79bccSAnna Dabrowska            $sqlite->query('ROLLBACK TRANSACTION');
339bbd79bccSAnna Dabrowska            return false;
340bbd79bccSAnna Dabrowska        }
341bbd79bccSAnna Dabrowska        $sqlite->query('COMMIT TRANSACTION');
342bbd79bccSAnna Dabrowska        return true;
343bbd79bccSAnna Dabrowska    }
344*fc6ac2e5SAnna Dabrowska    /**
345*fc6ac2e5SAnna Dabrowska     * Executes Migration 19
346*fc6ac2e5SAnna Dabrowska     *
347*fc6ac2e5SAnna Dabrowska     * Add "published" column to all existing tables
348*fc6ac2e5SAnna Dabrowska     *
349*fc6ac2e5SAnna Dabrowska     * @param helper_plugin_sqlite $sqlite
350*fc6ac2e5SAnna Dabrowska     * @return bool
351*fc6ac2e5SAnna Dabrowska     */
352*fc6ac2e5SAnna Dabrowska    protected function migration19(helper_plugin_sqlite $sqlite)
353*fc6ac2e5SAnna Dabrowska    {
354*fc6ac2e5SAnna Dabrowska        $ok = true;
355*fc6ac2e5SAnna Dabrowska        $sqlite->query('BEGIN TRANSACTION');
356*fc6ac2e5SAnna Dabrowska
357*fc6ac2e5SAnna Dabrowska        /** @noinspection SqlResolve */
358*fc6ac2e5SAnna Dabrowska        $sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND (name LIKE 'data_%' OR name LIKE 'multi_%')";
359*fc6ac2e5SAnna Dabrowska        $res = $sqlite->query($sql);
360*fc6ac2e5SAnna Dabrowska        $tables = $sqlite->res2arr($res);
361*fc6ac2e5SAnna Dabrowska        $sqlite->res_close($res);
362*fc6ac2e5SAnna Dabrowska
363*fc6ac2e5SAnna Dabrowska        foreach ($tables as $row) {
364*fc6ac2e5SAnna Dabrowska            $sql = 'ALTER TABLE ? ADD COLUMN published INT DEFAULT NULL';
365*fc6ac2e5SAnna Dabrowska            $ok = $ok && $sqlite->query($sql, $row['name']);
366*fc6ac2e5SAnna Dabrowska        }
367*fc6ac2e5SAnna Dabrowska        if (!$ok) {
368*fc6ac2e5SAnna Dabrowska            $sqlite->query('ROLLBACK TRANSACTION');
369*fc6ac2e5SAnna Dabrowska            return false;
370*fc6ac2e5SAnna Dabrowska        }
371*fc6ac2e5SAnna Dabrowska        $sqlite->query('COMMIT TRANSACTION');
372*fc6ac2e5SAnna Dabrowska        return true;
373*fc6ac2e5SAnna Dabrowska    }
374*fc6ac2e5SAnna Dabrowska
375bbd79bccSAnna Dabrowska
376bbd79bccSAnna Dabrowska    /**
377544dca1bSAnna Dabrowska     * Returns a select statement to fetch Lookup columns in the current schema
378544dca1bSAnna Dabrowska     *
379544dca1bSAnna Dabrowska     * @param int $sid Id of the schema
380544dca1bSAnna Dabrowska     * @return string SQL statement
381544dca1bSAnna Dabrowska     */
382544dca1bSAnna Dabrowska    protected function getLookupColsSql($sid)
383544dca1bSAnna Dabrowska    {
384544dca1bSAnna Dabrowska        return "SELECT C.colref AS COL, T.class AS TYPE
385544dca1bSAnna Dabrowska                FROM schema_cols AS C
386544dca1bSAnna Dabrowska                LEFT OUTER JOIN types AS T
387544dca1bSAnna Dabrowska                    ON C.tid = T.id
388544dca1bSAnna Dabrowska                WHERE C.sid = $sid
389544dca1bSAnna Dabrowska                AND TYPE LIKE '%Lookup'
390544dca1bSAnna Dabrowska            ";
391544dca1bSAnna Dabrowska    }
392544dca1bSAnna Dabrowska
393544dca1bSAnna Dabrowska    /**
394544dca1bSAnna Dabrowska     * Checks for improperly migrated values and returns an array with
395544dca1bSAnna Dabrowska     * "<column> = <fixed-value>" fragments to be used in the UPDATE statement.
396544dca1bSAnna Dabrowska     *
397544dca1bSAnna Dabrowska     * @param array $row
398544dca1bSAnna Dabrowska     * @return array
399544dca1bSAnna Dabrowska     */
400544dca1bSAnna Dabrowska    protected function getFixedValues($row)
401544dca1bSAnna Dabrowska    {
402544dca1bSAnna Dabrowska        $pid = $row['pid'];
403544dca1bSAnna Dabrowska        $rid = $row['rid'];
404544dca1bSAnna Dabrowska        $rev = $row['rev'];
405544dca1bSAnna Dabrowska        $colref = $row['colref'];
406544dca1bSAnna Dabrowska        $rowno = $row['row'];
407544dca1bSAnna Dabrowska        $fixes = [];
408544dca1bSAnna Dabrowska        $matches = [];
409544dca1bSAnna Dabrowska
410544dca1bSAnna Dabrowska        // check if anything needs to be fixed in data columns
411544dca1bSAnna Dabrowska        foreach ($row as $col => $value) {
412544dca1bSAnna Dabrowska            if (in_array($col, ['pid', 'rid', 'rev', 'colref', 'row'])) {
413544dca1bSAnna Dabrowska                continue;
414544dca1bSAnna Dabrowska            }
415544dca1bSAnna Dabrowska            preg_match('/^\["",(?<pid>.*?\D+.*?)\]$/', $value, $matches);
416544dca1bSAnna Dabrowska            if (!empty($matches['pid'])) {
417544dca1bSAnna Dabrowska                $fixes[$col] = '["' . $matches['pid'] . '",0]';
418544dca1bSAnna Dabrowska            }
419544dca1bSAnna Dabrowska        }
420544dca1bSAnna Dabrowska
421544dca1bSAnna Dabrowska        if (!empty($fixes)) {
422544dca1bSAnna Dabrowska            $fixes = array_map(function ($set, $key) {
423544dca1bSAnna Dabrowska                return "$key = '$set'";
424544dca1bSAnna Dabrowska            }, $fixes, array_keys($fixes));
425544dca1bSAnna Dabrowska        }
426544dca1bSAnna Dabrowska
427544dca1bSAnna Dabrowska        return [$pid, $rid, $rev, $colref, $rowno, $fixes];
428544dca1bSAnna Dabrowska    }
4298f259467SAndreas Gohr}
430