Skip to content
Snippets Groups Projects
Commit ef6f6a80 authored by Tim van Dijen's avatar Tim van Dijen
Browse files

While at it: flatten database table migrations

parent 80ca0308
No related branches found
No related tags found
No related merge requests found
......@@ -95,7 +95,7 @@ class SQLStore implements StoreInterface
}
while (($row = $fetchTableVersion->fetch(PDO::FETCH_ASSOC)) !== false) {
$this->tableVersions[$row['_name']] = (int) $row['_version'];
$this->tableVersions[$row['_name']] = intval($row['_version']);
}
}
......@@ -105,74 +105,37 @@ class SQLStore implements StoreInterface
*/
private function initKVTable(): void
{
$current_version = $this->getTableVersion('kvstore');
$tableVer = $this->getTableVersion('kvstore');
if ($tableVer === 2) {
return;
} elseif ($tableVer < 2 && $tableVer > 0) {
throw new Exception('No upgrade path available. Please migrate to the latest 1.16+ version of SimpleSAMLphp first before upgrading to 2.x.');
}
$text_t = 'TEXT';
$time_field = 'TIMESTAMP';
if ($this->driver === 'mysql') {
// TEXT data type has size constraints that can be hit at some point, so we use LONGTEXT instead
$text_t = 'LONGTEXT';
}
$time_field = 'TIMESTAMP';
if ($this->driver === 'sqlsrv') {
// TIMESTAMP will not work for MSSQL. TIMESTAMP is automatically generated and cannot be inserted
// so we use DATETIME instead
$time_field = 'DATETIME';
}
/**
* Queries for updates, grouped by version.
* New updates can be added as a new array in this array
*/
$table_updates = [
[
'CREATE TABLE ' . $this->prefix .
'_kvstore (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value ' . $text_t .
' NOT NULL, _expire ' . $time_field . ', PRIMARY KEY (_key, _type))',
$this->driver === 'sqlite' || $this->driver === 'sqlsrv' || $this->driver === 'pgsql' ?
'CREATE INDEX ' . $this->prefix . '_kvstore_expire ON ' . $this->prefix . '_kvstore (_expire)' :
'ALTER TABLE ' . $this->prefix . '_kvstore ADD INDEX ' . $this->prefix . '_kvstore_expire (_expire)'
],
/**
* This upgrade removes the default NOT NULL constraint on the _expire field in MySQL.
* Because SQLite does not support field alterations, the approach is to:
* Create a new table without the NOT NULL constraint
* Copy the current data to the new table
* Drop the old table
* Rename the new table correctly
* Read the index
*/
[
'CREATE TABLE ' . $this->prefix .
'_kvstore_new (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value ' . $text_t .
' NOT NULL, _expire ' . $time_field . ' NULL, PRIMARY KEY (_key, _type))',
'INSERT INTO ' . $this->prefix . '_kvstore_new SELECT * FROM ' . $this->prefix . '_kvstore',
'DROP TABLE ' . $this->prefix . '_kvstore',
// FOR MSSQL use EXEC sp_rename to rename a table (RENAME won't work)
$this->driver === 'sqlsrv' ?
'EXEC sp_rename ' . $this->prefix . '_kvstore_new, ' . $this->prefix . '_kvstore' :
'ALTER TABLE ' . $this->prefix . '_kvstore_new RENAME TO ' . $this->prefix . '_kvstore',
$this->driver === 'sqlite' || $this->driver === 'sqlsrv' || $this->driver === 'pgsql' ?
'CREATE INDEX ' . $this->prefix . '_kvstore_expire ON ' . $this->prefix . '_kvstore (_expire)' :
'ALTER TABLE ' . $this->prefix . '_kvstore ADD INDEX ' . $this->prefix . '_kvstore_expire (_expire)'
]
];
$latest_version = count($table_updates);
if ($current_version == $latest_version) {
return;
}
// Only run queries for after the current version
$updates_to_run = array_slice($table_updates, $current_version);
$query = 'CREATE TABLE ' . $this->prefix .
'_kvstore (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value ' . $text_t .
' NOT NULL, _expire ' . $time_field . ' NULL, PRIMARY KEY (_key, _type))';
$this->pdo->exec($query);
foreach ($updates_to_run as $version_updates) {
foreach ($version_updates as $query) {
$this->pdo->exec($query);
}
}
$query = $this->driver === 'sqlite' || $this->driver === 'sqlsrv' || $this->driver === 'pgsql' ?
'CREATE INDEX ' . $this->prefix . '_kvstore_expire ON ' . $this->prefix . '_kvstore (_expire)' :
'ALTER TABLE ' . $this->prefix . '_kvstore ADD INDEX ' . $this->prefix . '_kvstore_expire (_expire)';
$this->pdo->exec($query);
$this->setTableVersion('kvstore', $latest_version);
$this->setTableVersion('kvstore', 2);
}
......
......@@ -32,156 +32,8 @@ class LogoutStore
$tableVer = $store->getTableVersion('saml_LogoutStore');
if ($tableVer === 4) {
return;
} elseif ($tableVer === 3) {
/**
* Table version 4 fixes the column type for the _expire column.
* We now use DATETIME instead of TIMESTAMP to support MSSQL.
*/
switch ($store->driver) {
case 'pgsql':
// This does not affect the NOT NULL constraint
$update = [
'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore ALTER COLUMN _expire TYPE TIMESTAMP'
];
break;
case 'sqlsrv':
$update = [
'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore ALTER COLUMN _expire DATETIME NOT NULL'
];
break;
case 'sqlite':
/**
* Because SQLite does not support field alterations, the approach is to:
* Create a new table without the proper column size
* Copy the current data to the new table
* Drop the old table
* Rename the new table correctly
* Read the index
*/
$update = [
'CREATE TABLE ' . $store->prefix . '_saml_LogoutStore_new (' .
'_authSource VARCHAR(255) NOT NULL, _nameId VARCHAR(40) NOT NULL' .
', _sessionIndex VARCHAR(50) NOT NULL, _expire DATETIME NOT NULL,' .
'_sessionId VARCHAR(50) NOT NULL, UNIQUE (_authSource, _nameID, _sessionIndex))',
'INSERT INTO ' . $store->prefix . '_saml_LogoutStore_new SELECT * FROM ' .
$store->prefix . '_saml_LogoutStore',
'DROP TABLE ' . $store->prefix . '_saml_LogoutStore',
'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore_new RENAME TO ' .
$store->prefix . '_saml_LogoutStore',
'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_expire ON ' .
$store->prefix . '_saml_LogoutStore (_expire)',
'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON ' .
$store->prefix . '_saml_LogoutStore (_authSource, _nameId)'
];
break;
default:
$update = [
'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore MODIFY _expire DATETIME NOT NULL'
];
break;
}
try {
foreach ($update as $query) {
$store->pdo->exec($query);
}
} catch (\Exception $e) {
Logger::warning('Database error: ' . var_export($store->pdo->errorInfo(), true));
return;
}
$store->setTableVersion('saml_LogoutStore', 4);
return;
} elseif ($tableVer === 2) {
/**
* TableVersion 3 fixes the indexes that were set to 255 in version 2;
* they cannot be larger than 191 on MySQL
*/
if ($store->driver === 'mysql') {
// Drop old indexes
$query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore DROP INDEX ' .
$store->prefix . '_saml_LogoutStore_nameId';
$store->pdo->exec($query);
$query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore DROP INDEX _authSource';
$store->pdo->exec($query);
// Create new indexes
$query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON ';
$query .= $store->prefix . '_saml_LogoutStore (_authSource(191), _nameId)';
$store->pdo->exec($query);
$query = 'ALTER TABLE ' . $store->prefix .
'_saml_LogoutStore ADD UNIQUE KEY (_authSource(191), _nameID, _sessionIndex)';
$store->pdo->exec($query);
}
$store->setTableVersion('saml_LogoutStore', 3);
return;
} elseif ($tableVer === 1) {
// TableVersion 2 increased the column size to 255 (191 for mysql) which is the maximum length of a FQDN
switch ($store->driver) {
case 'pgsql':
// This does not affect the NOT NULL constraint
$update = [
'ALTER TABLE ' . $store->prefix .
'_saml_LogoutStore ALTER COLUMN _authSource TYPE VARCHAR(255)'];
break;
case 'sqlsrv':
$update = [
'ALTER TABLE ' . $store->prefix .
'_saml_LogoutStore ALTER COLUMN _authSource VARCHAR(255) NOT NULL'
];
break;
case 'sqlite':
/**
* Because SQLite does not support field alterations, the approach is to:
* Create a new table without the proper column size
* Copy the current data to the new table
* Drop the old table
* Rename the new table correctly
* Read the index
*/
$update = [
'CREATE TABLE ' . $store->prefix .
'_saml_LogoutStore_new (_authSource VARCHAR(255) NOT NULL,' .
'_nameId VARCHAR(40) NOT NULL, _sessionIndex VARCHAR(50) NOT NULL, ' .
'_expire TIMESTAMP NOT NULL, _sessionId VARCHAR(50) NOT NULL, UNIQUE ' .
'(_authSource, _nameID, _sessionIndex))',
'INSERT INTO ' . $store->prefix . '_saml_LogoutStore_new SELECT * FROM ' .
$store->prefix . '_saml_LogoutStore',
'DROP TABLE ' . $store->prefix . '_saml_LogoutStore',
'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore_new RENAME TO ' .
$store->prefix . '_saml_LogoutStore',
'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_expire ON ' .
$store->prefix . '_saml_LogoutStore (_expire)',
'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON ' .
$store->prefix . '_saml_LogoutStore (_authSource, _nameId)'
];
break;
case 'mysql':
$update = [
'ALTER TABLE ' . $store->prefix .
'_saml_LogoutStore MODIFY _authSource VARCHAR(191) NOT NULL'
];
break;
default:
$update = [
'ALTER TABLE ' . $store->prefix .
'_saml_LogoutStore MODIFY _authSource VARCHAR(255) NOT NULL'
];
break;
}
try {
foreach ($update as $query) {
$store->pdo->exec($query);
}
} catch (\Exception $e) {
Logger::warning('Database error: ' . var_export($store->pdo->errorInfo(), true));
return;
}
$store->setTableVersion('saml_LogoutStore', 2);
return;
} elseif ($tableVer < 4 && $tableVer > 0) {
throw new Exception('No upgrade path available. Please migrate to the latest 1.18+ version of SimpleSAMLphp first before upgrading to 2.x.');
}
$query = 'CREATE TABLE ' . $store->prefix . '_saml_LogoutStore (
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment