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