Index: trunk/extensions/SemanticMediaWiki/specials/SMWAdmin/SMW_SpecialSMWAdmin.php |
— | — | @@ -32,32 +32,33 @@ |
33 | 33 | return; |
34 | 34 | } |
35 | 35 | |
| 36 | + $wgOut->setPageTitle(wfMsg('smwadmin')); |
| 37 | + |
36 | 38 | /**** Execute actions if any ****/ |
37 | 39 | |
38 | 40 | $action = $wgRequest->getText( 'action' ); |
39 | | - $message=''; |
40 | 41 | if ( $action=='updatetables' ) { |
41 | 42 | $sure = $wgRequest->getText( 'udsure' ); |
42 | 43 | if ($sure == 'yes') { |
43 | | - $message = smwfGetStore()->setup(); |
44 | | - if ($message === true) { |
45 | | - $message = 'The database was set up successfully.'; |
| 44 | + $wgOut->disable(); // raw output |
| 45 | + ob_start(); |
| 46 | + print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\">\n<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>Setting up Storage for Semantic MediaWiki</title></head><body><p style=\"font-family: courier, fixed, monospace; \">"; |
| 47 | + header( "Content-type: application/rdf+xml; charset=UTF-8" ); |
| 48 | + $result = smwfGetStore()->setup(); |
| 49 | + print '</p>'; |
| 50 | + if ($result === true) { |
| 51 | + print '<p><b>The storage engine was set up successfully.</b></p>'; |
46 | 52 | } |
| 53 | + print '<p> Return to <a href="' . $wgServer . $wgScript . '/Special:SMWAdmin">Special:SMWAdmin</a></p>'; |
| 54 | + print '</body></html>'; |
| 55 | + ob_flush(); |
| 56 | + flush(); |
| 57 | + return; |
47 | 58 | } |
48 | 59 | } |
49 | 60 | |
50 | | - /**** Output ****/ |
| 61 | + /**** Normal output ****/ |
51 | 62 | |
52 | | - $wgOut->setPageTitle(wfMsg('smwadmin')); |
53 | | - |
54 | | - // only report success/failure after an action |
55 | | - if ( $message!='' ) { |
56 | | - $html = $message; |
57 | | - $html .= '<p> Return to <a href="' . $wgServer . $wgScript . '/Special:SMWAdmin">Special:SMWAdmin</p>'; |
58 | | - $wgOut->addHTML($html); |
59 | | - return true; |
60 | | - } |
61 | | - |
62 | 63 | $html = '<p>This special page helps you during installation and upgrade of |
63 | 64 | Semantic MediaWiki. Remember to backup valuable data before |
64 | 65 | executing administrative functions.</p>' . "\n"; |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php |
— | — | @@ -625,6 +625,15 @@ |
626 | 626 | foreach ($query->getErrors() as $error) { |
627 | 627 | $result .= $error . '<br />'; |
628 | 628 | } |
| 629 | + $result .= '<br /><b>Auxilliary tables used (possibly in multiple copies)</b><br />'; |
| 630 | + foreach (SMWSQLStore::$m_categorytables as $tablename) { |
| 631 | + $result .= $tablename . ': '; |
| 632 | + $res = $db->select( $tablename, 'cat_name', '', 'SMW::getQueryResult:DEBUG'); |
| 633 | + while ( $row = $db->fetchObject($res) ) { |
| 634 | + $result .= $row->cat_name . ', '; |
| 635 | + } |
| 636 | + $result .= '<br />'; |
| 637 | + } |
629 | 638 | $result .= '</div>'; |
630 | 639 | /// TODO: report query errors! |
631 | 640 | return $result; |
— | — | @@ -676,18 +685,27 @@ |
677 | 686 | |
678 | 687 | ///// Setup store ///// |
679 | 688 | |
680 | | - function setup() { |
| 689 | + function setup($verbose = true) { |
681 | 690 | global $wgDBname; |
| 691 | + $this->reportProgress('Setting up standard database configuration for SMW ...<br /><br />',$verbose); |
682 | 692 | |
683 | 693 | $fname = 'SMW::setupDatabase'; |
684 | 694 | $db =& wfGetDB( DB_MASTER ); |
685 | 695 | |
686 | 696 | extract( $db->tableNames('smw_relations','smw_attributes','smw_longstrings','smw_specialprops') ); |
687 | 697 | |
| 698 | +/// DEBUG |
| 699 | +// $this->setupTable('smw_test', |
| 700 | +// array('subject_id' => 'INT(8) UNSIGNED NOT NULL', |
| 701 | +// 'subject_namespace' => 'INT(11) NOT NULL', |
| 702 | +// 'subject_title' => 'VARCHAR(255) NOT NULL', |
| 703 | +// 'nullvalue' => 'VARCHAR(255)', |
| 704 | +// 'value_unit' => 'VARCHAR(63)'), $db, $verbose); |
| 705 | + |
688 | 706 | // create relation table |
689 | | - if ($db->tableExists('smw_relations') === false) { |
| 707 | + if ($db->tableExists($smw_relations) === false) { |
690 | 708 | $sql = 'CREATE TABLE ' . $wgDBname . '.' . $smw_relations . ' |
691 | | - ( subject_id INT(8) UNSIGNED NOT NULL, |
| 709 | + ( subject_id INT(8) UNSIGNED NOT NULL, |
692 | 710 | subject_namespace INT(11) NOT NULL, |
693 | 711 | subject_title VARCHAR(255) NOT NULL, |
694 | 712 | relation_title VARCHAR(255) NOT NULL, |
— | — | @@ -695,12 +713,15 @@ |
696 | 714 | object_title VARCHAR(255) NOT NULL |
697 | 715 | ) TYPE=innodb'; |
698 | 716 | $res = $db->query( $sql, $fname ); |
| 717 | + } else { |
| 718 | + |
699 | 719 | } |
700 | 720 | |
701 | 721 | $this->setupIndex($smw_relations, array('subject_id','relation_title','object_title,object_namespace'), $db); |
| 722 | + $this->reportProgress('Relation table set up successfully.<br />',$verbose); |
702 | 723 | |
703 | 724 | // create attribute table |
704 | | - if ($db->tableExists('smw_attributes') === false) { |
| 725 | + if ($db->tableExists($smw_attributes) === false) { |
705 | 726 | $sql = 'CREATE TABLE ' . $wgDBname . '.' . $smw_attributes . ' |
706 | 727 | ( subject_id INT(8) UNSIGNED NOT NULL, |
707 | 728 | subject_namespace INT(11) NOT NULL, |
— | — | @@ -715,9 +736,10 @@ |
716 | 737 | } |
717 | 738 | |
718 | 739 | $this->setupIndex($smw_attributes, array('subject_id','attribute_title','value_num','value_xsd'), $db); |
| 740 | + $this->reportProgress('Attribute table set up successfully.<br />',$verbose); |
719 | 741 | |
720 | 742 | // create table for long string attributes |
721 | | - if ($db->tableExists('smw_longstrings') === false) { |
| 743 | + if ($db->tableExists($smw_longstrings) === false) { |
722 | 744 | $sql = 'CREATE TABLE ' . $wgDBname . '.' . $smw_longstrings . ' |
723 | 745 | ( subject_id INT(8) UNSIGNED NOT NULL, |
724 | 746 | subject_namespace INT(11) NOT NULL, |
— | — | @@ -729,9 +751,10 @@ |
730 | 752 | } |
731 | 753 | |
732 | 754 | $this->setupIndex($smw_longstrings, array('subject_id','attribute_title'), $db); |
| 755 | + $this->reportProgress('Table for long string values (Type:Text) set up successfully.<br />',$verbose); |
733 | 756 | |
734 | 757 | // create table for special properties |
735 | | - if ($db->tableExists('smw_specialprops') === false) { |
| 758 | + if ($db->tableExists($smw_specialprops) === false) { |
736 | 759 | $sql = 'CREATE TABLE ' . $wgDBname . '.' . $smw_specialprops . ' |
737 | 760 | ( subject_id INT(8) UNSIGNED NOT NULL, |
738 | 761 | subject_namespace INT(11) NOT NULL, |
— | — | @@ -741,9 +764,10 @@ |
742 | 765 | ) TYPE=innodb'; /// TODO: remove subject_namespace and subject_title columns completely |
743 | 766 | $res = $db->query( $sql, $fname ); |
744 | 767 | } |
745 | | - |
746 | 768 | $this->setupIndex($smw_specialprops, array('subject_id', 'property_id'), $db); |
747 | | - |
| 769 | + $this->reportProgress('Table for special properties set up successfully.<br />',$verbose); |
| 770 | + |
| 771 | + $this->reportProgress('Database initialised successfully.<br />',$verbose); |
748 | 772 | return true; |
749 | 773 | } |
750 | 774 | |
— | — | @@ -921,14 +945,13 @@ |
922 | 946 | if ($this->addInnerJoin('PAGE', $from, $db, $curtables)) { // try to add PAGE |
923 | 947 | $curtables['CATS'] = 'cl' . SMWSQLStore::$m_tablenum++; |
924 | 948 | $cond = $curtables['CATS'] . '.cl_from=' . $curtables['PAGE'] . '.page_id'; |
925 | | -// if ($smwgIQRedirectNormalization) { |
926 | | -// $this->addInnerJoin('REDIPAGE', $from, $db, $curtables); |
927 | | -// $cond = '((' . $cond . ') OR (' . |
928 | | -// $curtables['PAGE'] . '.page_id=' . $curtables['REDIRECT'] . '.rd_from AND ' . |
929 | | -// $curtables['REDIRECT'] . '.rd_title=' . $curtables['REDIPAGE'] . '.page_title AND ' . |
930 | | -// $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['REDIPAGE'] . '.page_namespace AND ' . |
931 | | -// $curtables['REDIPAGE'] . '.page_id=' . $curtables['CATS'] . '.cl_from))'; |
932 | | -// } |
| 949 | + /// TODO: slow, introduce another parameter to activate this |
| 950 | + if ($smwgIQRedirectNormalization && (array_key_exists('PREVREL', $curtables))) { |
| 951 | + // only do this at inner queries (PREVREL set) |
| 952 | + $this->addInnerJoin('REDIPAGE', $from, $db, $curtables); |
| 953 | + $cond = '((' . $cond . ') OR (' . |
| 954 | + $curtables['REDIPAGE'] . '.page_id=' . $curtables['CATS'] . '.cl_from))'; |
| 955 | + } |
933 | 956 | $from .= ' INNER JOIN ' . $db->tableName('categorylinks') . ' AS ' . $curtables['CATS'] . ' ON ' . $cond; |
934 | 957 | return true; |
935 | 958 | } |
— | — | @@ -936,20 +959,32 @@ |
937 | 960 | if ($this->addInnerJoin('PAGE', $from, $db, $curtables)) { // try to add PAGE |
938 | 961 | $curtables['RELS'] = 'rel' . SMWSQLStore::$m_tablenum++; |
939 | 962 | $cond = $curtables['RELS'] . '.subject_id=' . $curtables['PAGE'] . '.page_id'; |
940 | | -// if ($smwgIQRedirectNormalization) { |
941 | | -// $this->addInnerJoin('REDIRECT', $from, $db, $curtables); |
942 | | -// $cond = '((' . $cond . ') OR (' . |
943 | | -// $curtables['PAGE'] . '.page_id=' . $curtables['REDIRECT'] . '.rd_from AND ' . |
944 | | -// $curtables['REDIRECT'] . '.rd_title=' . $curtables['RELS'] . '.subject_title AND ' . |
945 | | -// $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['RELS'] . '.subject_namespace))'; |
946 | | -// } |
| 963 | + /// TODO: slow, introduce another parameter to activate this |
| 964 | + if ($smwgIQRedirectNormalization && (array_key_exists('PREVREL', $curtables))) { |
| 965 | + // only do this at inner queries (PREVREL set) |
| 966 | + $this->addInnerJoin('REDIRECT', $from, $db, $curtables); |
| 967 | + $cond = '((' . $cond . ') OR (' . |
| 968 | + //$curtables['PAGE'] . '.page_id=' . $curtables['REDIRECT'] . '.rd_from AND ' . |
| 969 | + $curtables['REDIRECT'] . '.rd_title=' . $curtables['RELS'] . '.subject_title AND ' . |
| 970 | + $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['RELS'] . '.subject_namespace))'; |
| 971 | + } |
947 | 972 | $from .= ' INNER JOIN ' . $db->tableName('smw_relations') . ' AS ' . $curtables['RELS'] . ' ON ' . $cond; |
948 | 973 | return true; |
949 | 974 | } |
950 | 975 | } elseif ($tablename == 'ATTS') { |
951 | 976 | if ($this->addInnerJoin('PAGE', $from, $db, $curtables)) { // try to add PAGE |
952 | 977 | $curtables['ATTS'] = 'att' . SMWSQLStore::$m_tablenum++; |
953 | | - $from .= ' INNER JOIN ' . $db->tableName('smw_attributes') . ' AS ' . $curtables['ATTS'] . ' ON ' . $curtables['ATTS'] . '.subject_id=' . $curtables['PAGE'] . '.page_id'; |
| 978 | + $cond = $curtables['ATTS'] . '.subject_id=' . $curtables['PAGE'] . '.page_id'; |
| 979 | + /// TODO: slow, introduce another parameter to activate this |
| 980 | + if ($smwgIQRedirectNormalization && (array_key_exists('PREVREL', $curtables))) { |
| 981 | + // only do this at inner queries (PREVREL set) |
| 982 | + $this->addInnerJoin('REDIRECT', $from, $db, $curtables); |
| 983 | + $cond = '((' . $cond . ') OR (' . |
| 984 | + //$curtables['PAGE'] . '.page_id=' . $curtables['REDIRECT'] . '.rd_from AND ' . |
| 985 | + $curtables['REDIRECT'] . '.rd_title=' . $curtables['ATTS'] . '.subject_title AND ' . |
| 986 | + $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['ATTS'] . '.subject_namespace))'; |
| 987 | + } |
| 988 | + $from .= ' INNER JOIN ' . $db->tableName('smw_attributes') . ' AS ' . $curtables['ATTS'] . ' ON ' . $cond; |
954 | 989 | return true; |
955 | 990 | } |
956 | 991 | } elseif ($tablename == 'TEXT') { |
— | — | @@ -961,13 +996,16 @@ |
962 | 997 | } elseif ($tablename == 'REDIRECT') { |
963 | 998 | if ($this->addInnerJoin('PAGE', $from, $db, $curtables)) { // try to add PAGE |
964 | 999 | $curtables['REDIRECT'] = 'rd' . SMWSQLStore::$m_tablenum++; |
965 | | - $from .= ' INNER JOIN ' . $db->tableName('redirect') . ' AS ' . $curtables['REDIRECT']; |
| 1000 | + $from .= ' LEFT JOIN ' . $db->tableName('redirect') . ' AS ' . $curtables['REDIRECT'] . ' ON ' . $curtables['REDIRECT'] . '.rd_from=' . $curtables['PAGE'] . '.page_id'; |
966 | 1001 | return true; |
967 | 1002 | } |
968 | 1003 | } elseif ($tablename == 'REDIPAGE') { // add another copy of page for getting ids of redirect targets |
969 | 1004 | if ($this->addInnerJoin('REDIRECT', $from, $db, $curtables)) { |
970 | 1005 | $curtables['REDIPAGE'] = 'rp' . SMWSQLStore::$m_tablenum++; |
971 | | - $from .= ' INNER JOIN ' . $db->tableName('page') . ' AS ' . $curtables['REDIPAGE']; |
| 1006 | + $from .= ' INNER JOIN ' . $db->tableName('page') . ' AS ' . $curtables['REDIPAGE'] . ' ON (' . |
| 1007 | + $curtables['REDIRECT'] . '.rd_title=' . $curtables['REDIPAGE'] . '.page_title AND ' . |
| 1008 | + $curtables['REDIRECT'] . '.rd_namespace=' . $curtables['REDIPAGE'] . '.page_namespace)'; |
| 1009 | + |
972 | 1010 | return true; |
973 | 1011 | } |
974 | 1012 | } |
— | — | @@ -1036,8 +1074,8 @@ |
1037 | 1075 | $page->getNamespace(); |
1038 | 1076 | if ( $smwgIQRedirectNormalization && ($this->addInnerJoin('REDIRECT', $from, $db, $curtables)) ) { |
1039 | 1077 | $cond = '(' . $cond . ') OR (' . |
1040 | | - $curtables['REDIRECT'] . '.rd_from=' . |
1041 | | - $curtables['PAGE'] . '.page_id AND ' . |
| 1078 | +// $curtables['REDIRECT'] . '.rd_from=' . |
| 1079 | +// $curtables['PAGE'] . '.page_id AND ' . |
1042 | 1080 | $curtables['REDIRECT'] . '.rd_title=' . |
1043 | 1081 | $db->addQuotes($page->getDBKey()) . ' AND ' . |
1044 | 1082 | $curtables['REDIRECT'] . '.rd_namespace=' . |
— | — | @@ -1149,6 +1187,48 @@ |
1150 | 1188 | } |
1151 | 1189 | } |
1152 | 1190 | } |
| 1191 | + |
| 1192 | + /** |
| 1193 | + * Make sure the table of the given name has the given fields, provided |
| 1194 | + * as an array with entries fieldname => typeparams. typeparams should be |
| 1195 | + * in a normalised form and order to match to existing values. |
| 1196 | + */ |
| 1197 | + protected function setupTable($table, $fields, $db, $verbose) { |
| 1198 | + global $wgDBname; |
| 1199 | + if ($db->tableExists($table) === false) { // create new table |
| 1200 | + $sql = 'CREATE TABLE ' . $wgDBname . '.' . $table . ' ('; |
| 1201 | + $first = true; |
| 1202 | + foreach ($fields as $name => $type) { |
| 1203 | + if ($first) { |
| 1204 | + $first = false; |
| 1205 | + } else { |
| 1206 | + $sql .= ','; |
| 1207 | + } |
| 1208 | + $sql .= $name . ' ' . $type; |
| 1209 | + } |
| 1210 | + $sql .= ') TYPE=innodb'; |
| 1211 | + $db->query( $sql, 'SMWSQLStore::setupTable' ); |
| 1212 | + } else { // check table signature |
| 1213 | + $res = $db->query( 'DESCRIBE ' . $table, 'SMWSQLStore::setupTable' ); |
| 1214 | + $curfields = array(); |
| 1215 | + while ($row = $db->fetchObject($res)) { |
| 1216 | + $type = strtoupper($row->Type); |
| 1217 | + if ($row->Null != 'YES') { |
| 1218 | + $type .= ' NOT NULL'; |
| 1219 | + } |
| 1220 | + $curfields[$row->Field] = $type; |
| 1221 | + } |
| 1222 | + foreach ($fields as $name => $type) { |
| 1223 | + if ( !array_key_exists($name,$curfields) ) { |
| 1224 | + $this->reportProgress("Field $name not existing yet.<br />",$verbose); |
| 1225 | + } elseif ($curfields[$name] != $type) { |
| 1226 | + $this->reportProgress("Field $name has wrong type (should be '$type', but is '$curfields[$name]').<br />",$verbose); |
| 1227 | + } else { |
| 1228 | + $this->reportProgress("Field $name is fine.<br />",$verbose); |
| 1229 | + } |
| 1230 | + } |
| 1231 | + } |
| 1232 | + } |
1153 | 1233 | |
1154 | 1234 | /** |
1155 | 1235 | * Make sure that each of the column descriptions in the given array is indexed by *one* index |
— | — | @@ -1184,6 +1264,19 @@ |
1185 | 1265 | return true; |
1186 | 1266 | } |
1187 | 1267 | |
| 1268 | + /** |
| 1269 | + * Print some output to indicate progress. The output message is given by |
| 1270 | + * $msg, while $verbose indicates whether or not output is desired at all. |
| 1271 | + */ |
| 1272 | + protected function reportProgress($msg, $verbose) { |
| 1273 | + if (!$verbose) { |
| 1274 | + return; |
| 1275 | + } |
| 1276 | + print $msg; |
| 1277 | + ob_flush(); |
| 1278 | + flush(); |
| 1279 | + } |
| 1280 | + |
1188 | 1281 | } |
1189 | 1282 | |
1190 | 1283 | |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_Store.php |
— | — | @@ -227,8 +227,13 @@ |
228 | 228 | * creation of database tables. It is called upon installation as well as on upgrade: hence it |
229 | 229 | * must be able to upgrade existing storage structures if needed. It should return "true" if |
230 | 230 | * successful and return a meaningful string error message otherwise. |
| 231 | + * |
| 232 | + * The parameter $verbose determines whether the procedure is allowed to report on its progress. |
| 233 | + * This is doen by just using print and possibly ob_flush/flush. This is also relevant for preventing |
| 234 | + * timeouts during long operations. All output must be valid XHTML, but should preferrably be plain |
| 235 | + * text, possibly with some linebreaks and weak markup. |
231 | 236 | */ |
232 | | - abstract function setup(); |
| 237 | + abstract function setup($verbose = true); |
233 | 238 | |
234 | 239 | } |
235 | 240 | |