Index: trunk/extensions/BotQuery/query.php |
— | — | @@ -111,7 +111,7 @@ |
112 | 112 | * 0) Function to call |
113 | 113 | * 1) true/false - does this property work on individual pages? (false for site's metadata) |
114 | 114 | * 2) array of accepted parameters |
115 | | - * 3) array of default parameter values |
| 115 | + * 3) array of default parameter values. If the default value is an array itself, only the listed values are allowed, and the 1st value is taken as default. |
116 | 116 | * 4) Format description |
117 | 117 | */ |
118 | 118 | var $propGenerators = array( |
— | — | @@ -209,7 +209,7 @@ |
210 | 210 | "blfilter - Of all given pages, which should be queried:", |
211 | 211 | " 'nonredirects', 'existing' (blue links, default), or 'all' (red links)", |
212 | 212 | "bllimit - how many total links to return", |
213 | | - "blcontfrom - from which point to continue. Use the 'next' value from previous queries.", |
| 213 | + "blcontfrom - from which point to continue. Use the 'next' value from the previous queries.", |
214 | 214 | "Example: query.php?what=backlinks&titles=Main%20Page&bllimit=10", |
215 | 215 | )), |
216 | 216 | 'embeddedin' => array( 'genPageBackLinksHelper', false, |
— | — | @@ -221,35 +221,40 @@ |
222 | 222 | "eifilter - Of all given pages, which should be queried:", |
223 | 223 | " 'nonredirects', 'existing' (blue links, default), or 'all' (red links)", |
224 | 224 | "eilimit - how many total links to return", |
225 | | - "eicontfrom - from which point to continue. Use the 'next' value from previous queries.", |
| 225 | + "eicontfrom - from which point to continue. Use the 'next' value from the previous queries.", |
226 | 226 | "Example: query.php?what=embeddedin&titles=Template:Stub&eilimit=10", |
227 | 227 | )), |
228 | 228 | 'imagelinks' => array( 'genPageBackLinksHelper', false, |
229 | 229 | array( 'ilfilter', 'illimit', 'ilcontfrom' ), |
230 | | - array( array('existing', 'nonredirects', 'all'), 50, null ), |
| 230 | + array( array('all', 'existing', 'nonredirects'), 50, null ), |
231 | 231 | array( |
232 | 232 | "What pages use this image(s)", |
233 | 233 | "ilfilter - Of all given images, which should be queried:", |
234 | | - " 'nonredirects', 'existing' (default), or 'all' (including non-existant)", |
| 234 | + " 'nonredirects', 'existing', or 'all' (default, includes non-existant or those stored on Wikimedia Commons)", |
235 | 235 | "illimit - how many total links to return", |
236 | | - "ilcontfrom - from which point to continue. Use the 'next' value from previous queries.", |
237 | | - "Example: query.php?what=imagelinks&titles=image:test.jpg&illimit=10", |
| 236 | + "ilcontfrom - from which point to continue. Use the 'next' value from the previous queries.", |
| 237 | + "Example: query.php?what=imagelinks&titles=Image:HermitageAcrossNeva.jpg&illimit=10", |
238 | 238 | )), |
239 | 239 | 'revisions' => array( 'genPageHistory', false, |
240 | | - array( 'rvcomments', 'rvlimit', 'rvoffset', 'rvstart', 'rvend' ), |
241 | | - array( false, 50, 0, null, null ), |
| 240 | + array( 'rvcomments', 'rvcontent', 'rvlimit', 'rvoffset', 'rvstart', 'rvend' ), |
| 241 | + array( false, false, 50, 0, null, null ), |
242 | 242 | array( |
243 | 243 | "Revision history - Lists edits performed to the given pages", |
244 | 244 | "Parameters supported:", |
245 | 245 | "rvcomments - if specified, the result will include summary strings", |
| 246 | + "rvcontent - if specified, the result will include raw wiki text.", |
| 247 | + " This parameter is *very slow*, use only when needed.", |
246 | 248 | "rvlimit - how many links to return *for each title*", |
247 | 249 | "rvoffset - when too many results are found, use this to page", |
248 | 250 | "rvstart - timestamp of the earliest entry", |
249 | 251 | "rvend - timestamp of the latest entry", |
250 | 252 | "Example: query.php?what=revisions&titles=Main%20Page&rvlimit=10&rvcomments", |
251 | 253 | )), |
252 | | - 'content' => array( 'genPageContent', false, null, null, array( |
253 | | - "Raw page content", |
| 254 | + 'content' => array( 'genPageContent', false, null, null, |
| 255 | + array( |
| 256 | + "Raw page content - Retrieves raw wiki markup for each page.", |
| 257 | + "This query is *very slow*! Please optimize content requests to reduce load on the servers.", |
| 258 | + "Duplicate results may be obtained through revisions+rvcontent request", |
254 | 259 | "Example: query.php?what=content&titles=Main%20Page", |
255 | 260 | )), |
256 | 261 | ); |
— | — | @@ -320,9 +325,7 @@ |
321 | 326 | function output($isError = false) { |
322 | 327 | global $wgRequest, $wgUser; |
323 | 328 | |
324 | | - // hack: pretend that profiling was started at the begining of the class execution. |
325 | | - $this->startTime = $this->totalStartTime; |
326 | | - $this->endProfiling( 'total' ); |
| 329 | + $this->recordProfiling( 'total', 'time', $this->totalStartTime ); |
327 | 330 | |
328 | 331 | $printer = $this->outputGenerators[$this->format][GEN_FUNCTION]; |
329 | 332 | $mime = $this->outputGenerators[$this->format][GEN_MIME]; |
— | — | @@ -404,7 +407,7 @@ |
405 | 408 | */ |
406 | 409 | function genPageInfo() { |
407 | 410 | global $wgUser, $wgRequest; |
408 | | - |
| 411 | + $this->startProfiling(); |
409 | 412 | $where = array(); |
410 | 413 | |
411 | 414 | // |
— | — | @@ -414,8 +417,8 @@ |
415 | 418 | if( $titles !== null ) { |
416 | 419 | $titles = explode( '|', $titles ); |
417 | 420 | $linkBatch = new LinkBatch; |
418 | | - foreach ( $titles as $titleString ) { |
419 | | - $titleObj = Title::newFromText( $titleString ); |
| 421 | + foreach ( $titles as &$titleString ) { |
| 422 | + $titleObj = &Title::newFromText( $titleString ); |
420 | 423 | if ( !$titleObj ) { |
421 | 424 | $this->dieUsage( "bad title $titleString", 'pi_invalidtitle' ); |
422 | 425 | } |
— | — | @@ -442,7 +445,6 @@ |
443 | 446 | } else { |
444 | 447 | $nonexistentPages = array(); // empty data to keep unset() happy |
445 | 448 | } |
446 | | - |
447 | 449 | // |
448 | 450 | // List of Page IDs |
449 | 451 | // |
— | — | @@ -458,9 +460,10 @@ |
459 | 461 | $where['page_id'] = $pageids; |
460 | 462 | $this->requestsize += count($pageids); |
461 | 463 | } |
462 | | - |
| 464 | + |
463 | 465 | // Do we have anything to do? |
464 | 466 | if( $this->requestsize == 0 ) { |
| 467 | + // Do not end profiling here, as it will introduce an element to the data object, and the usage screen may not be shown. |
465 | 468 | return false; // Nothing to do for any of the page generators |
466 | 469 | } |
467 | 470 | |
— | — | @@ -481,12 +484,12 @@ |
482 | 485 | // Query page information with the given lists of titles & pageIDs |
483 | 486 | // |
484 | 487 | $this->redirectPageIds = array(); |
485 | | - $this->startProfiling(); |
| 488 | + $this->startDbProfiling(); |
486 | 489 | $res = $this->db->select( 'page', |
487 | 490 | array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect', 'page_touched', 'page_latest' ), |
488 | 491 | $this->db->makeList( $where, LIST_OR ), |
489 | 492 | $this->classname . '::genPageInfo' ); |
490 | | - $this->endProfiling('pageInfo'); |
| 493 | + $this->endDbProfiling('pageInfo'); |
491 | 494 | while( $row = $this->db->fetchObject( $res ) ) { |
492 | 495 | $title = Title::makeTitle( $row->page_namespace, $row->page_title ); |
493 | 496 | if ( !$title->userCanRead() ) { |
— | — | @@ -568,7 +571,7 @@ |
569 | 572 | $data['_element'] = 'title'; |
570 | 573 | $data[] = $givenTitle; |
571 | 574 | } |
572 | | - |
| 575 | + $this->endProfiling('pageInfo'); |
573 | 576 | return true; // success |
574 | 577 | } |
575 | 578 | |
— | — | @@ -583,6 +586,7 @@ |
584 | 587 | */ |
585 | 588 | function genMetaSiteInfo(&$prop, &$genInfo) { |
586 | 589 | global $wgSitename, $wgVersion, $wgCapitalLinks; |
| 590 | + $this->startProfiling(); |
587 | 591 | $meta = array(); |
588 | 592 | $mainPage = Title::newFromText( wfMsgForContent( 'mainpage' ) ); |
589 | 593 | |
— | — | @@ -593,6 +597,7 @@ |
594 | 598 | $meta['case'] = $wgCapitalLinks ? 'first-letter' : 'case-sensitive'; // "case-insensitive" option is reserved for future |
595 | 599 | |
596 | 600 | $this->data['meta']['site'] = $meta; |
| 601 | + $this->endProfiling($prop); |
597 | 602 | } |
598 | 603 | |
599 | 604 | /** |
— | — | @@ -600,12 +605,14 @@ |
601 | 606 | */ |
602 | 607 | function genMetaNamespaceInfo(&$prop, &$genInfo) { |
603 | 608 | global $wgContLang; |
| 609 | + $this->startProfiling(); |
604 | 610 | $meta = array(); |
605 | 611 | $meta['_element'] = 'ns'; |
606 | 612 | foreach( $wgContLang->getFormattedNamespaces() as $ns => $title ) { |
607 | 613 | $meta[$ns] = array( "id"=>$ns, "*" => $title ); |
608 | 614 | } |
609 | 615 | $this->data['meta']['namespaces'] = $meta; |
| 616 | + $this->endProfiling($prop); |
610 | 617 | } |
611 | 618 | |
612 | 619 | /** |
— | — | @@ -613,7 +620,7 @@ |
614 | 621 | */ |
615 | 622 | function genMetaUserInfo(&$prop, &$genInfo) { |
616 | 623 | global $wgUser; |
617 | | - |
| 624 | + $this->startProfiling(); |
618 | 625 | extract( $this->getParams( $prop, $genInfo )); |
619 | 626 | $meta = array(); |
620 | 627 | $meta['name'] = $wgUser->getName(); |
— | — | @@ -627,13 +634,14 @@ |
628 | 635 | $meta['rights']['_element'] = 'r'; |
629 | 636 | } |
630 | 637 | $this->data['meta']['user'] = $meta; |
| 638 | + $this->endProfiling($prop); |
631 | 639 | } |
632 | 640 | |
633 | 641 | /** |
634 | 642 | * Add pagids of the most recently modified pages to the output |
635 | 643 | */ |
636 | 644 | function genMetaRecentChanges(&$prop, &$genInfo) { |
637 | | - |
| 645 | + $this->startProfiling(); |
638 | 646 | extract( $this->getParams( $prop, $genInfo )); |
639 | 647 | # It makes no sense to hide both anons and logged-in users |
640 | 648 | if( in_array('anons', $rchide) && in_array('liu', $rchide) ) { |
— | — | @@ -670,7 +678,7 @@ |
671 | 679 | $options = array( 'USE INDEX' => 'rc_timestamp', 'LIMIT' => $rclimit ); |
672 | 680 | $options['ORDER BY'] = 'rc_timestamp' . ( $rcfrom != '' ? '' : ' DESC' ); |
673 | 681 | |
674 | | - $this->startProfiling(); |
| 682 | + $this->startDbProfiling(); |
675 | 683 | $res = $this->db->select( |
676 | 684 | 'recentchanges', |
677 | 685 | 'rc_cur_id', |
— | — | @@ -678,13 +686,14 @@ |
679 | 687 | $this->classname . '::genMetaRecentChanges', |
680 | 688 | $options |
681 | 689 | ); |
682 | | - $this->endProfiling($prop); |
| 690 | + $this->endDbProfiling($prop); |
683 | 691 | while ( $row = $this->db->fetchObject( $res ) ) { |
684 | 692 | if( $row->rc_cur_id != 0 ) { |
685 | 693 | $this->addRaw( 'pageids', $row->rc_cur_id ); |
686 | 694 | } |
687 | 695 | } |
688 | 696 | $this->db->freeResult( $res ); |
| 697 | + $this->endProfiling($prop); |
689 | 698 | } |
690 | 699 | |
691 | 700 | /** |
— | — | @@ -692,12 +701,12 @@ |
693 | 702 | */ |
694 | 703 | function genUserPages(&$prop, &$genInfo) { |
695 | 704 | global $wgContLang; |
696 | | - |
| 705 | + $this->startProfiling(); |
697 | 706 | extract( $this->getParams( $prop, $genInfo )); |
698 | 707 | |
699 | 708 | $this->validateLimit( 'uslimit', $uslimit, 50, 1000 ); |
700 | 709 | |
701 | | - $this->startProfiling(); |
| 710 | + $this->startDbProfiling(); |
702 | 711 | $res = $this->db->select( |
703 | 712 | 'user', |
704 | 713 | 'user_name', |
— | — | @@ -705,7 +714,7 @@ |
706 | 715 | $this->classname . '::genUserPages', |
707 | 716 | array( 'ORDER BY' => 'user_name', 'LIMIT' => $uslimit ) |
708 | 717 | ); |
709 | | - $this->endProfiling($prop); |
| 718 | + $this->endDbProfiling($prop); |
710 | 719 | |
711 | 720 | $userNS = $wgContLang->getNsText(NS_USER); |
712 | 721 | if( !$userNS ) $userNS = 'User'; |
— | — | @@ -715,6 +724,7 @@ |
716 | 725 | $this->addRaw( 'titles', $userNS . $row->user_name ); |
717 | 726 | } |
718 | 727 | $this->db->freeResult( $res ); |
| 728 | + $this->endProfiling($prop); |
719 | 729 | } |
720 | 730 | |
721 | 731 | /** |
— | — | @@ -725,6 +735,7 @@ |
726 | 736 | // TODO: This is very inefficient - we can get the actual page information, instead we make two identical query. |
727 | 737 | // |
728 | 738 | global $wgContLang; |
| 739 | + $this->startProfiling(); |
729 | 740 | extract( $this->getParams( $prop, $genInfo )); |
730 | 741 | |
731 | 742 | $this->validateLimit( 'aplimit', $aplimit, 50, 1000 ); |
— | — | @@ -736,14 +747,14 @@ |
737 | 748 | $ns .= ':'; |
738 | 749 | } |
739 | 750 | |
740 | | - $this->startProfiling(); |
| 751 | + $this->startDbProfiling(); |
741 | 752 | $res = $this->db->select( |
742 | 753 | 'page', |
743 | 754 | 'page_title', |
744 | 755 | array( 'page_namespace' => intval($apnamespace), 'page_title>=' . $this->db->addQuotes($apfrom) ), |
745 | 756 | $this->classname . '::genMetaAllPages', |
746 | | - array( 'FORCE INDEX' => 'name_title', 'LIMIT' => $aplimit+1, 'ORDER BY' => 'page_namespace, page_title' )); |
747 | | - $this->endProfiling($prop); |
| 757 | + array( 'USE INDEX' => 'name_title', 'LIMIT' => $aplimit+1, 'ORDER BY' => 'page_namespace, page_title' )); |
| 758 | + $this->endDbProfiling($prop); |
748 | 759 | |
749 | 760 | // Add found page ids to the list of requested titles - they will be auto-populated later |
750 | 761 | $count = 0; |
— | — | @@ -756,6 +767,7 @@ |
757 | 768 | $this->addRaw( 'titles', $ns . $row->page_title ); |
758 | 769 | } |
759 | 770 | $this->db->freeResult( $res ); |
| 771 | + $this->endProfiling($prop); |
760 | 772 | } |
761 | 773 | |
762 | 774 | /** |
— | — | @@ -766,6 +778,7 @@ |
767 | 779 | // TODO: This is very inefficient - we can get the actual page information, instead we make two identical query. |
768 | 780 | // |
769 | 781 | global $wgContLang; |
| 782 | + $this->startProfiling(); |
770 | 783 | extract( $this->getParams( $prop, $genInfo )); |
771 | 784 | $this->validateLimit( 'nllimit', $nllimit, 50, 1000 ); |
772 | 785 | extract( $this->db->tableNames( 'page', 'langlinks' ) ); |
— | — | @@ -781,9 +794,9 @@ |
782 | 795 | . ' ORDER BY page_namespace, page_title' |
783 | 796 | . ' LIMIT ' . intval($nllimit+1); |
784 | 797 | |
785 | | - $this->startProfiling(); |
| 798 | + $this->startDbProfiling(); |
786 | 799 | $res = $this->db->query( $sql, $this->classname . '::genMetaNoLangLinksPages' ); |
787 | | - $this->endProfiling($prop); |
| 800 | + $this->endDbProfiling($prop); |
788 | 801 | |
789 | 802 | // Add found page ids to the list of requested titles - they will be auto-populated later |
790 | 803 | $count = 0; |
— | — | @@ -796,6 +809,7 @@ |
797 | 810 | $this->addRaw( 'pageids', $row->page_id ); |
798 | 811 | } |
799 | 812 | $this->db->freeResult( $res ); |
| 813 | + $this->endProfiling($prop); |
800 | 814 | } |
801 | 815 | |
802 | 816 | |
— | — | @@ -812,6 +826,7 @@ |
813 | 827 | if( empty( $this->redirectPageIds ) ) { |
814 | 828 | return; |
815 | 829 | } |
| 830 | + $this->startProfiling(); |
816 | 831 | extract( $this->db->tableNames( 'page', 'pagelinks' ) ); |
817 | 832 | |
818 | 833 | // |
— | — | @@ -843,9 +858,9 @@ |
844 | 859 | "pb.page_is_redirect IS NULL OR pb.page_is_redirect = '1'" |
845 | 860 | ), LIST_AND ); |
846 | 861 | |
847 | | - $this->startProfiling(); |
| 862 | + $this->startDbProfiling(); |
848 | 863 | $res = $this->db->query( $sql, $this->classname . '::genRedirectInfo' ); |
849 | | - $this->endProfiling('redirects'); |
| 864 | + $this->endDbProfiling('redirects'); |
850 | 865 | while ( $row = $this->db->fetchObject( $res ) ) { |
851 | 866 | $this->addPageSubElement( $row->a_id, 'redirect', 'to', $this->getLinkInfo( $row->b_namespace, $row->b_title, $row->b_id, $row->b_is_redirect ), false); |
852 | 867 | if( $row->b_is_redirect ) { |
— | — | @@ -853,6 +868,7 @@ |
854 | 869 | } |
855 | 870 | } |
856 | 871 | $this->db->freeResult( $res ); |
| 872 | + $this->endProfiling($prop); |
857 | 873 | } |
858 | 874 | |
859 | 875 | var $genPageLinksSettings = array( // database column name prefix, output element name |
— | — | @@ -867,9 +883,10 @@ |
868 | 884 | if( empty($this->nonRedirPageIds) ) { |
869 | 885 | return; |
870 | 886 | } |
| 887 | + $this->startProfiling(); |
871 | 888 | extract( $this->genPageLinksSettings[$prop] ); |
872 | 889 | |
873 | | - $this->startProfiling(); |
| 890 | + $this->startDbProfiling(); |
874 | 891 | $res = $this->db->select( |
875 | 892 | $linktbl, |
876 | 893 | array( "{$prefix}_from from_id", |
— | — | @@ -877,7 +894,7 @@ |
878 | 895 | "{$prefix}_title to_title" ), |
879 | 896 | array( "{$prefix}_from" => $this->nonRedirPageIds ), |
880 | 897 | $this->classname . "::genPageLinks_{$code}" ); |
881 | | - $this->endProfiling($prop); |
| 898 | + $this->endDbProfiling($prop); |
882 | 899 | |
883 | 900 | while ( $row = $this->db->fetchObject( $res ) ) { |
884 | 901 | if( $langlinks ) { |
— | — | @@ -888,6 +905,7 @@ |
889 | 906 | $this->addPageSubElement( $row->from_id, $prop, $code, $values); |
890 | 907 | } |
891 | 908 | $this->db->freeResult( $res ); |
| 909 | + $this->endProfiling($prop); |
892 | 910 | } |
893 | 911 | |
894 | 912 | var $genPageBackLinksSettings = array( // database column name prefix, output element name |
— | — | @@ -900,7 +918,7 @@ |
901 | 919 | * $type - either 'template' or 'page' |
902 | 920 | */ |
903 | 921 | function genPageBackLinksHelper(&$prop, &$genInfo) { |
904 | | - |
| 922 | + $this->startProfiling(); |
905 | 923 | extract( $this->genPageBackLinksSettings[$prop] ); |
906 | 924 | |
907 | 925 | // |
— | — | @@ -1009,14 +1027,14 @@ |
1010 | 1028 | // |
1011 | 1029 | // Execute |
1012 | 1030 | // |
1013 | | - $this->startProfiling(); |
| 1031 | + $this->startDbProfiling(); |
1014 | 1032 | $res = $this->db->select( |
1015 | 1033 | array( $linktbl, 'page' ), |
1016 | 1034 | $columns, |
1017 | 1035 | $where, |
1018 | 1036 | $this->classname . "::genPageBackLinks_{$code}", |
1019 | 1037 | $options ); |
1020 | | - $this->endProfiling($prop); |
| 1038 | + $this->endDbProfiling($prop); |
1021 | 1039 | |
1022 | 1040 | $count = 0; |
1023 | 1041 | while ( $row = $this->db->fetchObject( $res ) ) { |
— | — | @@ -1031,6 +1049,7 @@ |
1032 | 1050 | $this->addPageSubElement( $pageId, $prop, $code, $values ); |
1033 | 1051 | } |
1034 | 1052 | $this->db->freeResult( $res ); |
| 1053 | + $this->endProfiling($prop); |
1035 | 1054 | } |
1036 | 1055 | |
1037 | 1056 | /** |
— | — | @@ -1040,10 +1059,12 @@ |
1041 | 1060 | if( empty( $this->existingPageIds ) ) { |
1042 | 1061 | return; |
1043 | 1062 | } |
| 1063 | + $this->startProfiling(); |
1044 | 1064 | extract( $this->getParams( $prop, $genInfo )); |
1045 | 1065 | |
1046 | | - $fields = array('rev_id', 'rev_timestamp', 'rev_user', 'rev_user_text', 'rev_minor_edit'); |
1047 | | - if( isset($rvcomments) ) { |
| 1066 | + $tables = array('revision'); |
| 1067 | + $fields = array('rev_id', 'rev_text_id', 'rev_timestamp', 'rev_user', 'rev_user_text', 'rev_minor_edit'); |
| 1068 | + if( $rvcomments ) { |
1048 | 1069 | $fields[] = 'rev_comment'; |
1049 | 1070 | } |
1050 | 1071 | $conds = array( 'rev_deleted' => 0 ); |
— | — | @@ -1060,15 +1081,30 @@ |
1061 | 1082 | if( $rvoffset !== 0 ) { |
1062 | 1083 | $options['OFFSET'] = $rvoffset; |
1063 | 1084 | } |
1064 | | - $this->validateLimit( 'rvlimit * pages', $rvlimit * count($this->existingPageIds), 200, 2000 ); |
1065 | | - |
1066 | | - $this->startProfiling(); |
| 1085 | + if( $rvcontent ) { |
| 1086 | + $this->validateLimit( 'content + rvlimit * pages', $rvlimit * count($this->existingPageIds), 50, 200 ); |
| 1087 | + $tables[] = 'text'; |
| 1088 | + $fields[] = 'old_id'; |
| 1089 | + $fields[] = 'old_text'; |
| 1090 | + $fields[] = 'old_flags'; |
| 1091 | + $conds[] = 'rev_text_id=old_id'; |
| 1092 | + } else { |
| 1093 | + $this->validateLimit( 'rvlimit * pages', $rvlimit * count($this->existingPageIds), 200, 2000 ); |
| 1094 | + } |
| 1095 | + |
| 1096 | + $this->startDbProfiling(); |
1067 | 1097 | foreach( $this->existingPageIds as $pageId ) { |
1068 | 1098 | $conds['rev_page'] = $pageId; |
1069 | | - $res = $this->db->select( 'revision', $fields, $conds, $this->classname . '::genPageHistory', $options ); |
| 1099 | + $res = $this->db->select( |
| 1100 | + $tables, |
| 1101 | + $fields, |
| 1102 | + $conds, |
| 1103 | + $this->classname . '::genPageHistory', |
| 1104 | + $options ); |
1070 | 1105 | while ( $row = $this->db->fetchObject( $res ) ) { |
1071 | 1106 | $vals = array( |
1072 | 1107 | 'revid' => $row->rev_id, |
| 1108 | + 'oldid' => $row->rev_text_id, |
1073 | 1109 | 'timestamp' => wfTimestamp( TS_ISO_8601, $row->rev_timestamp ), |
1074 | 1110 | 'user' => $row->rev_user_text, |
1075 | 1111 | ); |
— | — | @@ -1078,11 +1114,18 @@ |
1079 | 1115 | if( $row->rev_minor_edit ) { |
1080 | 1116 | $vals['minor'] = ''; |
1081 | 1117 | } |
1082 | | - $vals['*'] = $rvcomments ? $row->rev_comment : ''; |
| 1118 | + if( $rvcomments ) { |
| 1119 | + $vals['comment'] = $row->rev_comment; |
| 1120 | + } |
| 1121 | + if( $rvcontent ) { |
| 1122 | + $vals['xml:space'] = 'preserve'; |
| 1123 | + $vals['*'] = Revision::getRevisionText( $row ); |
| 1124 | + } |
1083 | 1125 | $this->addPageSubElement( $pageId, 'revisions', 'rv', $vals); |
1084 | 1126 | } |
1085 | 1127 | $this->db->freeResult( $res ); |
1086 | 1128 | } |
| 1129 | + $this->endDbProfiling($prop); |
1087 | 1130 | $this->endProfiling($prop); |
1088 | 1131 | } |
1089 | 1132 | |
— | — | @@ -1093,23 +1136,33 @@ |
1094 | 1137 | if( empty( $this->existingPageIds ) ) { |
1095 | 1138 | return; |
1096 | 1139 | } |
1097 | | - $this->validateLimit( 'co_querytoobig', count($this->existingPageIds), 50, 200 ); |
1098 | 1140 | $this->startProfiling(); |
| 1141 | + |
| 1142 | + // Generate the WHERE clause for pageIds+RevisionIds |
| 1143 | + $ids = array(); |
| 1144 | + foreach( $this->data['pages'] as $pageId => &$page ) { |
| 1145 | + if( $pageId > 0 ) { |
| 1146 | + $ids[] = "(rev_page=$pageId AND rev_id={$page['revid']})"; |
| 1147 | + } |
| 1148 | + } |
| 1149 | + $this->validateLimit( 'co_querytoobig', count($ids), 50, 200 ); |
| 1150 | + |
| 1151 | + $this->startDbProfiling(); |
1099 | 1152 | $res = $this->db->select( |
1100 | | - array('page', 'revision', 'text'), |
1101 | | - array('page_id', 'old_id', 'old_text', 'old_flags'), |
1102 | | - array('page_id=rev_page', 'page_latest=rev_id', 'rev_text_id=old_id', 'page_id' => $this->existingPageIds), |
| 1153 | + array('revision', 'text'), |
| 1154 | + array('rev_page', 'old_id', 'old_text', 'old_flags'), |
| 1155 | + array('rev_text_id=old_id', implode('OR', $ids)), |
1103 | 1156 | $this->classname . '::genPageContent' |
1104 | 1157 | ); |
1105 | 1158 | while ( $row = $this->db->fetchObject( $res ) ) { |
1106 | | - $this->addPageSubElement( $row->page_id, $prop, 'xml:space', 'preserve', false); |
1107 | | - $this->addPageSubElement( $row->page_id, $prop, '*', Revision::getRevisionText( $row ), false); |
| 1159 | + $this->addPageSubElement( $row->rev_page, $prop, 'xml:space', 'preserve', false); |
| 1160 | + $this->addPageSubElement( $row->rev_page, $prop, '*', Revision::getRevisionText( $row ), false); |
1108 | 1161 | } |
1109 | 1162 | $this->db->freeResult( $res ); |
1110 | | - $this->endProfiling($prop); // getRevisionText is also a database call |
| 1163 | + $this->endDbProfiling($prop); // Revision::getRevisionText is also a database call, so we include them in this scope |
| 1164 | + $this->endProfiling($prop); |
1111 | 1165 | } |
1112 | 1166 | |
1113 | | - |
1114 | 1167 | // |
1115 | 1168 | // ************************************* UTILITIES ************************************* |
1116 | 1169 | // |
— | — | @@ -1385,15 +1438,33 @@ |
1386 | 1439 | function startProfiling() { |
1387 | 1440 | $this->startTime = wfTime(); |
1388 | 1441 | } |
| 1442 | + /** |
| 1443 | + * Same as startProfiling, but used for DB access only |
| 1444 | + */ |
| 1445 | + function startDbProfiling() { |
| 1446 | + $this->startDbTime = wfTime(); |
| 1447 | + } |
1389 | 1448 | |
1390 | 1449 | /** |
1391 | | - * Records the running time of the given module since last startProfiling() call. |
| 1450 | + * Records the running time of the given module since last startDbProfiling() call. |
1392 | 1451 | */ |
1393 | 1452 | function endProfiling( $module ) { |
1394 | | - $timeDelta = wfTime() - $this->startTime; |
1395 | | - unset($this->startTime); |
1396 | | - $this->addStatusMessage( $module, array( 'time' => sprintf( "%1.2fms", $timeDelta * 1000.0 ) )); |
| 1453 | + $this->recordProfiling( $module, 'time', $this->startTime ); |
1397 | 1454 | } |
| 1455 | + /** |
| 1456 | + * Same as endProfiling, but used for DB access only |
| 1457 | + */ |
| 1458 | + function endDbProfiling( $module ) { |
| 1459 | + $this->recordProfiling( $module, 'dbtime', $this->startDbTime ); |
| 1460 | + } |
| 1461 | + /** |
| 1462 | + * Helper profiling function |
| 1463 | + */ |
| 1464 | + function recordProfiling( $module, $type, &$start ) { |
| 1465 | + $timeDelta = wfTime() - $start; |
| 1466 | + unset($start); |
| 1467 | + $this->addStatusMessage( $module, array( $type => sprintf( "%1.2fms", $timeDelta * 1000.0 ) )); |
| 1468 | + } |
1398 | 1469 | |
1399 | 1470 | /** |
1400 | 1471 | * Validate the value against the minimum and user/bot maximum limits. Prints usage info on failure. |