Index: src/wp-includes/link-template.php
===================================================================
--- src/wp-includes/link-template.php	(revision 27232)
+++ src/wp-includes/link-template.php	(working copy)
@@ -1136,20 +1136,20 @@
 	$current_post_date = $post->post_date;
 
 	$join = '';
-	$posts_in_ex_terms_sql = '';
+	$same_terms_or_exclude_where = '';
 	if ( $in_same_term || ! empty( $excluded_terms ) ) {
 		$join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
 
 		if ( $in_same_term ) {
 			if ( ! is_object_in_taxonomy( $post->post_type, $taxonomy ) )
 				return '';
-			$term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
-			if ( ! $term_array || is_wp_error( $term_array ) )
+			$same_term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
+			if ( ! $same_term_array || is_wp_error( $same_term_array ) )
 				return '';
-			$join .= $wpdb->prepare( " AND tt.taxonomy = %s AND tt.term_id IN (" . implode( ',', array_map( 'intval', $term_array ) ) . ")", $taxonomy );
+		} else {
+			$same_term_array = array();
 		}
 
-		$posts_in_ex_terms_sql = $wpdb->prepare( "AND tt.taxonomy = %s", $taxonomy );
 		if ( ! empty( $excluded_terms ) ) {
 			if ( ! is_array( $excluded_terms ) ) {
 				// back-compat, $excluded_terms used to be $excluded_terms with IDs separated by " and "
@@ -1162,15 +1162,23 @@
 			}
 
 			$excluded_terms = array_map( 'intval', $excluded_terms );
+		} else {
+			$excluded_terms = array();
+		}
 
-			if ( ! empty( $term_array ) ) {
-				$excluded_terms = array_diff( $excluded_terms, $term_array );
-				$posts_in_ex_terms_sql = '';
+		if ( ! empty( $same_term_array ) || ! empty ( $excluded_terms ) ) {
+			$same_term_array = array_diff( $same_term_array, $excluded_terms );
+			if ( !empty ( $same_term_array ) ) {
+				// if there are still same terms, we can assume that all $excluded_terms
+				// have been removed from them. therefore, since AND is exclusive,
+				// we don't need to worry about the remaining excluded terms and 
+				// can do IN
+				$same_terms_or_exclude_where = $wpdb->prepare( " AND tt.taxonomy = %s AND tt.term_id IN (" . implode( ',', array_map( 'intval', $same_term_array ) ) . ")", $taxonomy );
+			} else if ( ! empty ( $excluded_terms ) ) {
+				// if there are no same terms, but there are excluded terms,
+				// we need to do a NOT IN
+				$same_terms_or_exclude_where = $wpdb->prepare( " AND tt.taxonomy = %s AND tt.term_id NOT IN (" . implode( $excluded_terms, ',' ) . ')', $taxonomy );
 			}
-
-			if ( ! empty( $excluded_terms ) ) {
-				$posts_in_ex_terms_sql = $wpdb->prepare( " AND tt.taxonomy = %s AND tt.term_id NOT IN (" . implode( $excluded_terms, ',' ) . ')', $taxonomy );
-			}
 		}
 	}
 
@@ -1179,7 +1187,7 @@
 	$order = $previous ? 'DESC' : 'ASC';
 
 	$join  = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_term, $excluded_terms );
-	$where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare( "WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_terms_sql", $current_post_date, $post->post_type), $in_same_term, $excluded_terms );
+	$where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare( "WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $same_terms_or_exclude_where", $current_post_date, $post->post_type), $in_same_term, $excluded_terms );
 	$sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
 
 	$query = "SELECT p.ID FROM $wpdb->posts AS p $join $where $sort";
Index: tests/phpunit/tests/link.php
===================================================================
--- tests/phpunit/tests/link.php	(revision 27232)
+++ tests/phpunit/tests/link.php	(working copy)
@@ -167,4 +167,64 @@
 		$this->assertEquals( array( $post_two ), get_boundary_post( true, '', true, 'post_tag' ) );
 		$this->assertEquals( array( $post_four ), get_boundary_post( true, '', false, 'post_tag' ) );
 	}
+
+	/**
+	* @ticket 22112
+	*/
+	function test_get_adjacent_post_exclude_self_term() {
+		// Need some sample posts to test adjacency when looking at the
+		// next post
+		$post_one = $this->factory->post->create_and_get( array(
+			'post_title' => 'First',
+			'post_date' => '2012-01-01 12:00:00'
+		) );
+
+		$post_two = $this->factory->post->create_and_get( array(
+			'post_title' => 'Second',
+			'post_date' => '2012-02-01 12:00:00'
+		) );
+
+		$post_three = $this->factory->post->create_and_get( array(
+			'post_title' => 'Third',
+			'post_date' => '2012-03-01 12:00:00'
+		) );
+
+		// Assign some terms
+		wp_set_object_terms( $post_one->ID, 'good', 'category', false );
+		wp_set_object_terms( $post_one->ID, 'bad', 'category', false );
+
+		wp_set_object_terms( $post_two->ID, 'bad', 'category', false );
+
+		wp_set_object_terms( $post_three->ID, 'good', 'category', false );
+
+		$exclude_term = get_term_by('name', 'bad', 'category');
+
+		// Test that if the next post has the same term *and* is in the
+		// has a term in the excluded_terms array, it is skipped
+		$this->go_to( get_permalink( $post_one->ID ) );
+		$this->assertEquals( $post_three, get_adjacent_post( true, "$exclude_term->term_id", false ) );
+
+
+		// Need some sample posts to test adjacency when looking at the
+		// previous post
+		$post_four = $this->factory->post->create_and_get( array(
+			'post_title' => 'Fourth',
+			'post_date' => '2012-04-01 12:00:00'
+		) );
+
+		$post_five = $this->factory->post->create_and_get( array(
+			'post_title' => 'Fifth',
+			'post_date' => '2012-05-01 12:00:00'
+		) );
+
+		wp_set_object_terms( $post_four->ID, 'bad', 'category', false );
+
+		wp_set_object_terms( $post_five->ID, 'good', 'category', false );
+		wp_set_object_terms( $post_five->ID, 'bad', 'category', false );
+
+		// Test that if the previous post has the same term *and* is in the
+		// has a term in the excluded_terms array, it is skipped
+		$this->go_to( get_permalink( $post_five->ID ) );
+		$this->assertEquals( $post_three, get_adjacent_post( true, "$exclude_term->term_id", true ) );
+	}
 }
\ No newline at end of file
