154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project/* 254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * you may not use this file except in compliance with the License. 654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * You may obtain a copy of the License at 754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 1054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * See the License for the specific language governing permissions and 1454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * limitations under the License. 1554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 1654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 1754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpackage android.database.sqlite; 1854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 1954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.database.Cursor; 2054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.database.DatabaseUtils; 21a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.CancellationSignal; 22a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.OperationCanceledException; 2354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.provider.BaseColumns; 2454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.text.TextUtils; 2554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.util.Log; 2654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 2754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport java.util.Iterator; 2854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport java.util.Map; 2954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport java.util.Map.Entry; 3050b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmannimport java.util.Set; 31ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Linimport java.util.regex.Pattern; 3254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 3354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project/** 3454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * This is a convience class that helps build SQL queries to be sent to 3554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * {@link SQLiteDatabase} objects. 3654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 3754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpublic class SQLiteQueryBuilder 3854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project{ 3954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private static final String TAG = "SQLiteQueryBuilder"; 40ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin private static final Pattern sLimitPattern = 41ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?"); 4254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 4354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private Map<String, String> mProjectionMap = null; 4454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private String mTables = ""; 45ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick private StringBuilder mWhereClause = null; // lazily created 4654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private boolean mDistinct; 4754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private SQLiteDatabase.CursorFactory mFactory; 4850b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann private boolean mStrict; 4954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 5054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public SQLiteQueryBuilder() { 5154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mDistinct = false; 5254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mFactory = null; 5354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 5454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 5554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 5654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Mark the query as DISTINCT. 5754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 5854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param distinct if true the query is DISTINCT, otherwise it isn't 5954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 6054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void setDistinct(boolean distinct) { 6154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mDistinct = distinct; 6254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 6354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 6454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 6554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Returns the list of tables being queried 6654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 6754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the list of tables being queried 6854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 6954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String getTables() { 7054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return mTables; 7154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 7254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 7354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 7454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Sets the list of tables to query. Multiple tables can be specified to perform a join. 7554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * For example: 7654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * setTables("foo, bar") 7754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * setTables("foo LEFT OUTER JOIN bar ON (foo.id = bar.foo_id)") 7854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 7954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param inTables the list of tables to query on 8054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 8154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void setTables(String inTables) { 8254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mTables = inTables; 8354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 8454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 8554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 8654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Append a chunk to the WHERE clause of the query. All chunks appended are surrounded 8754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * by parenthesis and ANDed with the selection passed to {@link #query}. The final 8854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WHERE clause looks like: 8954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 9054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WHERE (<append chunk 1><append chunk2>) AND (<query() selection parameter>) 9154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 9254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param inWhere the chunk of text to append to the WHERE clause. 9354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 9454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void appendWhere(CharSequence inWhere) { 95ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (mWhereClause == null) { 96ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick mWhereClause = new StringBuilder(inWhere.length() + 16); 97ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick } 9854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (mWhereClause.length() == 0) { 9954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mWhereClause.append('('); 10054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 10154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mWhereClause.append(inWhere); 10254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 10354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 10454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 10554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Append a chunk to the WHERE clause of the query. All chunks appended are surrounded 10654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * by parenthesis and ANDed with the selection passed to {@link #query}. The final 10754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WHERE clause looks like: 10854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 10954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WHERE (<append chunk 1><append chunk2>) AND (<query() selection parameter>) 11054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 11154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param inWhere the chunk of text to append to the WHERE clause. it will be escaped 11254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * to avoid SQL injection attacks 11354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 11454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void appendWhereEscapeString(String inWhere) { 115ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (mWhereClause == null) { 116ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick mWhereClause = new StringBuilder(inWhere.length() + 16); 117ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick } 11854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (mWhereClause.length() == 0) { 11954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mWhereClause.append('('); 12054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 12154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere); 12254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 12354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 12454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 12554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Sets the projection map for the query. The projection map maps 12654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * from column names that the caller passes into query to database 12754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * column names. This is useful for renaming columns as well as 12854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * disambiguating column names when doing joins. For example you 12954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * could map "name" to "people.name". If a projection map is set 13054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * it must contain all column names the user may request, even if 13154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the key and value are the same. 13254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 13354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param columnMap maps from the user column names to the database column names 13454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 13554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void setProjectionMap(Map<String, String> columnMap) { 13654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mProjectionMap = columnMap; 13754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 13854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 13954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 14054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Sets the cursor factory to be used for the query. You can use 14154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * one factory for all queries on a database but it is normally 14275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * easier to specify the factory when doing this query. 14375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * 14475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param factory the factory to use. 14554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 14654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public void setCursorFactory(SQLiteDatabase.CursorFactory factory) { 14754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mFactory = factory; 14854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 14954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 15054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 15150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * When set, the selection is verified against malicious arguments. 15250b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * When using this class to create a statement using 15350b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * {@link #buildQueryString(boolean, String, String[], String, String, String, String, String)}, 15450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * non-numeric limits will raise an exception. If a projection map is specified, fields 15550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * not in that map will be ignored. 15650b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * If this class is used to execute the statement directly using 15750b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * {@link #query(SQLiteDatabase, String[], String, String[], String, String, String)} 15850b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * or 15950b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * {@link #query(SQLiteDatabase, String[], String, String[], String, String, String, String)}, 16050b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * additionally also parenthesis escaping selection are caught. 16150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * 16250b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * To summarize: To get maximum protection against malicious third party apps (for example 16350b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * content provider consumers), make sure to do the following: 16450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * <ul> 16550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * <li>Set this value to true</li> 16650b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * <li>Use a projection map</li> 16750b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * <li>Use one of the query overloads instead of getting the statement as a sql string</li> 16850b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * </ul> 16950b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * By default, this value is false. 17050b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann */ 17150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann public void setStrict(boolean flag) { 17250b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann mStrict = flag; 17340eb4aad2bbf88abe21f5868cc09d49ee1b05bf8Dmitri Plotnikov } 17440eb4aad2bbf88abe21f5868cc09d49ee1b05bf8Dmitri Plotnikov 17540eb4aad2bbf88abe21f5868cc09d49ee1b05bf8Dmitri Plotnikov /** 17654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Build an SQL query string from the given clauses. 17754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 17854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param distinct true if you want each row to be unique, false otherwise. 17954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param tables The table names to compile the query against. 18054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param columns A list of which columns to return. Passing null will 18154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * return all columns, which is discouraged to prevent reading 18254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * data from storage that isn't going to be used. 18354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param where A filter declaring which rows to return, formatted as an SQL 18454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WHERE clause (excluding the WHERE itself). Passing null will 18554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * return all rows for the given URL. 18654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted as an SQL 18754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * GROUP BY clause (excluding the GROUP BY itself). Passing null 18854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will cause the rows to not be grouped. 18954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in the cursor, 19054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * if row grouping is being used, formatted as an SQL HAVING 19154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * clause (excluding the HAVING itself). Passing null will cause 19254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * all row groups to be included, and is required when row 19354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * grouping is not being used. 19454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause 19554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * (excluding the ORDER BY itself). Passing null will use the 19654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * default sort order, which may be unordered. 19754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit Limits the number of rows returned by the query, 19854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 19954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the SQL query string 20054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 20154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public static String buildQueryString( 20254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project boolean distinct, String tables, String[] columns, String where, 20354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String groupBy, String having, String orderBy, String limit) { 20454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (TextUtils.isEmpty(groupBy) && !TextUtils.isEmpty(having)) { 20554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project throw new IllegalArgumentException( 20654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project "HAVING clauses are only permitted when using a groupBy clause"); 20754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 208ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin if (!TextUtils.isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) { 209ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin throw new IllegalArgumentException("invalid LIMIT clauses:" + limit); 210ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin } 21154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 21254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project StringBuilder query = new StringBuilder(120); 21354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 21454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append("SELECT "); 21554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (distinct) { 21654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append("DISTINCT "); 21754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 21854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (columns != null && columns.length != 0) { 21954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendColumns(query, columns); 22054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else { 22154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append("* "); 22254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 22354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append("FROM "); 22454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append(tables); 22554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " WHERE ", where); 22654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " GROUP BY ", groupBy); 22754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " HAVING ", having); 22854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " ORDER BY ", orderBy); 229ab18d1f46a0501f9a54da1ef08ff4967f4b63b68Owen Lin appendClause(query, " LIMIT ", limit); 23054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 23154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return query.toString(); 23254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 23354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 23454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private static void appendClause(StringBuilder s, String name, String clause) { 23554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (!TextUtils.isEmpty(clause)) { 23654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project s.append(name); 23754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project s.append(clause); 23854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 23954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 24054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 24154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 24254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Add the names that are non-null in columns to s, separating 24354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * them with commas. 24454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 24554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public static void appendColumns(StringBuilder s, String[] columns) { 24654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int n = columns.length; 24754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 24854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < n; i++) { 24954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String column = columns[i]; 25054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 25154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (column != null) { 25254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (i > 0) { 25354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project s.append(", "); 25454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 25554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project s.append(column); 25654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 25754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 25854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project s.append(' '); 25954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 26054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 26154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 26254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Perform a query by combining all current settings and the 26354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * information passed into this method. 26454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 26554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param db the database to query on 26654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param projectionIn A list of which columns to return. Passing 26754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will return all columns, which is discouraged to prevent 26854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * reading data from storage that isn't going to be used. 26954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 27054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 27154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given URL. 27254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selectionArgs You may include ?s in selection, which 27354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will be replaced by the values from selectionArgs, in order 27454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * that they appear in the selection. The values will be bound 27554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as Strings. 27654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 27754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY 27854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will cause the rows to not be grouped. 27954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 28054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 28154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 28254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 28354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 28454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 28554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing null 28654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will use the default sort order, which may be unordered. 28754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return a cursor over the result set 28854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @see android.content.ContentResolver#query(android.net.Uri, String[], 28954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * String, String[], String) 29054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 29154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public Cursor query(SQLiteDatabase db, String[] projectionIn, 29254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 29354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String having, String sortOrder) { 29454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder, 2954c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown null /* limit */, null /* cancellationSignal */); 29654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 29754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 29854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 29954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Perform a query by combining all current settings and the 30054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * information passed into this method. 30154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 30254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param db the database to query on 30354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param projectionIn A list of which columns to return. Passing 30454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will return all columns, which is discouraged to prevent 30554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * reading data from storage that isn't going to be used. 30654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 30754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 30854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given URL. 30954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selectionArgs You may include ?s in selection, which 31054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will be replaced by the values from selectionArgs, in order 31154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * that they appear in the selection. The values will be bound 31254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as Strings. 31354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 31454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY 31554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will cause the rows to not be grouped. 31654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 31754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 31854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 31954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 32054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 32154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 32254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing null 32354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will use the default sort order, which may be unordered. 32454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit Limits the number of rows returned by the query, 32554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 32654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return a cursor over the result set 32754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @see android.content.ContentResolver#query(android.net.Uri, String[], 32854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * String, String[], String) 32954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 33054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public Cursor query(SQLiteDatabase db, String[] projectionIn, 33154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String selection, String[] selectionArgs, String groupBy, 33254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String having, String sortOrder, String limit) { 33375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown return query(db, projectionIn, selection, selectionArgs, 33475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown groupBy, having, sortOrder, limit, null); 33575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown } 33675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown 33775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown /** 33875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Perform a query by combining all current settings and the 33975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * information passed into this method. 34075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * 34175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param db the database to query on 34275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param projectionIn A list of which columns to return. Passing 34375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * null will return all columns, which is discouraged to prevent 34475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * reading data from storage that isn't going to be used. 34575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param selection A filter declaring which rows to return, 34675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * formatted as an SQL WHERE clause (excluding the WHERE 34775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * itself). Passing null will return all rows for the given URL. 34875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param selectionArgs You may include ?s in selection, which 34975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * will be replaced by the values from selectionArgs, in order 35075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * that they appear in the selection. The values will be bound 35175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * as Strings. 35275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param groupBy A filter declaring how to group rows, formatted 35375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * as an SQL GROUP BY clause (excluding the GROUP BY 35475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * itself). Passing null will cause the rows to not be grouped. 35575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param having A filter declare which row groups to include in 35675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * the cursor, if row grouping is being used, formatted as an 35775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * SQL HAVING clause (excluding the HAVING itself). Passing 35875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * null will cause all row groups to be included, and is 35975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * required when row grouping is not being used. 36075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param sortOrder How to order the rows, formatted as an SQL 36175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * ORDER BY clause (excluding the ORDER BY itself). Passing null 36275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * will use the default sort order, which may be unordered. 36375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @param limit Limits the number of rows returned by the query, 36475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 3654c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 36675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * If the operation is canceled, then {@link OperationCanceledException} will be thrown 36775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * when the query is executed. 36875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @return a cursor over the result set 36975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * @see android.content.ContentResolver#query(android.net.Uri, String[], 37075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * String, String[], String) 37175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */ 37275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown public Cursor query(SQLiteDatabase db, String[] projectionIn, 37375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown String selection, String[] selectionArgs, String groupBy, 3744c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown String having, String sortOrder, String limit, CancellationSignal cancellationSignal) { 37554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (mTables == null) { 37654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return null; 37754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 37854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 37950b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann if (mStrict && selection != null && selection.length() > 0) { 38050b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // Validate the user-supplied selection to detect syntactic anomalies 38150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // in the selection string that could indicate a SQL injection attempt. 38250b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // The idea is to ensure that the selection clause is a valid SQL expression 38350b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // by compiling it twice: once wrapped in parentheses and once as 38450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // originally specified. An attacker cannot create an expression that 38550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // would escape the SQL expression while maintaining balanced parentheses 38650b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann // in both the wrapped and original forms. 38750b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy, 38850b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann having, sortOrder, limit); 38917aa1b7ac799e308e3724f8c4170620c846dcc09Makoto Onuki db.validateSql(sqlForValidation, cancellationSignal); // will throw if query is invalid 39050b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann } 39150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann 39254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String sql = buildQuery( 39384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger projectionIn, selection, groupBy, having, 39454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project sortOrder, limit); 39554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 39654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 39754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Log.d(TAG, "Performing query: " + sql); 39854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 39954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return db.rawQueryWithFactory( 40054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mFactory, sql, selectionArgs, 40175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown SQLiteDatabase.findEditTable(mTables), 4024c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal); // will throw if query is invalid 40350b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann } 40450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann 40550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann /** 40654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Construct a SELECT statement suitable for use in a group of 40754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SELECT statements that will be joined through UNION operators 40854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * in buildUnionQuery. 40954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 41054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param projectionIn A list of which columns to return. Passing 41154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will return all columns, which is discouraged to 41254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * prevent reading data from storage that isn't going to be 41354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * used. 41454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 41554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 41654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given 41754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * URL. 41854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 41954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY itself). 42054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Passing null will cause the rows to not be grouped. 42154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 42254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 42354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 42454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 42554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 42654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 42754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing null 42854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will use the default sort order, which may be unordered. 42954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit Limits the number of rows returned by the query, 43054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 43154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 43254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 43354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildQuery( 43484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] projectionIn, String selection, String groupBy, 43584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String having, String sortOrder, String limit) { 43654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = computeProjection(projectionIn); 43754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 438accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) StringBuilder where = new StringBuilder(); 439ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick boolean hasBaseWhereClause = mWhereClause != null && mWhereClause.length() > 0; 440accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) 441ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (hasBaseWhereClause) { 442accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(mWhereClause.toString()); 443accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(')'); 44454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 44554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 44654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Tack on the user's selection, if present. 44754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (selection != null && selection.length() > 0) { 448ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (hasBaseWhereClause) { 449accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(" AND "); 45054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 45154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 452accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append('('); 453accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(selection); 454accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(')'); 45554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 45654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 45754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return buildQueryString( 458accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) mDistinct, mTables, projection, where.toString(), 45954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project groupBy, having, sortOrder, limit); 46054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 46154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 46254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 46384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * @deprecated This method's signature is misleading since no SQL parameter 46484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * substitution is carried out. The selection arguments parameter does not get 46584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * used at all. To avoid confusion, call 46684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * {@link #buildQuery(String[], String, String, String, String, String)} instead. 46784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger */ 46884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger @Deprecated 46984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger public String buildQuery( 47084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] projectionIn, String selection, String[] selectionArgs, 47184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String groupBy, String having, String sortOrder, String limit) { 47284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit); 47384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger } 47484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger 47584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger /** 47654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Construct a SELECT statement suitable for use in a group of 47754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SELECT statements that will be joined through UNION operators 47854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * in buildUnionQuery. 47954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 48054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param typeDiscriminatorColumn the name of the result column 48154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * whose cells will contain the name of the table from which 48254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * each row was drawn. 48354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param unionColumns the names of the columns to appear in the 48454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * result. This may include columns that do not appear in the 48554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * table this SELECT is querying (i.e. mTables), but that do 48654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * appear in one of the other tables in the UNION query that we 48754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * are constructing. 48854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param columnsPresentInTable a Set of the names of the columns 48954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * that appear in this table (i.e. in the table whose name is 49054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * mTables). Since columns in unionColumns include columns that 49154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * appear only in other tables, we use this array to distinguish 49254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * which ones actually are present. Other columns will have 49354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * NULL values for results from this subquery. 49454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param computedColumnsOffset all columns in unionColumns before 49554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * this index are included under the assumption that they're 49654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * computed and therefore won't appear in columnsPresentInTable, 49754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * e.g. "date * 1000 as normalized_date" 49854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param typeDiscriminatorValue the value used for the 49954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * type-discriminator column in this subquery 50054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 50154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 50254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given 50354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * URL. 50454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 50554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY itself). 50654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Passing null will cause the rows to not be grouped. 50754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 50854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 50954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 51054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 51154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 51254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 51354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 51454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildUnionSubQuery( 51554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String typeDiscriminatorColumn, 51654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] unionColumns, 51754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Set<String> columnsPresentInTable, 51854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int computedColumnsOffset, 51954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String typeDiscriminatorValue, 52054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String selection, 52154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String groupBy, 52254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String having) { 52354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int unionColumnsCount = unionColumns.length; 52454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projectionIn = new String[unionColumnsCount]; 52554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 52654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < unionColumnsCount; i++) { 52754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String unionColumn = unionColumns[i]; 52854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 52954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (unionColumn.equals(typeDiscriminatorColumn)) { 53054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = "'" + typeDiscriminatorValue + "' AS " 53154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project + typeDiscriminatorColumn; 53254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else if (i <= computedColumnsOffset 53354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project || columnsPresentInTable.contains(unionColumn)) { 53454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = unionColumn; 53554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else { 53654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = "NULL AS " + unionColumn; 53754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 53854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 53954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return buildQuery( 54084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger projectionIn, selection, groupBy, having, 54154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project null /* sortOrder */, 54254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project null /* limit */); 54354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 54454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 54554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 54684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * @deprecated This method's signature is misleading since no SQL parameter 54784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * substitution is carried out. The selection arguments parameter does not get 54884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * used at all. To avoid confusion, call 549f4072fcc14ec44072d31d7beeb4524550bead531Jean-Baptiste Queru * {@link #buildUnionSubQuery} 55084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * instead. 55184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger */ 55284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger @Deprecated 55384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger public String buildUnionSubQuery( 55484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String typeDiscriminatorColumn, 55584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] unionColumns, 55684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger Set<String> columnsPresentInTable, 55784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger int computedColumnsOffset, 55884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String typeDiscriminatorValue, 55984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String selection, 56084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] selectionArgs, 56184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String groupBy, 56284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String having) { 56384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger return buildUnionSubQuery( 56484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger typeDiscriminatorColumn, unionColumns, columnsPresentInTable, 56584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger computedColumnsOffset, typeDiscriminatorValue, selection, 56684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger groupBy, having); 56784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger } 56884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger 56984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger /** 57054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Given a set of subqueries, all of which are SELECT statements, 57154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * construct a query that returns the union of what those 57254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * subqueries return. 57354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param subQueries an array of SQL SELECT statements, all of 57454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * which must have the same columns as the same positions in 57554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * their results 57654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 57754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing 57854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will use the default sort order, which may be unordered. 57954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit The limit clause, which applies to the entire union result set 58054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 58154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 58254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 58354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildUnionQuery(String[] subQueries, String sortOrder, String limit) { 58454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project StringBuilder query = new StringBuilder(128); 58554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int subQueryCount = subQueries.length; 58654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String unionOperator = mDistinct ? " UNION " : " UNION ALL "; 58754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 58854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < subQueryCount; i++) { 58954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (i > 0) { 59054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append(unionOperator); 59154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 59254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append(subQueries[i]); 59354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 59454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " ORDER BY ", sortOrder); 59554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " LIMIT ", limit); 59654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return query.toString(); 59754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 59854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 59954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private String[] computeProjection(String[] projectionIn) { 60054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (projectionIn != null && projectionIn.length > 0) { 60154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (mProjectionMap != null) { 60254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = new String[projectionIn.length]; 60354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int length = projectionIn.length; 60454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 60554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < length; i++) { 60654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String userColumn = projectionIn[i]; 60754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String column = mProjectionMap.get(userColumn); 60854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 60999c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan if (column != null) { 61054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projection[i] = column; 61199c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan continue; 61254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 61399c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan 61450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann if (!mStrict && 61540eb4aad2bbf88abe21f5868cc09d49ee1b05bf8Dmitri Plotnikov ( userColumn.contains(" AS ") || userColumn.contains(" as "))) { 61699c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan /* A column alias already exist */ 61799c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan projection[i] = userColumn; 61899c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan continue; 61999c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan } 62099c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan 62199c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan throw new IllegalArgumentException("Invalid column " 62299c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan + projectionIn[i]); 62354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 62454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projection; 62554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else { 62654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projectionIn; 62754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 62854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else if (mProjectionMap != null) { 62954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Return all columns in projection map. 63054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Set<Entry<String, String>> entrySet = mProjectionMap.entrySet(); 63154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = new String[entrySet.size()]; 63254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Iterator<Entry<String, String>> entryIter = entrySet.iterator(); 63354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int i = 0; 63454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 63554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project while (entryIter.hasNext()) { 63654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Entry<String, String> entry = entryIter.next(); 63754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 63854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Don't include the _count column when people ask for no projection. 63954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (entry.getKey().equals(BaseColumns._COUNT)) { 64054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project continue; 64154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 64254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projection[i++] = entry.getValue(); 64354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 64454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projection; 64554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 64654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return null; 64754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 64854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project} 649