database update scripts

This commit is contained in:
david 2002-04-19 18:58:31 +00:00
parent 6e81a1afc4
commit 457bafc3b6
3 changed files with 533 additions and 0 deletions

View File

@ -0,0 +1,24 @@
*** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
ALWAYS BACK UP YOUR DATABASE BEFORE
ATTEMPTING TO UPDATE IT!
TAKE THIS WARNING SERIOUSLY, OR PAY THE CONSEQUENCES!!!
*** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
These are scripts for updating the database tables between releases.
They are named according to the version to which they convert the database.
So, update-0.2 updates the database from version 0.1 to version 0.2.
The scripts use config.version to identify the current database version, and
abort if you're trying to do something illegal.
No attempt is made to update from, say, 0.1 to 0.3. To update from 0.1 to 0.3
you have to run update-0.2, then update-0.3.
After you run the update script, back up your data again. You must have saved
your first backup in a safe location, because it will be overwritten. Then,
recreate your database using the new createdb.sh, and reload your data. This
is required because the update script is not guaranteed to establish all
referential integrity rules, only table structures.

View File

@ -0,0 +1,444 @@
#! /usr/bin/perl
#
$LAST_VERSION = '0.1';
$VERSION = '0.2';
use Pg;
use String::Random;
$dbmain = "ldp";
@row;
$conn=Pg::connectdb("dbname=$dbmain");
$result = $conn->exec("SELECT value FROM config WHERE name='version'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
@row = $result->fetchrow;
$version = $row[0];
$version =~ s/\s+$//;
if ($version ne $LAST_VERSION) {
print "ERROR: This script can only update from version $LAST_VERSION to $VERSION\n";
exit(1);
}
%maintainers = ();
%editors = ();
# Create new username table
#
$sql = "DROP TABLE username_new";
$conn->exec("$sql");
$sql = "CREATE TABLE username_new (user_id INT4 NOT NULL, username CHAR(20) NOT NULL, session_id CHAR(20), first_name CHAR(20), middle_name CHAR(20), surname CHAR(20), email TEXT, admin BOOLEAN, password CHAR(12), notes TEXT);";
$conn->exec("$sql");
$sql = "CREATE UNIQUE INDEX username ON username_new(username)";
$conn->exec("$sql");
# Copy users over to new table
#
$sql = "INSERT INTO username_new(user_id, username, first_name, middle_name, surname, email, admin) SELECT 0, username, first_name, '', surname, email, admin FROM username";
$conn->exec("$sql");
# Assign the users sequential user_ids
#
$new_user_id = 0;
$result = $conn->exec("SELECT username FROM username_new");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$username = $row[0];
$username =~ s/\s+$//;
$new_user_id++;
$sql = "UPDATE username_new SET user_id=$new_user_id WHERE username='$username'";
$conn->exec("$sql");
}
# Create accounts for maintainers
#
$result = $conn->exec("SELECT maintainer_id, maintainer_name, email FROM maintainer");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$maintainer_id = $row[0];
$maintainer_name = $row[1];
$email = $row[2];
# Try to match it up with an existing user account
#
$result2 = $conn->exec("SELECT COUNT(*) FROM username WHERE maintainer_id=$maintainer_id");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
if ($row2[0]) {
# There's already a user account, just remember how to map it
#
$result2 = $conn->exec("SELECT username FROM username WHERE maintainer_id=$maintainer_id");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$username = $row2[0];
$username =~ s/\s+$//;
$result2 = $conn->exec("SELECT user_id FROM username_new WHERE username='$username'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$user_id = $row2[0];
$maintainers{$maintainer_id} = $user_id;
} else {
# There is no user account for this maintainer yet, so create one
#
$new_user_id++;
$username = $maintainer_name;
$result2 = $conn->exec("SELECT COUNT(*) FROM username WHERE username=" . wsq($username));
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
if ($row2[0]) {
print "ERROR: duplicate username $username\n";
exit(1);
}
($first_name, $middle_name, $surname) = &splitname($maintainer_name);
$sql = "INSERT INTO username_new(user_id, username, first_name, middle_name, surname, email, admin) VALUES ($new_user_id, '$username', '$first_name', '$middle_name', " . wsq($surname) . ", '$email', 'f')";
$conn->exec("$sql");
$maintainers{$maintainer_id} = $new_user_id;
}
}
# Create accounts for editors
#
$result = $conn->exec("SELECT editor_id, editor_name, email, notes FROM editor");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$editor_id = $row[0];
$editor_name = $row[1];
$email = $row[2];
$notes = $row[3];
# Try to match it up with an existing user account
#
$result2 = $conn->exec("SELECT COUNT(*) FROM username WHERE editor_id=$editor_id");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
if ($row2[0]) {
# There's already a user account, just remember how to map it
#
$result2 = $conn->exec("SELECT username FROM username WHERE editor_id=$editor_id");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$username = $row2[0];
$username =~ s/\s+$//;
$result2 = $conn->exec("SELECT user_id FROM username_new WHERE username='$username'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$user_id = $row2[0];
$editors{$editor_id} = $user_id;
$sql = "UPDATE username_new SET notes = " . wsq($notes) . " WHERE user_id=$user_id";
$conn->exec("$sql");
} else {
# There was no user account originally, but we could have created one in the previous step.
#
$result2 = $conn->exec("SELECT COUNT(*) FROM username_new WHERE username=" . wsq($editor_name));
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
if ($row2[0]) {
$result2 = $conn->exec("SELECT user_id FROM username_new WHERE username='$username'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$user_id = $row2[0];
$editors{$editor_id} = $user_id;
$sql = "UPDATE username_new SET notes = " . wsq($notes) . " WHERE user_id=$user_id";
$conn->exec("$sql");
} else {
# There is no user account for this editor yet, so create one
#
$new_user_id++;
$username = $editor_name;
$result2 = $conn->exec("SELECT COUNT(*) FROM username WHERE username=" . wsq($username));
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
if ($row2[0]) {
print "ERROR: duplicate username $username\n";
exit(1);
}
($first_name, $middle_name, $surname) = &splitname($editor_name);
$sql = "INSERT INTO username_new(user_id, username, first_name, middle_name, surname, email, admin, notes) VALUES ($new_user_id, '$username', '$first_name', '$middle_name', " . wsq($surname) . ", '$email', 'f'," . wsq($notes) . ")";
$conn->exec("$sql");
$editors{$editor_id} = $new_user_id;
}
}
}
# Create new role table
#
$sql = "DROP TABLE role_new";
$conn->exec("$sql");
$sql = "CREATE TABLE role_new (role CHAR(12), PRIMARY KEY (role))";
$conn->exec("$sql");
# Append roles to the new role table merging editor_role and role
#
$sql = "INSERT INTO role_new(role) SELECT role from role";
$conn->exec("$sql");
$sql = "INSERT INTO role_new(role) SELECT editor_role from editor_role";
$conn->exec("$sql");
# Create new document_user table
#
$sql = "DROP TABLE document_user";
$conn->exec("$sql");
$sql = "CREATE TABLE document_user (doc_id INT4 NOT NULL, user_id INT4 NOT NULL, role CHAR(12) NOT NULL, email TEXT, active BOOLEAN NOT NULL, PRIMARY KEY (doc_id, user_id, role));";
$conn->exec("$sql");
# Copy over maintainer assignments
#
$sql = "SELECT doc_id, maintainer_id, role, active, email FROM document_maintainer";
$result = $conn->exec("$sql");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$doc_id = $row[0];
$maintainer_id= $row[1];
$user_id = $maintainers{$maintainer_id};
unless ($user_id) {
print "ERROR: couldn't locate maintainer $maintainer_id in new user table\n";
exit(1);
}
$role = $row[2];
$active = $row[3];
$email = $row[4];
$sql = "INSERT INTO document_user (doc_id, user_id, role, email, active) VALUES ($doc_id, $user_id, '$role', '$email', '$active')";
$conn->exec("$sql");
}
# Copy over editor assignments
#
$sql = "SELECT doc_id, editor_id, editor_role, active FROM document_editor";
$result = $conn->exec("$sql");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$doc_id = $row[0];
$editor_id= $row[1];
$user_id = $editors{$editor_id};
unless ($user_id) {
print "ERROR: couldn't locate editor $editor_id in new user table\n";
exit(1);
}
$role = $row[2];
$active = $row[3];
$sql = "INSERT INTO document_user (doc_id, user_id, role, email, active) VALUES ($doc_id, $user_id, '$role', '', '$active')";
$conn->exec("$sql");
}
# Copy maintainer notes
#
$sql = "DROP TABLE username_notes";
$conn->exec("$sql");
$sql = "CREATE TABLE username_notes (user_id INT4 NOT NULL, date_entered TIMESTAMP NOT NULL DEFAULT now(), notes TEXT, creator_id INT4 NOT NULL)";
$conn->exec("$sql");
$sql = "SELECT maintainer_id, date_entered, notes, username FROM maintainer_notes";
$result = $conn->exec("$sql");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$maintainer_id = $row[0];
$user_id = $maintainers{$maintainer_id};
unless ($user_id) {
print "ERROR: couldn't locate maintainer $maintainer_id in new user table\n";
exit(1);
}
$date_entered = $row[1];
$notes = $row[2];
$username = $row[3];
$result2 = $conn->exec("SELECT user_id FROM username_new WHERE username='$username'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$creator_id = $row2[0];
$sql = "INSERT INTO username_notes(user_id, date_entered, notes, creator_id) VALUES ($user_id, " . wsq($date_entered) . ", " . wsq($notes) . ", $creator_id)";
$conn->exec("$sql");
}
# Copy document notes
#
$sql = "DROP TABLE notes_new";
$conn->exec("$sql");
$sql = "CREATE TABLE notes_new (doc_id INT4 NOT NULL, date_entered TIMESTAMP NOT NULL DEFAULT now(), notes TEXT, creator_id INT4)";
$conn->exec("$sql");
$sql = "SELECT doc_id, date_entered, notes, username FROM notes";
$result = $conn->exec("$sql");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
while (@row = $result->fetchrow) {
$doc_id = $row[0];
$date_entered = $row[1];
$notes = $row[2];
$username = $row[3];
$username =~ s/\s+$//;
$result2 = $conn->exec("SELECT user_id FROM username_new WHERE username='$username'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result2->resultStatus;
@row2 = $result2->fetchrow;
$creator_id = $row2[0];
$sql = "INSERT INTO notes_new(doc_id, date_entered, notes, creator_id) VALUES ($doc_id, " . wsq($date_entered) . ", " . wsq($notes) . ", $creator_id)";
$conn->exec("$sql");
}
# Drop some fields from the document table
#
$sql = "DROP TABLE document_new";
$conn->exec("$sql");
$sql = "CREATE TABLE document_new (doc_id INT4 NOT NULL, title TEXT NOT NULL, class CHAR(12), format CHAR(12), dtd CHAR(12), dtd_version CHAR(12), version CHAR(12), last_update DATE, URL TEXT, ISBN TEXT, pub_status CHAR, review_status CHAR, tickle_date DATE, pub_date DATE, ref_url TEXT, tech_review_status CHAR, maintained BOOLEAN DEFAULT False, license CHAR(12), abstract TEXT, rating REAL, PRIMARY KEY (doc_id))";
$conn->exec("$sql");
$sql = "INSERT INTO document_new SELECT doc_id, title, class, format, dtd, dtd_version, version, last_update, url, isbn, pub_status, review_status, tickle_date, pub_date, ref_url, tech_review_status, maintained, license, abstract, rating FROM document";
$conn->exec("$sql");
# Switch doc_vote to use user_id instead of username
#
$sql = "DROP TABLE doc_vote_new";
$conn->exec("$sql");
$sql = "CREATE TABLE doc_vote_new (doc_id INT4 NOT NULL, user_id INT4 NOT NULL, date_entered TIMESTAMP NOT NULL DEFAULT now(), vote INT4 NOT NULL, PRIMARY KEY (doc_id, user_id))";
$conn->exec("$sql");
$sql = "INSERT INTO doc_vote_new SELECT doc_id, user_id, date_entered, vote FROM doc_vote, username_new WHERE username_new.username = doc_vote.username";
$conn->exec("$sql");
# Update the document_wiki table
#
$sql = "DROP TABLE document_wiki_new";
$conn->exec("$sql");
$sql = "CREATE TABLE document_wiki_new(doc_id INT4 NOT NULL, revision INT4 NOT NULL, date_entered TIMESTAMP NOT NULL DEFAULT now(), wiki TEXT, notes CHAR(256), user_id INT4)";
$conn->exec("$sql");
$sql = "INSERT INTO document_wiki_new SELECT doc_id, revision, date_entered, wiki, document_wiki.notes, user_id FROM document_wiki, username_new WHERE document_wiki.username = username_new.username";
$conn->exec("$sql");
# Add "free" column to license table
#
$sql = "ALTER TABLE license ADD COLUMN free BOOLEAN";
$conn->exec($sql);
$sql = "UPDATE license SET free='t' WHERE license='GPL' or license='GFDL' or license='PD' or license='OPL'";
$conn->exec($sql);
$sql = "UPDATE license SET free='f' WHERE free IS NULL";
$conn->exec($sql);
# Create document_file table
#
$sql = "DROP TABLE document_file";
$conn->exec($sql);
$sql = "CREATE TABLE document_file(doc_id INT4 NOT NULL, filename CHAR(60) NOT NULL, PRIMARY KEY (doc_id, filename))";
$conn->exec($sql);
$sql = "INSERT INTO document_file(doc_id, filename) SELECT doc_id, filename FROM document WHERE filename<>''";
$conn->exec($sql);
# Create document_error table
#
$sql = "DROP TABLE document_error";
$conn->exec($sql);
$sql = "CREATE TABLE document_error(doc_id INT4 NOT NULL, error TEXT)";
$conn->exec($sql);
# Copy the new tables over to replace the old ones
#
$conn->exec("DROP TABLE document");
$conn->exec("DROP TABLE document_editor");
$conn->exec("DROP TABLE document_maintainer");
$conn->exec("DROP TABLE document_wiki");
$conn->exec("DROP TABLE doc_vote");
$conn->exec("DROP TABLE editor");
$conn->exec("DROP TABLE editor_role");
$conn->exec("DROP TABLE maintainer");
$conn->exec("DROP TABLE maintainer_notes");
$conn->exec("DROP TABLE notes");
$conn->exec("DROP TABLE role");
$conn->exec("DROP TABLE username");
$conn->exec("DROP TABLE volunteer");
$conn->exec("ALTER TABLE document_new RENAME TO document");
$conn->exec("ALTER TABLE document_wiki_new RENAME TO document_wiki");
$conn->exec("ALTER TABLE doc_vote_new RENAME TO doc_vote");
$conn->exec("ALTER TABLE notes_new RENAME TO notes");
$conn->exec("ALTER TABLE role_new RENAME TO role");
$conn->exec("ALTER TABLE username_new RENAME TO username");
# Update permissions for the new tables
#
$conn->exec('GRANT ALL ON document TO "www-data"');
$conn->exec('GRANT ALL ON document_error TO "www-data"');
$conn->exec('GRANT ALL ON document_user TO "www-data"');
$conn->exec('GRANT ALL ON document_wiki TO "www-data"');
$conn->exec('GRANT ALL ON document_file TO "www-data"');
$conn->exec('GRANT ALL ON doc_vote TO "www-data"');
$conn->exec('GRANT ALL ON notes TO "www-data"');
$conn->exec('GRANT ALL ON role TO "www-data"');
$conn->exec('GRANT ALL ON username TO "www-data"');
$conn->exec('GRANT ALL ON username_notes TO "www-data"');
$conn->exec('GRANT ALL ON dtd TO "www-data"');
$conn->exec('GRANT ALL ON format TO "www-data"');
$conn->exec('GRANT ALL ON license TO "www-data"');
$conn->exec('GRANT ALL ON pub_status TO "www-data"');
$conn->exec('GRANT ALL ON review_status TO "www-data"');
$conn->exec('GRANT ALL ON topic TO "www-data"');
$conn->exec('GRANT ALL ON subtopic TO "www-data"');
# Alter the case of the classes
#
$conn->exec("UPDATE class SET class='Backgrounder' WHERE class='BACKGROUNDER'");
$conn->exec("UPDATE document SET class='Backgrounder' WHERE class='BACKGROUNDER'");
$conn->exec("UPDATE class SET class='Mini' WHERE class='MINI'");
$conn->exec("UPDATE document SET class='Mini' WHERE class='MINI'");
$conn->exec("UPDATE class SET class='Mini' WHERE class='MINI'");
$conn->exec("UPDATE document SET class='Mini' WHERE class='MINI'");
$conn->exec("UPDATE class SET class='Template' WHERE class='TEMPLATE'");
$conn->exec("UPDATE document SET class='Template' WHERE class='TEMPLATE'");
$conn->exec("UPDATE class SET class='Guide' WHERE class='GUIDE'");
$conn->exec("UPDATE document SET class='Guide' WHERE class='GUIDE'");
$conn->exec("UPDATE class SET class='Quick' WHERE class='QUICK'");
$conn->exec("UPDATE document SET class='Quick' WHERE class='QUICK'");
# Alter the review_status "Review in Progress"
#
$conn->exec("UPDATE review_status SET review_status_name='Pending' WHERE review_status='P'");
# Alter the LANG and TECH roles
#
$conn->exec("UPDATE role SET role='Editor' WHERE role='LANG'");
$conn->exec("UPDATE role SET role='Fact Checker' WHERE role='TECH'");
$conn->exec("UPDATE document_user SET role='Editor' WHERE role='LANG'");
$conn->exec("UPDATE document_user SET role='Fact Checker' WHERE role='TECH'");
# Update the database version
#
$conn->exec("UPDATE CONFIG SET value='$VERSION' WHERE name='version'");
sub splitname {
my $name = shift;
my $first_name = '';
my $middle_name = '';
my $mi1 = '';
my $mi2 = '';
my $surname = '';
$name =~ s/^Dr\.\s+//;
my @pieces = split(/ /, $name);
if (scalar @pieces == 0) {
} elsif (scalar @pieces == 1) {
$first_name = $name;
} elsif (scalar @pieces == 2) {
($first_name, $surname) = split(/ /, $name);
} elsif (scalar @pieces == 3) {
($first_name, $middle_name, $surname) = split(/ /, $name);
} elsif (scalar @pieces == 4) {
($first_name, $mi1, $mi2, $surname) = split(/ /, $name);
$middle_name = $mi1 . ' ' . $mi2;
} else {
print "ERROR: Name too long ($name)\n";
exit(1);
}
if ((uc($middle_name) eq 'VAN') or
(uc($middle_name) eq 'VAN DER') or
(uc($middle_name) eq 'VAN DEN') or
(uc($middle_name) eq 'DE') or
(uc($middle_name) eq 'DE LA') or
(uc($middle_name) eq 'DER')) {
$surname = $middle_name . ' ' . $surname;
$middle_name = '';
}
return ($first_name, $middle_name, $surname);
}
sub wsq {
my $temp = shift;
$temp =~ s/'/''/g;
return "'" . $temp . "'";
}

View File

@ -0,0 +1,65 @@
#! /usr/bin/perl
#
$LAST_VERSION = '0.2';
$VERSION = '0.3';
use Pg;
$dbmain = "ldp";
@row;
$conn=Pg::connectdb("dbname=$dbmain");
$result = $conn->exec("SELECT value FROM config WHERE name='version'");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
@row = $result->fetchrow;
$version = $row[0];
$version =~ s/\s+$//;
if ($version ne $LAST_VERSION) {
print "ERROR: This script can only update from version $LAST_VERSION to $VERSION\n";
exit(1);
}
# i18n support in class table
#
$sql = "CREATE TABLE class_new (class_id INT4 NOT NULL, PRIMARY KEY (class_id))";
$conn->exec($sql);
$sql = "CREATE TABLE class_i18n (class_id INT4 NOT NULL, lang CHAR(2) NOT NULL, class_name CHAR(20) NOT NULL, class_description TEXT NOT NULL, PRIMARY KEY (class_id, lang))";
$conn->exec($sql);
$sql = "SELECT class, class_name FROM class";
$result = $conn->exec("$sql");
die $conn->errorMessage unless PGRES_TUPLES_OK eq $result->resultStatus;
$class_id = 0;
while (@row = $result->fetchrow) {
$class = $row[0];
$class_name = $row[1];
$class_id++;
$sql = "INSERT INTO class_new (class_id) VALUES ($class_id)";
$conn->exec($sql);
$sql = "INSERT INTO class_i18n(class_id, lang, class_name, class_description) VALUES ($class_id, 'EN', '$class', '$class_name')";
$conn->exec($sql);
}
# Update document table
#
$sql = "CREATE TABLE document_new (doc_id INT4 NOT NULL, title TEXT NOT NULL, class_id INT4, format CHAR(12), dtd CHAR(12), dtd_version CHAR(12), version CHAR(12), last_update DATE, URL TEXT, ISBN TEXT, pub_status CHAR, review_status CHAR, tickle_date DATE, pub_date DATE, ref_url TEXT, tech_review_status CHAR, maintained BOOLEAN DEFAULT False, license CHAR(12), abstract TEXT, rating REAL, PRIMARY KEY (doc_id))";
$conn->exec("$sql");
$sql = "INSERT INTO document_new SELECT doc_id, title, class_id, format, dtd, dtd_version, version, last_update, url, isbn, pub_status, review_status, tickle_date, pub_date, ref_url, tech_review_status, maintained, license, abstract, rating FROM document d, class_i18n c WHERE d.class=c.class_name";
$conn->exec("$sql");
# Copy new tables over old tables
#
$conn->exec("DROP TABLE class");
$conn->exec("ALTER TABLE class_new RENAME TO class");
$conn->exec("DROP TABLE document");
$conn->exec("ALTER TABLE document_new RENAME TO document");
# Update database version
#
$conn->exec("UPDATE config SET value='$VERSION' WHERE name='version'");