Skip to content

Commit

Permalink
Merge "Speed up query for group tab" into ics-mr1
Browse files Browse the repository at this point in the history
  • Loading branch information
Makoto Onuki authored and Android (Google) Code Review committed Oct 27, 2011
2 parents db09128 + 23ba865 commit a2535f3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
20 changes: 20 additions & 0 deletions src/com/android/providers/contacts/ContactsDatabaseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,26 @@ public interface Tables {
+ "view_raw_contacts._id)";
}

public interface Joins {
/**
* Join string intended to be used with the GROUPS table/view. The main table must be named
* as "groups".
*
* Adds the "group_member_count column" to the query, which will be null if a group has
* no members. Use ifnull(group_member_count, 0) if 0 is needed instead.
*/
public static final String GROUP_MEMBER_COUNT =
" LEFT OUTER JOIN (SELECT "
+ "data.data1 AS member_count_group_id, "
+ "COUNT(data.raw_contact_id) AS group_member_count "
+ "FROM data "
+ "WHERE "
+ "data.mimetype_id = (SELECT _id FROM mimetypes WHERE "
+ "mimetypes.mimetype = '" + GroupMembership.CONTENT_ITEM_TYPE + "')"
+ "GROUP BY member_count_group_id) AS member_count_table" // End of inner query
+ " ON (groups._id = member_count_table.member_count_group_id)";
}

public interface Views {
public static final String DATA = "view_data";
public static final String RAW_CONTACTS = "view_raw_contacts";
Expand Down
31 changes: 25 additions & 6 deletions src/com/android/providers/contacts/ContactsProvider2.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.DataUsageStatColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.Joins;
import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
Expand Down Expand Up @@ -868,13 +869,16 @@ interface RawContactsQuery {
.add(Groups.SYNC4)
.build();

/** Contains {@link Groups} columns along with summary details */
/**
* Contains {@link Groups} columns along with summary details.
*
* Note {@link Groups#SUMMARY_COUNT} doesn't exist in groups/view_groups.
* When we detect this column being requested, we join {@link Joins#GROUP_MEMBER_COUNT} to
* generate it.
*/
private static final ProjectionMap sGroupsSummaryProjectionMap = ProjectionMap.builder()
.addAll(sGroupsProjectionMap)
.add(Groups.SUMMARY_COUNT,
"(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM "
+ Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP
+ ")")
.add(Groups.SUMMARY_COUNT, "ifnull(group_member_count, 0)")
.add(Groups.SUMMARY_WITH_PHONES,
"(SELECT COUNT(" + ContactsColumns.CONCRETE_ID + ") FROM "
+ Tables.CONTACTS_JOIN_RAW_CONTACTS_DATA_FILTERED_BY_GROUPMEMBERSHIP
Expand Down Expand Up @@ -4955,6 +4959,17 @@ public void resetDirectoryCache() {
}
}

private boolean hasColumn(String[] projection, String column) {
if (projection == null) {
return true; // Null projection means "all columns".
}

for (int i = 0; i < projection.length; i++) {
if (column.equalsIgnoreCase(projection[i])) return true;
}
return false;
}

protected Cursor queryLocal(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder, long directoryId) {
if (VERBOSE_LOGGING) {
Expand Down Expand Up @@ -5712,7 +5727,11 @@ protected Cursor queryLocal(Uri uri, String[] projection, String selection,
final boolean returnGroupCountPerAccount =
readBooleanQueryParameter(uri, Groups.PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT,
false);
qb.setTables(Views.GROUPS + " AS " + Tables.GROUPS);
String tables = Views.GROUPS + " AS " + Tables.GROUPS;
if (hasColumn(projection, Groups.SUMMARY_COUNT)) {
tables = tables + Joins.GROUP_MEMBER_COUNT;
}
qb.setTables(tables);
qb.setProjectionMap(returnGroupCountPerAccount ?
sGroupsSummaryProjectionMapWithGroupCountPerAccount
: sGroupsSummaryProjectionMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -918,9 +918,14 @@ protected void assertStoredValues(Uri rowUri, String selection, String[] selecti
}

protected void assertStoredValuesWithProjection(Uri rowUri, ContentValues expectedValues) {
Cursor c = mResolver.query(rowUri, buildProjection(expectedValues), null, null, null);
assertStoredValuesWithProjection(rowUri, new ContentValues[] {expectedValues});
}

protected void assertStoredValuesWithProjection(Uri rowUri, ContentValues[] expectedValues) {
assertTrue("Need at least one ContentValues for this test", expectedValues.length > 0);
Cursor c = mResolver.query(rowUri, buildProjection(expectedValues[0]), null, null, null);
try {
assertEquals("Record count", 1, c.getCount());
assertEquals("Record count", expectedValues.length, c.getCount());
c.moveToFirst();
assertCursorValues(c, expectedValues);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@
*
* Run the test like this:
* <code>
* adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \
* com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \
com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
* </code>
*/
@LargeTest
Expand Down Expand Up @@ -2190,6 +2190,18 @@ public void testGroupSummaryQuery() {
v4.put(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT,
v1.getAsInteger(Groups.SUMMARY_GROUP_COUNT_PER_ACCOUNT));
assertStoredValues(uri, new ContentValues[] { v1, v2, v3, v4 });

// We change the tables dynamically according to the requested projection.
// Make sure the SUMMARY_COUNT column exists
v1.clear();
v1.put(Groups.SUMMARY_COUNT, 2);
v2.clear();
v2.put(Groups.SUMMARY_COUNT, 1);
v3.clear();
v3.put(Groups.SUMMARY_COUNT, 0);
v4.clear();
v4.put(Groups.SUMMARY_COUNT, 0);
assertStoredValuesWithProjection(uri, new ContentValues[] { v1, v2, v3, v4 });
}

public void testSettingsQuery() {
Expand Down

0 comments on commit a2535f3

Please sign in to comment.