MediaWiki
REL1_20
|
00001 <?php 00031 class PostgresUpdater extends DatabaseUpdater { 00032 00036 protected $db; 00037 00043 protected function getCoreUpdateList() { 00044 return array( 00045 # rename tables 1.7.3 00046 # r15791 Change reserved word table names "user" and "text" 00047 array( 'renameTable', 'user', 'mwuser' ), 00048 array( 'renameTable', 'text', 'pagecontent' ), 00049 array( 'renameIndex', 'mwuser', 'user_pkey', 'mwuser_pkey'), 00050 array( 'renameIndex', 'mwuser', 'user_user_name_key', 'mwuser_user_name_key' ), 00051 array( 'renameIndex', 'pagecontent','text_pkey', 'pagecontent_pkey' ), 00052 00053 # renamed sequences 00054 array( 'renameSequence', 'ipblocks_ipb_id_val', 'ipblocks_ipb_id_seq' ), 00055 array( 'renameSequence', 'rev_rev_id_val', 'revision_rev_id_seq' ), 00056 array( 'renameSequence', 'text_old_id_val', 'text_old_id_seq' ), 00057 array( 'renameSequence', 'rc_rc_id_seq', 'recentchanges_rc_id_seq' ), 00058 array( 'renameSequence', 'log_log_id_seq', 'logging_log_id_seq' ), 00059 array( 'renameSequence', 'pr_id_val', 'page_restrictions_pr_id_seq' ), 00060 array( 'renameSequence', 'us_id_seq', 'uploadstash_us_id_seq' ), 00061 00062 # since r58263 00063 array( 'renameSequence', 'category_id_seq', 'category_cat_id_seq'), 00064 00065 # new sequences if not renamed above 00066 array( 'addSequence', 'logging', false, 'logging_log_id_seq' ), 00067 array( 'addSequence', 'page_restrictions', false, 'page_restrictions_pr_id_seq' ), 00068 array( 'addSequence', 'filearchive', 'fa_id', 'filearchive_fa_id_seq' ), 00069 00070 # new tables 00071 array( 'addTable', 'category', 'patch-category.sql' ), 00072 array( 'addTable', 'page', 'patch-page.sql' ), 00073 array( 'addTable', 'querycachetwo', 'patch-querycachetwo.sql' ), 00074 array( 'addTable', 'page_props', 'patch-page_props.sql' ), 00075 array( 'addTable', 'page_restrictions', 'patch-page_restrictions.sql' ), 00076 array( 'addTable', 'profiling', 'patch-profiling.sql' ), 00077 array( 'addTable', 'protected_titles', 'patch-protected_titles.sql' ), 00078 array( 'addTable', 'redirect', 'patch-redirect.sql' ), 00079 array( 'addTable', 'updatelog', 'patch-updatelog.sql' ), 00080 array( 'addTable', 'change_tag', 'patch-change_tag.sql' ), 00081 array( 'addTable', 'tag_summary', 'patch-tag_summary.sql' ), 00082 array( 'addTable', 'valid_tag', 'patch-valid_tag.sql' ), 00083 array( 'addTable', 'user_properties', 'patch-user_properties.sql' ), 00084 array( 'addTable', 'log_search', 'patch-log_search.sql' ), 00085 array( 'addTable', 'l10n_cache', 'patch-l10n_cache.sql' ), 00086 array( 'addTable', 'iwlinks', 'patch-iwlinks.sql' ), 00087 array( 'addTable', 'msg_resource', 'patch-msg_resource.sql' ), 00088 array( 'addTable', 'msg_resource_links','patch-msg_resource_links.sql' ), 00089 array( 'addTable', 'module_deps', 'patch-module_deps.sql' ), 00090 array( 'addTable', 'uploadstash', 'patch-uploadstash.sql' ), 00091 array( 'addTable', 'user_former_groups','patch-user_former_groups.sql' ), 00092 array( 'addTable', 'external_user', 'patch-external_user.sql' ), 00093 00094 # Needed before new field 00095 array( 'convertArchive2' ), 00096 00097 # new fields 00098 array( 'addPgField', 'updatelog', 'ul_value', 'TEXT' ), 00099 array( 'addPgField', 'archive', 'ar_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00100 array( 'addPgField', 'archive', 'ar_len', 'INTEGER' ), 00101 array( 'addPgField', 'archive', 'ar_page_id', 'INTEGER' ), 00102 array( 'addPgField', 'archive', 'ar_parent_id', 'INTEGER' ), 00103 array( 'addPgField', 'categorylinks', 'cl_sortkey_prefix', "TEXT NOT NULL DEFAULT ''"), 00104 array( 'addPgField', 'categorylinks', 'cl_collation', "TEXT NOT NULL DEFAULT 0"), 00105 array( 'addPgField', 'categorylinks', 'cl_type', "TEXT NOT NULL DEFAULT 'page'"), 00106 array( 'addPgField', 'image', 'img_sha1', "TEXT NOT NULL DEFAULT ''" ), 00107 array( 'addPgField', 'ipblocks', 'ipb_allow_usertalk', 'SMALLINT NOT NULL DEFAULT 0' ), 00108 array( 'addPgField', 'ipblocks', 'ipb_anon_only', 'SMALLINT NOT NULL DEFAULT 0' ), 00109 array( 'addPgField', 'ipblocks', 'ipb_by_text', "TEXT NOT NULL DEFAULT ''" ), 00110 array( 'addPgField', 'ipblocks', 'ipb_block_email', 'SMALLINT NOT NULL DEFAULT 0' ), 00111 array( 'addPgField', 'ipblocks', 'ipb_create_account', 'SMALLINT NOT NULL DEFAULT 1' ), 00112 array( 'addPgField', 'ipblocks', 'ipb_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00113 array( 'addPgField', 'ipblocks', 'ipb_enable_autoblock', 'SMALLINT NOT NULL DEFAULT 1' ), 00114 array( 'addPgField', 'ipblocks', 'ipb_parent_block_id', 'INTEGER DEFAULT NULL REFERENCES ipblocks(ipb_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED' ), 00115 array( 'addPgField', 'filearchive', 'fa_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00116 array( 'addPgField', 'logging', 'log_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00117 array( 'addPgField', 'logging', 'log_id', "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('logging_log_id_seq')" ), 00118 array( 'addPgField', 'logging', 'log_params', 'TEXT' ), 00119 array( 'addPgField', 'mwuser', 'user_editcount', 'INTEGER' ), 00120 array( 'addPgField', 'mwuser', 'user_newpass_time', 'TIMESTAMPTZ' ), 00121 array( 'addPgField', 'oldimage', 'oi_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00122 array( 'addPgField', 'oldimage', 'oi_major_mime', "TEXT NOT NULL DEFAULT 'unknown'" ), 00123 array( 'addPgField', 'oldimage', 'oi_media_type', 'TEXT' ), 00124 array( 'addPgField', 'oldimage', 'oi_metadata', "BYTEA NOT NULL DEFAULT ''" ), 00125 array( 'addPgField', 'oldimage', 'oi_minor_mime', "TEXT NOT NULL DEFAULT 'unknown'" ), 00126 array( 'addPgField', 'oldimage', 'oi_sha1', "TEXT NOT NULL DEFAULT ''" ), 00127 array( 'addPgField', 'page_restrictions', 'pr_id', "INTEGER NOT NULL UNIQUE DEFAULT nextval('page_restrictions_pr_id_seq')" ), 00128 array( 'addPgField', 'profiling', 'pf_memory', 'NUMERIC(18,10) NOT NULL DEFAULT 0' ), 00129 array( 'addPgField', 'recentchanges', 'rc_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00130 array( 'addPgField', 'recentchanges', 'rc_log_action', 'TEXT' ), 00131 array( 'addPgField', 'recentchanges', 'rc_log_type', 'TEXT' ), 00132 array( 'addPgField', 'recentchanges', 'rc_logid', 'INTEGER NOT NULL DEFAULT 0' ), 00133 array( 'addPgField', 'recentchanges', 'rc_new_len', 'INTEGER' ), 00134 array( 'addPgField', 'recentchanges', 'rc_old_len', 'INTEGER' ), 00135 array( 'addPgField', 'recentchanges', 'rc_params', 'TEXT' ), 00136 array( 'addPgField', 'redirect', 'rd_interwiki', 'TEXT NULL' ), 00137 array( 'addPgField', 'redirect', 'rd_fragment', 'TEXT NULL' ), 00138 array( 'addPgField', 'revision', 'rev_deleted', 'SMALLINT NOT NULL DEFAULT 0' ), 00139 array( 'addPgField', 'revision', 'rev_len', 'INTEGER' ), 00140 array( 'addPgField', 'revision', 'rev_parent_id', 'INTEGER DEFAULT NULL' ), 00141 array( 'addPgField', 'site_stats', 'ss_active_users', "INTEGER DEFAULT '-1'" ), 00142 array( 'addPgField', 'user_newtalk', 'user_last_timestamp', 'TIMESTAMPTZ' ), 00143 array( 'addPgField', 'logging', 'log_user_text', "TEXT NOT NULL DEFAULT ''" ), 00144 array( 'addPgField', 'logging', 'log_page', 'INTEGER' ), 00145 array( 'addPgField', 'interwiki', 'iw_api', "TEXT NOT NULL DEFAULT ''"), 00146 array( 'addPgField', 'interwiki', 'iw_wikiid', "TEXT NOT NULL DEFAULT ''"), 00147 array( 'addPgField', 'revision', 'rev_sha1', "TEXT NOT NULL DEFAULT ''" ), 00148 array( 'addPgField', 'archive', 'ar_sha1', "TEXT NOT NULL DEFAULT ''" ), 00149 array( 'addPgField', 'uploadstash', 'us_chunk_inx', "INTEGER NULL" ), 00150 array( 'addPgField', 'job', 'job_timestamp', "TIMESTAMPTZ" ), 00151 00152 # type changes 00153 array( 'changeField', 'archive', 'ar_deleted', 'smallint', '' ), 00154 array( 'changeField', 'archive', 'ar_minor_edit', 'smallint', 'ar_minor_edit::smallint DEFAULT 0' ), 00155 array( 'changeField', 'filearchive', 'fa_deleted', 'smallint', '' ), 00156 array( 'changeField', 'filearchive', 'fa_height', 'integer', '' ), 00157 array( 'changeField', 'filearchive', 'fa_metadata', 'bytea', "decode(fa_metadata,'escape')" ), 00158 array( 'changeField', 'filearchive', 'fa_size', 'integer', '' ), 00159 array( 'changeField', 'filearchive', 'fa_width', 'integer', '' ), 00160 array( 'changeField', 'filearchive', 'fa_storage_group', 'text', '' ), 00161 array( 'changeField', 'filearchive', 'fa_storage_key', 'text', '' ), 00162 array( 'changeField', 'image', 'img_metadata', 'bytea', "decode(img_metadata,'escape')" ), 00163 array( 'changeField', 'image', 'img_size', 'integer', '' ), 00164 array( 'changeField', 'image', 'img_width', 'integer', '' ), 00165 array( 'changeField', 'image', 'img_height', 'integer', '' ), 00166 array( 'changeField', 'interwiki', 'iw_local', 'smallint', 'iw_local::smallint' ), 00167 array( 'changeField', 'interwiki', 'iw_trans', 'smallint', 'iw_trans::smallint DEFAULT 0' ), 00168 array( 'changeField', 'ipblocks', 'ipb_auto', 'smallint', 'ipb_auto::smallint DEFAULT 0' ), 00169 array( 'changeField', 'ipblocks', 'ipb_anon_only', 'smallint', "CASE WHEN ipb_anon_only=' ' THEN 0 ELSE ipb_anon_only::smallint END DEFAULT 0" ), 00170 array( 'changeField', 'ipblocks', 'ipb_create_account', 'smallint', "CASE WHEN ipb_create_account=' ' THEN 0 ELSE ipb_create_account::smallint END DEFAULT 1" ), 00171 array( 'changeField', 'ipblocks', 'ipb_enable_autoblock', 'smallint', "CASE WHEN ipb_enable_autoblock=' ' THEN 0 ELSE ipb_enable_autoblock::smallint END DEFAULT 1" ), 00172 array( 'changeField', 'ipblocks', 'ipb_block_email', 'smallint', "CASE WHEN ipb_block_email=' ' THEN 0 ELSE ipb_block_email::smallint END DEFAULT 0" ), 00173 array( 'changeField', 'ipblocks', 'ipb_address', 'text', 'ipb_address::text' ), 00174 array( 'changeField', 'ipblocks', 'ipb_deleted', 'smallint', 'ipb_deleted::smallint DEFAULT 0' ), 00175 array( 'changeField', 'mwuser', 'user_token', 'text', '' ), 00176 array( 'changeField', 'mwuser', 'user_email_token', 'text', '' ), 00177 array( 'changeField', 'objectcache', 'keyname', 'text', '' ), 00178 array( 'changeField', 'oldimage', 'oi_height', 'integer', '' ), 00179 array( 'changeField', 'oldimage', 'oi_metadata', 'bytea', "decode(img_metadata,'escape')" ), 00180 array( 'changeField', 'oldimage', 'oi_size', 'integer', '' ), 00181 array( 'changeField', 'oldimage', 'oi_width', 'integer', '' ), 00182 array( 'changeField', 'page', 'page_is_redirect', 'smallint', 'page_is_redirect::smallint DEFAULT 0' ), 00183 array( 'changeField', 'page', 'page_is_new', 'smallint', 'page_is_new::smallint DEFAULT 0' ), 00184 array( 'changeField', 'querycache', 'qc_value', 'integer', '' ), 00185 array( 'changeField', 'querycachetwo', 'qcc_value', 'integer', '' ), 00186 array( 'changeField', 'recentchanges', 'rc_bot', 'smallint', 'rc_bot::smallint DEFAULT 0' ), 00187 array( 'changeField', 'recentchanges', 'rc_deleted', 'smallint', '' ), 00188 array( 'changeField', 'recentchanges', 'rc_minor', 'smallint', 'rc_minor::smallint DEFAULT 0' ), 00189 array( 'changeField', 'recentchanges', 'rc_new', 'smallint', 'rc_new::smallint DEFAULT 0' ), 00190 array( 'changeField', 'recentchanges', 'rc_type', 'smallint', 'rc_type::smallint DEFAULT 0' ), 00191 array( 'changeField', 'recentchanges', 'rc_patrolled', 'smallint', 'rc_patrolled::smallint DEFAULT 0' ), 00192 array( 'changeField', 'revision', 'rev_deleted', 'smallint', 'rev_deleted::smallint DEFAULT 0' ), 00193 array( 'changeField', 'revision', 'rev_minor_edit', 'smallint', 'rev_minor_edit::smallint DEFAULT 0' ), 00194 array( 'changeField', 'templatelinks', 'tl_namespace', 'smallint', 'tl_namespace::smallint' ), 00195 array( 'changeField', 'user_newtalk', 'user_ip', 'text', 'host(user_ip)' ), 00196 array( 'changeField', 'uploadstash', 'us_image_bits', 'smallint', '' ), 00197 00198 # null changes 00199 array( 'changeNullableField', 'oldimage', 'oi_bits', 'NULL' ), 00200 array( 'changeNullableField', 'oldimage', 'oi_timestamp', 'NULL' ), 00201 array( 'changeNullableField', 'oldimage', 'oi_major_mime', 'NULL' ), 00202 array( 'changeNullableField', 'oldimage', 'oi_minor_mime', 'NULL' ), 00203 array( 'changeNullableField', 'image', 'img_metadata', 'NOT NULL'), 00204 array( 'changeNullableField', 'filearchive', 'fa_metadata', 'NOT NULL'), 00205 array( 'changeNullableField', 'recentchanges', 'rc_cur_id', 'NULL' ), 00206 00207 array( 'checkOiDeleted' ), 00208 00209 # New indexes 00210 array( 'addPgIndex', 'archive', 'archive_user_text', '(ar_user_text)' ), 00211 array( 'addPgIndex', 'image', 'img_sha1', '(img_sha1)' ), 00212 array( 'addPgIndex', 'ipblocks', 'ipb_parent_block_id', '(ipb_parent_block_id)' ), 00213 array( 'addPgIndex', 'oldimage', 'oi_sha1', '(oi_sha1)' ), 00214 array( 'addPgIndex', 'page', 'page_mediawiki_title', '(page_title) WHERE page_namespace = 8' ), 00215 array( 'addPgIndex', 'pagelinks', 'pagelinks_title', '(pl_title)' ), 00216 array( 'addPgIndex', 'revision', 'rev_text_id_idx', '(rev_text_id)' ), 00217 array( 'addPgIndex', 'recentchanges', 'rc_timestamp_bot', '(rc_timestamp) WHERE rc_bot = 0' ), 00218 array( 'addPgIndex', 'templatelinks', 'templatelinks_from', '(tl_from)' ), 00219 array( 'addPgIndex', 'watchlist', 'wl_user', '(wl_user)' ), 00220 array( 'addPgIndex', 'logging', 'logging_user_type_time', '(log_user, log_type, log_timestamp)' ), 00221 array( 'addPgIndex', 'logging', 'logging_page_id_time', '(log_page,log_timestamp)' ), 00222 array( 'addPgIndex', 'iwlinks', 'iwl_prefix_title_from', '(iwl_prefix, iwl_title, iwl_from)' ), 00223 array( 'addPgIndex', 'job', 'job_timestamp_idx', '(job_timestamp)' ), 00224 00225 array( 'checkIndex', 'pagelink_unique', array( 00226 array('pl_from', 'int4_ops', 'btree', 0), 00227 array('pl_namespace', 'int2_ops', 'btree', 0), 00228 array('pl_title', 'text_ops', 'btree', 0), 00229 ), 00230 'CREATE UNIQUE INDEX pagelink_unique ON pagelinks (pl_from,pl_namespace,pl_title)' ), 00231 array( 'checkIndex', 'cl_sortkey', array( 00232 array('cl_to', 'text_ops', 'btree', 0), 00233 array('cl_sortkey', 'text_ops', 'btree', 0), 00234 array('cl_from', 'int4_ops', 'btree', 0), 00235 ), 00236 'CREATE INDEX cl_sortkey ON "categorylinks" USING "btree" ("cl_to", "cl_sortkey", "cl_from")' ), 00237 array( 'checkIndex', 'logging_times', array( 00238 array('log_timestamp', 'timestamptz_ops', 'btree', 0), 00239 ), 00240 'CREATE INDEX "logging_times" ON "logging" USING "btree" ("log_timestamp")' ), 00241 array( 'dropIndex', 'oldimage', 'oi_name' ), 00242 array( 'checkIndex', 'oi_name_archive_name', array( 00243 array('oi_name', 'text_ops', 'btree', 0), 00244 array('oi_archive_name', 'text_ops', 'btree', 0), 00245 ), 00246 'CREATE INDEX "oi_name_archive_name" ON "oldimage" USING "btree" ("oi_name", "oi_archive_name")' ), 00247 array( 'checkIndex', 'oi_name_timestamp', array( 00248 array('oi_name', 'text_ops', 'btree', 0), 00249 array('oi_timestamp', 'timestamptz_ops', 'btree', 0), 00250 ), 00251 'CREATE INDEX "oi_name_timestamp" ON "oldimage" USING "btree" ("oi_name", "oi_timestamp")' ), 00252 array( 'checkIndex', 'page_main_title', array( 00253 array('page_title', 'text_pattern_ops', 'btree', 0), 00254 ), 00255 'CREATE INDEX "page_main_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 0)' ), 00256 array( 'checkIndex', 'page_mediawiki_title', array( 00257 array('page_title', 'text_pattern_ops', 'btree', 0), 00258 ), 00259 'CREATE INDEX "page_mediawiki_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 8)' ), 00260 array( 'checkIndex', 'page_project_title', array( 00261 array('page_title', 'text_pattern_ops', 'btree', 0), 00262 ), 00263 'CREATE INDEX "page_project_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 4)' ), 00264 array( 'checkIndex', 'page_talk_title', array( 00265 array('page_title', 'text_pattern_ops', 'btree', 0), 00266 ), 00267 'CREATE INDEX "page_talk_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 1)' ), 00268 array( 'checkIndex', 'page_user_title', array( 00269 array('page_title', 'text_pattern_ops', 'btree', 0), 00270 ), 00271 'CREATE INDEX "page_user_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 2)' ), 00272 array( 'checkIndex', 'page_utalk_title', array( 00273 array('page_title', 'text_pattern_ops', 'btree', 0), 00274 ), 00275 'CREATE INDEX "page_utalk_title" ON "page" USING "btree" ("page_title" "text_pattern_ops") WHERE ("page_namespace" = 3)' ), 00276 array( 'checkIndex', 'ts2_page_text', array( 00277 array('textvector', 'tsvector_ops', 'gist', 0), 00278 ), 00279 'CREATE INDEX "ts2_page_text" ON "pagecontent" USING "gist" ("textvector")' ), 00280 array( 'checkIndex', 'ts2_page_title', array( 00281 array('titlevector', 'tsvector_ops', 'gist', 0), 00282 ), 00283 'CREATE INDEX "ts2_page_title" ON "page" USING "gist" ("titlevector")' ), 00284 00285 array( 'checkOiNameConstraint' ), 00286 array( 'checkPageDeletedTrigger' ), 00287 array( 'checkRevUserFkey' ), 00288 array( 'dropIndex', 'ipblocks', 'ipb_address'), 00289 array( 'checkIndex', 'ipb_address_unique', array( 00290 array('ipb_address', 'text_ops', 'btree', 0), 00291 array('ipb_user', 'int4_ops', 'btree', 0), 00292 array('ipb_auto', 'int2_ops', 'btree', 0), 00293 array('ipb_anon_only', 'int2_ops', 'btree', 0), 00294 ), 00295 'CREATE UNIQUE INDEX ipb_address_unique ON ipblocks (ipb_address,ipb_user,ipb_auto,ipb_anon_only)' ), 00296 00297 array( 'checkIwlPrefix' ), 00298 00299 # All FK columns should be deferred 00300 array( 'changeFkeyDeferrable', 'archive', 'ar_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00301 array( 'changeFkeyDeferrable', 'categorylinks', 'cl_from', 'page(page_id) ON DELETE CASCADE' ), 00302 array( 'changeFkeyDeferrable', 'externallinks', 'el_from', 'page(page_id) ON DELETE CASCADE' ), 00303 array( 'changeFkeyDeferrable', 'filearchive', 'fa_deleted_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00304 array( 'changeFkeyDeferrable', 'filearchive', 'fa_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00305 array( 'changeFkeyDeferrable', 'image', 'img_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00306 array( 'changeFkeyDeferrable', 'imagelinks', 'il_from', 'page(page_id) ON DELETE CASCADE' ), 00307 array( 'changeFkeyDeferrable', 'ipblocks', 'ipb_by', 'mwuser(user_id) ON DELETE CASCADE' ), 00308 array( 'changeFkeyDeferrable', 'ipblocks', 'ipb_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00309 array( 'changeFkeyDeferrable', 'ipblocks', 'ipb_parent_block_id', 'ipblocks(ipb_id) ON DELETE SET NULL' ), 00310 array( 'changeFkeyDeferrable', 'langlinks', 'll_from', 'page(page_id) ON DELETE CASCADE' ), 00311 array( 'changeFkeyDeferrable', 'logging', 'log_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00312 array( 'changeFkeyDeferrable', 'oldimage', 'oi_name', 'image(img_name) ON DELETE CASCADE ON UPDATE CASCADE' ), 00313 array( 'changeFkeyDeferrable', 'oldimage', 'oi_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00314 array( 'changeFkeyDeferrable', 'pagelinks', 'pl_from', 'page(page_id) ON DELETE CASCADE' ), 00315 array( 'changeFkeyDeferrable', 'page_props', 'pp_page', 'page (page_id) ON DELETE CASCADE' ), 00316 array( 'changeFkeyDeferrable', 'page_restrictions', 'pr_page', 'page(page_id) ON DELETE CASCADE' ), 00317 array( 'changeFkeyDeferrable', 'protected_titles', 'pt_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00318 array( 'changeFkeyDeferrable', 'recentchanges', 'rc_cur_id', 'page(page_id) ON DELETE SET NULL' ), 00319 array( 'changeFkeyDeferrable', 'recentchanges', 'rc_user', 'mwuser(user_id) ON DELETE SET NULL' ), 00320 array( 'changeFkeyDeferrable', 'redirect', 'rd_from', 'page(page_id) ON DELETE CASCADE' ), 00321 array( 'changeFkeyDeferrable', 'revision', 'rev_page', 'page (page_id) ON DELETE CASCADE' ), 00322 array( 'changeFkeyDeferrable', 'revision', 'rev_user', 'mwuser(user_id) ON DELETE RESTRICT' ), 00323 array( 'changeFkeyDeferrable', 'templatelinks', 'tl_from', 'page(page_id) ON DELETE CASCADE' ), 00324 array( 'changeFkeyDeferrable', 'user_groups', 'ug_user', 'mwuser(user_id) ON DELETE CASCADE' ), 00325 array( 'changeFkeyDeferrable', 'user_newtalk', 'user_id', 'mwuser(user_id) ON DELETE CASCADE' ), 00326 array( 'changeFkeyDeferrable', 'user_properties', 'up_user', 'mwuser(user_id) ON DELETE CASCADE' ), 00327 array( 'changeFkeyDeferrable', 'watchlist', 'wl_user', 'mwuser(user_id) ON DELETE CASCADE' ), 00328 00329 # r81574 00330 array( 'addInterwikiType' ), 00331 # end 00332 array( 'tsearchFixes' ), 00333 ); 00334 } 00335 00336 protected function getOldGlobalUpdates() { 00337 global $wgExtNewTables, $wgExtPGNewFields, $wgExtPGAlteredFields, $wgExtNewIndexes; 00338 00339 $updates = array(); 00340 00341 # Add missing extension tables 00342 foreach ( $wgExtNewTables as $tableRecord ) { 00343 $updates[] = array( 00344 'addTable', $tableRecord[0], $tableRecord[1], true 00345 ); 00346 } 00347 00348 # Add missing extension fields 00349 foreach ( $wgExtPGNewFields as $fieldRecord ) { 00350 $updates[] = array( 00351 'addPgField', $fieldRecord[0], $fieldRecord[1], 00352 $fieldRecord[2] 00353 ); 00354 } 00355 00356 # Change altered columns 00357 foreach ( $wgExtPGAlteredFields as $fieldRecord ) { 00358 $updates[] = array( 00359 'changeField', $fieldRecord[0], $fieldRecord[1], 00360 $fieldRecord[2] 00361 ); 00362 } 00363 00364 # Add missing extension indexes 00365 foreach ( $wgExtNewIndexes as $fieldRecord ) { 00366 $updates[] = array( 00367 'addPgExtIndex', $fieldRecord[0], $fieldRecord[1], 00368 $fieldRecord[2] 00369 ); 00370 } 00371 00372 return $updates; 00373 } 00374 00375 protected function describeTable( $table ) { 00376 $q = <<<END 00377 SELECT attname, attnum FROM pg_namespace, pg_class, pg_attribute 00378 WHERE pg_class.relnamespace = pg_namespace.oid 00379 AND attrelid=pg_class.oid AND attnum > 0 00380 AND relname=%s AND nspname=%s 00381 END; 00382 $res = $this->db->query( sprintf( $q, 00383 $this->db->addQuotes( $table ), 00384 $this->db->addQuotes( $this->db->getCoreSchema() ) ) ); 00385 if ( !$res ) { 00386 return null; 00387 } 00388 00389 $cols = array(); 00390 foreach ( $res as $r ) { 00391 $cols[] = array( 00392 "name" => $r[0], 00393 "ord" => $r[1], 00394 ); 00395 } 00396 return $cols; 00397 } 00398 00399 function describeIndex( $idx ) { 00400 // first fetch the key (which is a list of columns ords) and 00401 // the table the index applies to (an oid) 00402 $q = <<<END 00403 SELECT indkey, indrelid FROM pg_namespace, pg_class, pg_index 00404 WHERE nspname=%s 00405 AND pg_class.relnamespace = pg_namespace.oid 00406 AND relname=%s 00407 AND indexrelid=pg_class.oid 00408 END; 00409 $res = $this->db->query( 00410 sprintf( 00411 $q, 00412 $this->db->addQuotes( $this->db->getCoreSchema() ), 00413 $this->db->addQuotes( $idx ) 00414 ) 00415 ); 00416 if ( !$res ) { 00417 return null; 00418 } 00419 if ( !( $r = $this->db->fetchRow( $res ) ) ) { 00420 return null; 00421 } 00422 00423 $indkey = $r[0]; 00424 $relid = intval( $r[1] ); 00425 $indkeys = explode( ' ', $indkey ); 00426 00427 $colnames = array(); 00428 foreach ( $indkeys as $rid ) { 00429 $query = <<<END 00430 SELECT attname FROM pg_class, pg_attribute 00431 WHERE attrelid=$relid 00432 AND attnum=%d 00433 AND attrelid=pg_class.oid 00434 END; 00435 $r2 = $this->db->query( sprintf( $query, $rid ) ); 00436 if ( !$r2 ) { 00437 return null; 00438 } 00439 if ( !( $row2 = $this->db->fetchRow( $r2 ) ) ) { 00440 return null; 00441 } 00442 $colnames[] = $row2[0]; 00443 } 00444 00445 return $colnames; 00446 } 00447 00448 function fkeyDeltype( $fkey ) { 00449 $q = <<<END 00450 SELECT confdeltype FROM pg_constraint, pg_namespace 00451 WHERE connamespace=pg_namespace.oid 00452 AND nspname=%s 00453 AND conname=%s; 00454 END; 00455 $r = $this->db->query( 00456 sprintf( 00457 $q, 00458 $this->db->addQuotes( $this->db->getCoreSchema() ), 00459 $this->db->addQuotes( $fkey ) 00460 ) 00461 ); 00462 if ( !( $row = $this->db->fetchRow( $r ) ) ) { 00463 return null; 00464 } 00465 return $row[0]; 00466 } 00467 00468 function ruleDef( $table, $rule ) { 00469 $q = <<<END 00470 SELECT definition FROM pg_rules 00471 WHERE schemaname = %s 00472 AND tablename = %s 00473 AND rulename = %s 00474 END; 00475 $r = $this->db->query( 00476 sprintf( 00477 $q, 00478 $this->db->addQuotes( $this->db->getCoreSchema() ), 00479 $this->db->addQuotes( $table ), 00480 $this->db->addQuotes( $rule ) 00481 ) 00482 ); 00483 $row = $this->db->fetchRow( $r ); 00484 if ( !$row ) { 00485 return null; 00486 } 00487 $d = $row[0]; 00488 return $d; 00489 } 00490 00491 protected function addSequence( $table, $pkey, $ns ) { 00492 if ( !$this->db->sequenceExists( $ns ) ) { 00493 $this->output( "Creating sequence $ns\n" ); 00494 $this->db->query( "CREATE SEQUENCE $ns" ); 00495 if( $pkey !== false ) { 00496 $this->setDefault( $table, $pkey, '"nextval"(\'"' . $ns . '"\'::"regclass")' ); 00497 } 00498 } 00499 } 00500 00501 protected function renameSequence( $old, $new ) { 00502 if ( $this->db->sequenceExists( $new ) ) { 00503 $this->output( "...sequence $new already exists.\n" ); 00504 return; 00505 } 00506 if ( $this->db->sequenceExists( $old ) ) { 00507 $this->output( "Renaming sequence $old to $new\n" ); 00508 $this->db->query( "ALTER SEQUENCE $old RENAME TO $new" ); 00509 } 00510 } 00511 00512 protected function renameTable( $old, $new, $patch = false ) { 00513 if ( $this->db->tableExists( $old ) ) { 00514 $this->output( "Renaming table $old to $new\n" ); 00515 $old = $this->db->realTableName( $old, "quoted" ); 00516 $new = $this->db->realTableName( $new, "quoted" ); 00517 $this->db->query( "ALTER TABLE $old RENAME TO $new" ); 00518 if( $patch !== false ) { 00519 $this->applyPatch( $patch ); 00520 } 00521 } 00522 } 00523 00524 protected function renameIndex( $table, $old, $new ) { 00525 if ( $this->db->indexExists( $table, $old ) ) { 00526 $this->output( "Renaming index $old to $new\n" ); 00527 $this->db->query( "ALTER INDEX $old RENAME TO $new" ); 00528 } 00529 } 00530 00531 protected function addPgField( $table, $field, $type ) { 00532 $fi = $this->db->fieldInfo( $table, $field ); 00533 if ( !is_null( $fi ) ) { 00534 $this->output( "...column '$table.$field' already exists\n" ); 00535 return; 00536 } else { 00537 $this->output( "Adding column '$table.$field'\n" ); 00538 $this->db->query( "ALTER TABLE $table ADD $field $type" ); 00539 } 00540 } 00541 00542 protected function changeField( $table, $field, $newtype, $default ) { 00543 $fi = $this->db->fieldInfo( $table, $field ); 00544 if ( is_null( $fi ) ) { 00545 $this->output( "...ERROR: expected column $table.$field to exist\n" ); 00546 exit( 1 ); 00547 } 00548 00549 if ( $fi->type() === $newtype ) 00550 $this->output( "...column '$table.$field' is already of type '$newtype'\n" ); 00551 else { 00552 $this->output( "Changing column type of '$table.$field' from '{$fi->type()}' to '$newtype'\n" ); 00553 $sql = "ALTER TABLE $table ALTER $field TYPE $newtype"; 00554 if ( strlen( $default ) ) { 00555 $res = array(); 00556 if ( preg_match( '/DEFAULT (.+)/', $default, $res ) ) { 00557 $sqldef = "ALTER TABLE $table ALTER $field SET DEFAULT $res[1]"; 00558 $this->db->query( $sqldef ); 00559 $default = preg_replace( '/\s*DEFAULT .+/', '', $default ); 00560 } 00561 $sql .= " USING $default"; 00562 } 00563 $this->db->query( $sql ); 00564 } 00565 } 00566 00567 protected function setDefault( $table, $field, $default ) { 00568 00569 $info = $this->db->fieldInfo( $table, $field ); 00570 if ( $info->defaultValue() !== $default ) { 00571 $this->output( "Changing '$table.$field' default value\n" ); 00572 $this->db->query( "ALTER TABLE $table ALTER $field SET DEFAULT " . $default ); 00573 } 00574 } 00575 00576 protected function changeNullableField( $table, $field, $null) { 00577 $fi = $this->db->fieldInfo( $table, $field ); 00578 if ( is_null( $fi ) ) { 00579 $this->output( "...ERROR: expected column $table.$field to exist\n" ); 00580 exit( 1 ); 00581 } 00582 if ( $fi->isNullable() ) { 00583 # # It's NULL - does it need to be NOT NULL? 00584 if ( 'NOT NULL' === $null ) { 00585 $this->output( "Changing '$table.$field' to not allow NULLs\n" ); 00586 $this->db->query( "ALTER TABLE $table ALTER $field SET NOT NULL" ); 00587 } else { 00588 $this->output( "...column '$table.$field' is already set as NULL\n" ); 00589 } 00590 } else { 00591 # # It's NOT NULL - does it need to be NULL? 00592 if ( 'NULL' === $null ) { 00593 $this->output( "Changing '$table.$field' to allow NULLs\n" ); 00594 $this->db->query( "ALTER TABLE $table ALTER $field DROP NOT NULL" ); 00595 } 00596 else { 00597 $this->output( "...column '$table.$field' is already set as NOT NULL\n" ); 00598 } 00599 } 00600 } 00601 00602 public function addPgIndex( $table, $index, $type ) { 00603 if ( $this->db->indexExists( $table, $index ) ) { 00604 $this->output( "...index '$index' on table '$table' already exists\n" ); 00605 } else { 00606 $this->output( "Creating index '$index' on table '$table' $type\n" ); 00607 $this->db->query( "CREATE INDEX $index ON $table $type" ); 00608 } 00609 } 00610 00611 public function addPgExtIndex( $table, $index, $type ) { 00612 if ( $this->db->indexExists( $table, $index ) ) { 00613 $this->output( "...index '$index' on table '$table' already exists\n" ); 00614 } else { 00615 if ( preg_match( '/^\(/', $type ) ) { 00616 $this->output( "Creating index '$index' on table '$table'\n" ); 00617 $this->db->query( "CREATE INDEX $index ON $table $type" ); 00618 } else { 00619 $this->applyPatch( $type, true, "Creating index '$index' on table '$table'" ); 00620 } 00621 } 00622 } 00623 00624 protected function changeFkeyDeferrable( $table, $field, $clause ) { 00625 $fi = $this->db->fieldInfo( $table, $field ); 00626 if ( is_null( $fi ) ) { 00627 $this->output( "WARNING! Column '$table.$field' does not exist but it should! Please report this.\n" ); 00628 return; 00629 } 00630 if ( $fi->is_deferred() && $fi->is_deferrable() ) { 00631 return; 00632 } 00633 $this->output( "Altering column '$table.$field' to be DEFERRABLE INITIALLY DEFERRED\n" ); 00634 $conname = $fi->conname(); 00635 if ( $fi->conname() ) { 00636 $conclause = "CONSTRAINT \"$conname\""; 00637 $command = "ALTER TABLE $table DROP CONSTRAINT $conname"; 00638 $this->db->query( $command ); 00639 } else { 00640 $this->output( "Column '$table.$field' does not have a foreign key constraint, will be added\n" ); 00641 $conclause = ""; 00642 } 00643 $command = "ALTER TABLE $table ADD $conclause FOREIGN KEY ($field) REFERENCES $clause DEFERRABLE INITIALLY DEFERRED"; 00644 $this->db->query( $command ); 00645 } 00646 00647 protected function convertArchive2() { 00648 if ( $this->db->tableExists( "archive2" ) ) { 00649 if ( $this->db->ruleExists( 'archive', 'archive_insert' ) ) { 00650 $this->output( "Dropping rule 'archive_insert'\n" ); 00651 $this->db->query( 'DROP RULE archive_insert ON archive' ); 00652 } 00653 if ( $this->db->ruleExists( 'archive', 'archive_delete' ) ) { 00654 $this->output( "Dropping rule 'archive_delete'\n" ); 00655 $this->db->query( 'DROP RULE archive_delete ON archive' ); 00656 } 00657 $this->applyPatch( 'patch-remove-archive2.sql', false, "Converting 'archive2' back to normal archive table" ); 00658 } else { 00659 $this->output( "...obsolete table 'archive2' does not exist\n" ); 00660 } 00661 } 00662 00663 protected function checkOiDeleted() { 00664 if ( $this->db->fieldInfo( 'oldimage', 'oi_deleted' )->type() !== 'smallint' ) { 00665 $this->output( "Changing 'oldimage.oi_deleted' to type 'smallint'\n" ); 00666 $this->db->query( "ALTER TABLE oldimage ALTER oi_deleted DROP DEFAULT" ); 00667 $this->db->query( "ALTER TABLE oldimage ALTER oi_deleted TYPE SMALLINT USING (oi_deleted::smallint)" ); 00668 $this->db->query( "ALTER TABLE oldimage ALTER oi_deleted SET DEFAULT 0" ); 00669 } else { 00670 $this->output( "...column 'oldimage.oi_deleted' is already of type 'smallint'\n" ); 00671 } 00672 } 00673 00674 protected function checkOiNameConstraint() { 00675 if ( $this->db->hasConstraint( "oldimage_oi_name_fkey_cascaded" ) ) { 00676 $this->output( "...table 'oldimage' has correct cascading delete/update foreign key to image\n" ); 00677 } else { 00678 if ( $this->db->hasConstraint( "oldimage_oi_name_fkey" ) ) { 00679 $this->db->query( "ALTER TABLE oldimage DROP CONSTRAINT oldimage_oi_name_fkey" ); 00680 } 00681 if ( $this->db->hasConstraint( "oldimage_oi_name_fkey_cascade" ) ) { 00682 $this->db->query( "ALTER TABLE oldimage DROP CONSTRAINT oldimage_oi_name_fkey_cascade" ); 00683 } 00684 $this->output( "Making foreign key on table 'oldimage' (to image) a cascade delete/update\n" ); 00685 $this->db->query( "ALTER TABLE oldimage ADD CONSTRAINT oldimage_oi_name_fkey_cascaded " . 00686 "FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE ON UPDATE CASCADE" ); 00687 } 00688 } 00689 00690 protected function checkPageDeletedTrigger() { 00691 if ( !$this->db->triggerExists( 'page', 'page_deleted' ) ) { 00692 $this->applyPatch( 'patch-page_deleted.sql', false, "Adding function and trigger 'page_deleted' to table 'page'" ); 00693 } else { 00694 $this->output( "...table 'page' has 'page_deleted' trigger\n" ); 00695 } 00696 } 00697 00698 protected function dropIndex( $table, $index, $patch = '', $fullpath = false ) { 00699 if ( $this->db->indexExists( $table, $index ) ) { 00700 $this->output( "Dropping obsolete index '$index'\n" ); 00701 $this->db->query( "DROP INDEX \"". $index ."\"" ); 00702 } 00703 } 00704 00705 protected function checkIndex( $index, $should_be, $good_def ) { 00706 $pu = $this->db->indexAttributes( $index ); 00707 if ( !empty( $pu ) && $pu != $should_be ) { 00708 $this->output( "Dropping obsolete version of index '$index'\n" ); 00709 $this->db->query( "DROP INDEX \"". $index ."\"" ); 00710 $pu = array(); 00711 } else { 00712 $this->output( "...no need to drop index '$index'\n" ); 00713 } 00714 00715 if ( empty( $pu ) ) { 00716 $this->output( "Creating index '$index'\n" ); 00717 $this->db->query( $good_def ); 00718 } else { 00719 $this->output( "...index '$index' exists\n" ); 00720 } 00721 } 00722 00723 protected function checkRevUserFkey() { 00724 if ( $this->fkeyDeltype( 'revision_rev_user_fkey' ) == 'r' ) { 00725 $this->output( "...constraint 'revision_rev_user_fkey' is ON DELETE RESTRICT\n" ); 00726 } else { 00727 $this->applyPatch( 'patch-revision_rev_user_fkey.sql', false, "Changing constraint 'revision_rev_user_fkey' to ON DELETE RESTRICT" ); 00728 } 00729 } 00730 00731 protected function checkIwlPrefix() { 00732 if ( $this->db->indexExists( 'iwlinks', 'iwl_prefix' ) ) { 00733 $this->applyPatch( 'patch-rename-iwl_prefix.sql', false, "Replacing index 'iwl_prefix' with 'iwl_prefix_from_title'" ); 00734 } 00735 } 00736 00737 protected function addInterwikiType() { 00738 $this->applyPatch( 'patch-add_interwiki.sql', false, "Refreshing add_interwiki()" ); 00739 } 00740 00741 protected function tsearchFixes() { 00742 # Tweak the page_title tsearch2 trigger to filter out slashes 00743 # This is create or replace, so harmless to call if not needed 00744 $this->applyPatch( 'patch-ts2pagetitle.sql', false, "Refreshing ts2_page_title()" ); 00745 00746 # If the server is 8.3 or higher, rewrite the tsearch2 triggers 00747 # in case they have the old 'default' versions 00748 # Gather version numbers in case we need them 00749 if ( $this->db->getServerVersion() >= 8.3 ) { 00750 $this->applyPatch( 'patch-tsearch2funcs.sql', false, "Rewriting tsearch2 triggers" ); 00751 } 00752 } 00753 }