Index: wp-includes/comment.php
===================================================================
--- wp-includes/comment.php	(revision 9571)
+++ wp-includes/comment.php	(working copy)
@@ -180,7 +180,7 @@
 function get_comments( $args = '' ) {
 	global $wpdb;
 
-	$defaults = array('status' => '', 'orderby' => 'comment_date_gmt', 'order' => 'DESC', 'number' => '', 'offset' => '', 'post_id' => 0);
+	$defaults = array('status' => '', 'orderby' => 'comment_date_gmt', 'order' => 'DESC', 'number' => '', 'offset' => '', 'post_id' => 0, 'paged' => FALSE, 'page' => 1, 'comments_per_page' => get_option( 'comments_per_page' ), 'threaded' => FALSE, 'child_of' => 0, $passed_comments = NULL );
 
 	$args = wp_parse_args( $args, $defaults );
 	extract( $args, EXTR_SKIP );
@@ -198,8 +198,22 @@
 		return $cache;
 	}
 
-	$post_id = absint($post_id);
+	$post_id = absint( $post_id );
+	$page = absint( $page );
+	$comments_per_page = absint( $comments_per_page );
 
+	if ( is_string( $child_of) || is_int( $child_of ) )
+		$child_of = explode( ',', $child_of );
+
+	if ( is_array( $child_of ) ) {
+		$_child_of = array();
+		foreach ( (array) $child_of as $_child )
+			$_child_of[] = absint( trim( $_child, " '" ) );
+		$child_of = implode( ',', $_child_of );
+	} else {
+		$child_of = 0;
+	}
+
 	if ( 'hold' == $status )
 		$approved = "comment_approved = '0'";
 	elseif ( 'approve' == $status )
@@ -209,14 +223,27 @@
 	else
 		$approved = "( comment_approved = '0' OR comment_approved = '1' )";
 
-	$order = ( 'ASC' == $order ) ? 'ASC' : 'DESC';
+	$order = ( 'ASC' == strtoupper( $order ) ) ? 'ASC' : 'DESC';
 
 	$orderby = 'comment_date_gmt';  // Hard code for now
 
 	$number = absint($number);
 	$offset = absint($offset);
 
-	if ( !empty($number) ) {
+	$threaded_where = '';
+
+	if ( $paged && $post_id && !$threaded ) {
+		$number = 'LIMIT ' . ( $page - 1 ) * $comments_per_page . ',' . $comments_per_page;
+	} elseif ( $paged && $post_id ) {
+		if ( ( $comments_per_page * 2 ) >= get_comment_count( $post_id ) ) { // just query them all
+			$threaded = false; // we'll get them all in one query, so cancel any recursive queries
+			$number = '';
+		} elseif ( 0 == $child_of ) { // first level of recursion
+			$threaded_where = 'comment_parent = 0 AND ';
+		} else { // further level of recursion
+			$threaded_where = "comment_parent IN( $child_of ) AND ";
+		}
+	} elseif ( !empty($number) ) {
 		if ( $offset )
 			$number = 'LIMIT ' . $offset . ',' . $number;
 		else
@@ -227,13 +254,33 @@
 	}
 
 	if ( ! empty($post_id) )
-		$post_where = "comment_post_ID = $post_id AND";
+		$post_where = $wpdb->prepare( 'comment_post_ID = %d AND', $post_id );
 	else
 		$post_where = '';
 
-	$comments = $wpdb->get_results( "SELECT * FROM $wpdb->comments WHERE $post_where $approved ORDER BY $orderby $order $number" );
-	wp_cache_add( $cache_key, $comments, 'comment' );
+	$comments = $wpdb->get_results( "SELECT * FROM $wpdb->comments WHERE $threaded_where $post_where $approved ORDER BY $orderby $order $number" );
 
+	if ( $threaded && $paged ) {
+		if ( count( $comments ) ) { // have to recurse
+			if ( count( $passed_comments ) )
+				$passed_comments = array_merge( (array) $passed_comments, (array) $comments );
+			else
+				$passed_comments = $comments;
+			$_new_ids = array();
+			foreach ( (array) $comments as $_c )
+				$_new_ids[] = $_c->comment_ID;
+			$_args = compact( 'status', 'orderby', 'order', 'number', 'offset', 'post_id', 'paged', 'page', 'comments_per_page', 'threaded', 'passed_comments');
+			$_args['child_of'] = $_new_ids;
+			$comments = get_comments( $_args );
+		} else { // found them all!
+			$comments = $passed_comments;
+		}
+	}
+
+	// we only add to the cache when we've gathered the full comment tree
+	if ( ! ( $threaded && $paged && $child_of != 0 ) )
+		wp_cache_add( $cache_key, $comments, 'comment' );
+
 	return $comments;
 }
 
