diff --git a/upgrade.php b/upgrade.php index f0552d1c..e3dfb5c9 100644 --- a/upgrade.php +++ b/upgrade.php @@ -1,10 +1,27 @@ $function) { - $function(); + if ($current_version >= $target_version) { + # already up to date + echo "up to date"; + return true; } + + echo "

Updating database:

old version: $current_version; target version: $target_version"; + + for ($i = $current_version +1; $i <= $target_version; $i++) { + $function = "upgrade_$i"; + $function_mysql = $function . "_mysql"; + $function_pgsql = $function . "_pgsql"; + if (function_exists($function)) { + echo "

updating to version $i (all databases)..."; + $function(); + echo "   done"; + } + if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { + if (function_exists($function_mysql)) { + echo "

updating to version $i (MySQL)..."; + $function_mysql(); + echo "   done"; + } + } elseif($CONF['database_type'] == 'pgsql') { + if (function_exists($function_pgsql)) { + echo "

updating to version $i (PgSQL)..."; + $function_pgsql(); + echo "   done"; + } + } + # TODO: update version in config table after each change + # TODO: this avoids problems in case the script hits the max_execution_time, + # TODO: simply rerunning it will continue where it was stopped + }; } -function upgrade_00() { +/** + * Replaces database specific parts in a query + * @param String sql query with placeholders + * @param String (optional) MySQL specific code to attach, useful for COMMENT= on CREATE TABLE + * @return String sql query + */ + +function db_query_parsed($sql, $ignore_errors = 0, $attach_mysql = "") { global $CONF; - if($CONF['database_type'] == 'mysql') { - echo 'mysql 00'; + + if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { + + $replace = array( + '{AUTOINCREMENT}' => 'int(11) not null auto_increment', + '{PRIMARY}' => 'primary key', + '{UNSIGNED}' => 'unsigned' , + '{FULLTEXT}' => 'FULLTEXT', + '{BOOLEAN}' => '`active` tinyint(1) NOT NULL', + '{UTF_8}' => '/*!40100 CHARACTER SET utf8 COLLATE utf8_unicode_ci */', + '{LATIN1}' => '/*!40100 CHARACTER SET latin1 COLLATE latin1_swedish_ci */', + '{IF_NOT_EXISTS}' => 'IF NOT EXISTS', + '{RENAME_COLUMN}' => 'CHANGE COLUMN', + ); + $sql = "$sql $attach_mysql"; + + } elseif($CONF['database_type'] == 'pgsql') { + static $replace = array( + '{AUTOINCREMENT}' => 'SERIAL', + '{PRIMARY}' => 'primary key', + '{UNSIGNED}' => '', + '{FULLTEXT}' => '', + '{BOOLEAN}' => 'BOOLEAN NOT NULL', + '{UTF_8}' => '', # TODO: UTF_8 is simply ignored. + '{LATIN1}' => '', # TODO: same for latin1 + '{IF_NOT_EXISTS}' => 'IF NOT EXISTS', # TODO: does this work with PgSQL? + '{RENAME_COLUMN}' => 'CHANGE COLUMN', # TODO: probably wrong + 'int(1)' => 'int2', + 'int(10)' => 'int4', + 'int(11)' => 'int4', + 'int(4)' => 'int4', + ); + + } else { + echo "Sorry, unsupported database type " . $conf['database_type']; + exit; } - if($CONF['database_type'] == 'pgsql') { - echo 'pgsql 00'; + + $replace['{BOOL_TRUE}'] = db_get_boolean(True); + $replace['{BOOL_FALSE}'] = db_get_boolean(False); + + $query = trim(str_replace(array_keys($replace), $replace, $sql)); + $result = db_query($query, $ignore_errors); + if (safeget('debug') != "") { + print $result['error']; } + return $result; } -function upgrade_01() { +function _drop_index ($table, $index) { global $CONF; - if($CONF['database_type'] == 'mysql') { - echo 'mysql 01'; - } - if($CONF['database_type'] == 'pgsql') { - echo 'pgsql 01'; + $tabe = table_by_key ($table); + + if ($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli' ) { + return "ALTER TABLE $table DROP INDEX $index"; + } elseif($CONF['database_type'] == 'pgsql') { + return "DROP INDEX $index"; # TODO: on which table?! + } else { + echo "Sorry, unsupported database type " . $conf['database_type']; + exit; } } -function upgrade_02() { - global $CONF; - if($CONF['database_type'] == 'mysql') { - echo 'mysql 02'; - } - if($CONF['database_type'] == 'pgsql') { - echo 'pgsql 02'; + +function upgrade_1() { + # inserting the version number is a good start ;-) + db_insert( + 'config', + array( + 'name' => 'version', + 'value' => '1', + ) + ); + echo "upgrade_1"; +} + +function upgrade_2() { + # upgrade pre-2.1 database + # from TABLE_BACKUP_MX.TXT + $table_domain = table_by_key ('domain'); + $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN transport VARCHAR(255) AFTER maxquota;", TRUE); + $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN backupmx {BOOLEAN} DEFAULT {BOOL_FALSE} AFTER transport;", TRUE); +} + +function upgrade_3() { + # upgrade pre-2.1 database + # from TABLE_CHANGES.TXT + $table_admin = table_by_key ('admin'); + $table_alias = table_by_key ('alias'); + $table_domain = table_by_key ('domain'); + $table_mailbox = table_by_key ('mailbox'); + $table_vacation = table_by_key ('vacation'); + + $all_sql = split("\n", trim(" + ALTER TABLE $table_admin {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_admin {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_alias {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_alias {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_domain {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_domain {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_domain ADD COLUMN aliases INT(10) DEFAULT '-1' NOT NULL AFTER description; + ALTER TABLE $table_domain ADD COLUMN mailboxes INT(10) DEFAULT '-1' NOT NULL AFTER aliases; + ALTER TABLE $table_domain ADD COLUMN maxquota INT(10) DEFAULT '-1' NOT NULL AFTER mailboxes; + ALTER TABLE $table_domain ADD COLUMN transport VARCHAR(255) AFTER maxquota; + ALTER TABLE $table_domain ADD COLUMN backupmx TINYINT(1) DEFAULT '0' NOT NULL AFTER transport; + ALTER TABLE $table_mailbox {RENAME_COLUMN} create_date created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_mailbox {RENAME_COLUMN} change_date modified DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL; + ALTER TABLE $table_mailbox ADD COLUMN quota INT(10) DEFAULT '-1' NOT NULL AFTER maildir; + ALTER TABLE $table_vacation ADD COLUMN domain VARCHAR(255) DEFAULT '' NOT NULL AFTER cache; + ALTER TABLE $table_vacation ADD COLUMN created DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL AFTER domain; + ALTER TABLE $table_vacation ADD COLUMN active TINYINT(1) DEFAULT '1' NOT NULL AFTER created; + ALTER TABLE $table_vacation DROP PRIMARY KEY + ALTER TABLE $table_vacation ADD COLUMN PRIMARY KEY(email); + UPDATE $table_vacation SET domain=SUBSTRING_INDEX(email, '@', -1) WHERE email=email; + ")); + + foreach ($all_sql as $sql) { + $result = db_query_parsed($sql, TRUE); } } -function upgrade_03() { - echo 'woof 03'; + +function upgrade_4_mysql() { # MySQL only + # changes between 2.1 and moving to sourceforge + $table_domain = table_by_key ('domain'); + $result = db_query_parsed("ALTER TABLE $table_domain ADD COLUMN quota int(10) NOT NULL default '0' AFTER maxquota", TRUE); } + +function upgrade_4_pgsql() { # PgSQL only + # changes between 2.1 and moving to sourceforge + +/* TODO + +Changes in DATABASE_PGSQL.TXT: (in diff format - "-" means removed, "+" means added) + +TABLE domain +- domain character varying(255) NOT NULL default '', ++ domain character varying(255) NOT NULL, ++ quota integer NOT NULL default 0, + ++CREATE INDEX domain_domain_active ON domain(domain,active); + + +TABLE "admin" +- "username" character varying(255) NOT NULL default '', ++ "username" character varying(255) NOT NULL, + + +TABLE alias +- address character varying(255) NOT NULL default '', ++ address character varying(255) NOT NULL, +- domain character varying(255) NOT NULL default '', ++ domain character varying(255) NOT NULL REFERENCES domain, + ++CREATE INDEX alias_address_active ON alias(address,active); + +TABLE domain_admins +- username character varying(255) NOT NULL default '', ++ username character varying(255) NOT NULL, +- domain character varying(255) NOT NULL default '', ++ domain character varying(255) NOT NULL REFERENCES domain, + +TABLE log +- data character varying(255) NOT NULL default '' ++ data text NOT NULL default '' + +TABLE mailbox +- username character varying(255) NOT NULL default '', ++ username character varying(255) NOT NULL, +- domain character varying(255) NOT NULL default '', ++ domain character varying(255) NOT NULL REFERENCES domain, + ++CREATE INDEX mailbox_username_active ON mailbox(username,active); + +TABLE vacation +- email character varying(255) NOT NULL default '', ++ email character varying(255) PRIMARY KEY, +- body text NOT NULL, ++ body text NOT NULL DEFAULT '', +- cache text NOT NULL, ++ cache text NOT NULL DEFAULT '', +- domain character varying(255) NOT NULL default '', ++ "domain" character varying(255) NOT NULL REFERENCES "domain", +- active boolean NOT NULL default true, ++ active boolean DEFAULT true NOT NULL +- Constraint "vacation_key" Primary Key ("email") + +-COMMENT ON TABLE vacation IS 'Postfix Admin - Virtual Vacation'; + ++CREATE INDEX vacation_email_active ON vacation(email,active); + ++CREATE TABLE vacation_notification ( ++ on_vacation character varying(255) NOT NULL REFERENCES vacation(email) ON DELETE CASCADE, ++ notified character varying(255) NOT NULL, ++ notified_at timestamp with time zone NOT NULL DEFAULT now(), ++ CONSTRAINT vacation_notification_pkey primary key(on_vacation,notified) ++); + + +*/ +} + +function upgrade_79_mysql() { # MySQL only + # drop useless indicies (already available as primary key) + $result = db_query_parsed(_drop_index('admin', 'username')); + $result = db_query_parsed(_drop_index('alias', 'address')); + $result = db_query_parsed(_drop_index('domain', 'domain')); + $result = db_query_parsed(_drop_index('mailbox', 'username')); +} + +function upgrade_81_mysql() { # MySQL only +/* TODO + +table vacation - +- all varchar + text fields changed to utf8 +- active was tinyint (1), now (4) +- ENGINE changed +- DEFAULT CHARSET changed +- COLLATE changed + +diff: + - `body` text NOT NULL default '', + - `cache` text NOT NULL default '', + + body text NOT NULL, + + cache text NOT NULL, + - `active` tinyint(1) NOT NULL default '1', + + active tinyint(4) NOT NULL default '1', -> boolean are usually tinyint(1) + -) TYPE=MyISAM COMMENT='Postfix Admin - Virtual Vacation'; + +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci TYPE=InnoDB COMMENT='Postfix Admin - Virtual Vacation' ; + + + + */ + + db_query_parsed( + " CREATE TABLE {IF_NOT_EXISTS} vacation_notification ( + on_vacation varchar(255) NOT NULL, + notified varchar(255) NOT NULL, + notified_at timestamp NOT NULL default now(), + CONSTRAINT vacation_notification_pkey PRIMARY KEY(on_vacation, notified), + FOREIGN KEY (on_vacation) REFERENCES vacation(email) ON DELETE CASCADE + ) + ", + TRUE, + " ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci TYPE=InnoDB + COMMENT='Postfix Admin - Virtual Vacation Notifications' + " + ); +} + +function upgrade_169_mysql() { # MySQL only + # allow quota > 2 GB + + $table_domain = table_by_key ('domain'); + $table_mailbox = table_by_key ('mailbox'); + $result = db_query_parsed("ALTER TABLE $table_domain ALTER COLUMN `quota` bigint(20) NOT NULL default '0'", TRUE); + $result = db_query_parsed("ALTER TABLE $table_mailbox ALTER COLUMN `maxquota` bigint(20) NOT NULL default '0'", TRUE); + $result = db_query_parsed("ALTER TABLE $table_mailbox ALTER COLUMN `quota` bigint(20) NOT NULL default '0'", TRUE); +} + + +/* +TODO + + Database changes that should be done: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MySQL: +* vacation: DROP INDEX email +* vacation_notification: + - DEFAULT CHARSET and COLLATE should be changed + - change all varchar fields to latin1 (email addresses don't contain utf8 characters) +* remove all DROP TABLE statements from DATABASE_* + +*/ + + +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */