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); 38975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown validateQuerySql(db, sqlForValidation, 3904c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal); // will throw if query is invalid 39150b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann } 39250b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann 39354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String sql = buildQuery( 39484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger projectionIn, selection, groupBy, having, 39554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project sortOrder, limit); 39654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 39754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 39854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Log.d(TAG, "Performing query: " + sql); 39954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 40054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return db.rawQueryWithFactory( 40154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project mFactory, sql, selectionArgs, 40275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown SQLiteDatabase.findEditTable(mTables), 4034c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown cancellationSignal); // will throw if query is invalid 40450b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann } 40550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann 40650b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann /** 407e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown * Verifies that a SQL SELECT statement is valid by compiling it. 40850b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann * If the SQL statement is not valid, this method will throw a {@link SQLiteException}. 40950b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann */ 41075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown private void validateQuerySql(SQLiteDatabase db, String sql, 4114c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown CancellationSignal cancellationSignal) { 412e5360fbf3efe85427f7e7f59afe7bbeddb4949acJeff Brown db.getThreadSession().prepare(sql, 4134c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null); 41454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 41554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 41654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 41754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Construct a SELECT statement suitable for use in a group of 41854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SELECT statements that will be joined through UNION operators 41954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * in buildUnionQuery. 42054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 42154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param projectionIn A list of which columns to return. Passing 42254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will return all columns, which is discouraged to 42354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * prevent reading data from storage that isn't going to be 42454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * used. 42554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 42654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 42754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given 42854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * URL. 42954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 43054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY itself). 43154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Passing null will cause the rows to not be grouped. 43254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 43354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 43454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 43554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 43654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 43754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 43854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing null 43954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * will use the default sort order, which may be unordered. 44054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit Limits the number of rows returned by the query, 44154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as LIMIT clause. Passing null denotes no LIMIT clause. 44254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 44354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 44454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildQuery( 44584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] projectionIn, String selection, String groupBy, 44684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String having, String sortOrder, String limit) { 44754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = computeProjection(projectionIn); 44854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 449accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) StringBuilder where = new StringBuilder(); 450ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick boolean hasBaseWhereClause = mWhereClause != null && mWhereClause.length() > 0; 451accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) 452ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (hasBaseWhereClause) { 453accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(mWhereClause.toString()); 454accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(')'); 45554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 45654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 45754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Tack on the user's selection, if present. 45854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (selection != null && selection.length() > 0) { 459ae6cdd12ac7ded629971206efde331361604d442Brad Fitzpatrick if (hasBaseWhereClause) { 460accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(" AND "); 46154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 46254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 463accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append('('); 464accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(selection); 465accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) where.append(')'); 46654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 46754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 46854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return buildQueryString( 469accbadeb52eda2d972fa6d9f41ebaf9168dc343aYusuke Ohmichi(maimuzo) mDistinct, mTables, projection, where.toString(), 47054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project groupBy, having, sortOrder, limit); 47154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 47254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 47354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 47484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * @deprecated This method's signature is misleading since no SQL parameter 47584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * substitution is carried out. The selection arguments parameter does not get 47684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * used at all. To avoid confusion, call 47784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * {@link #buildQuery(String[], String, String, String, String, String)} instead. 47884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger */ 47984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger @Deprecated 48084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger public String buildQuery( 48184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] projectionIn, String selection, String[] selectionArgs, 48284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String groupBy, String having, String sortOrder, String limit) { 48384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit); 48484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger } 48584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger 48684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger /** 48754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Construct a SELECT statement suitable for use in a group of 48854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SELECT statements that will be joined through UNION operators 48954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * in buildUnionQuery. 49054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 49154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param typeDiscriminatorColumn the name of the result column 49254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * whose cells will contain the name of the table from which 49354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * each row was drawn. 49454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param unionColumns the names of the columns to appear in the 49554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * result. This may include columns that do not appear in the 49654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * table this SELECT is querying (i.e. mTables), but that do 49754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * appear in one of the other tables in the UNION query that we 49854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * are constructing. 49954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param columnsPresentInTable a Set of the names of the columns 50054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * that appear in this table (i.e. in the table whose name is 50154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * mTables). Since columns in unionColumns include columns that 50254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * appear only in other tables, we use this array to distinguish 50354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * which ones actually are present. Other columns will have 50454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * NULL values for results from this subquery. 50554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param computedColumnsOffset all columns in unionColumns before 50654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * this index are included under the assumption that they're 50754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * computed and therefore won't appear in columnsPresentInTable, 50854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * e.g. "date * 1000 as normalized_date" 50954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param typeDiscriminatorValue the value used for the 51054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * type-discriminator column in this subquery 51154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param selection A filter declaring which rows to return, 51254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * formatted as an SQL WHERE clause (excluding the WHERE 51354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * itself). Passing null will return all rows for the given 51454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * URL. 51554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param groupBy A filter declaring how to group rows, formatted 51654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * as an SQL GROUP BY clause (excluding the GROUP BY itself). 51754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Passing null will cause the rows to not be grouped. 51854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param having A filter declare which row groups to include in 51954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * the cursor, if row grouping is being used, formatted as an 52054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * SQL HAVING clause (excluding the HAVING itself). Passing 52154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will cause all row groups to be included, and is 52254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * required when row grouping is not being used. 52354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 52454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 52554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildUnionSubQuery( 52654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String typeDiscriminatorColumn, 52754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] unionColumns, 52854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Set<String> columnsPresentInTable, 52954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int computedColumnsOffset, 53054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String typeDiscriminatorValue, 53154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String selection, 53254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String groupBy, 53354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String having) { 53454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int unionColumnsCount = unionColumns.length; 53554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projectionIn = new String[unionColumnsCount]; 53654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 53754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < unionColumnsCount; i++) { 53854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String unionColumn = unionColumns[i]; 53954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 54054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (unionColumn.equals(typeDiscriminatorColumn)) { 54154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = "'" + typeDiscriminatorValue + "' AS " 54254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project + typeDiscriminatorColumn; 54354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else if (i <= computedColumnsOffset 54454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project || columnsPresentInTable.contains(unionColumn)) { 54554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = unionColumn; 54654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else { 54754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projectionIn[i] = "NULL AS " + unionColumn; 54854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 54954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 55054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return buildQuery( 55184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger projectionIn, selection, groupBy, having, 55254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project null /* sortOrder */, 55354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project null /* limit */); 55454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 55554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 55654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project /** 55784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * @deprecated This method's signature is misleading since no SQL parameter 55884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * substitution is carried out. The selection arguments parameter does not get 55984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * used at all. To avoid confusion, call 560f4072fcc14ec44072d31d7beeb4524550bead531Jean-Baptiste Queru * {@link #buildUnionSubQuery} 56184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger * instead. 56284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger */ 56384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger @Deprecated 56484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger public String buildUnionSubQuery( 56584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String typeDiscriminatorColumn, 56684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] unionColumns, 56784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger Set<String> columnsPresentInTable, 56884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger int computedColumnsOffset, 56984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String typeDiscriminatorValue, 57084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String selection, 57184029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String[] selectionArgs, 57284029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String groupBy, 57384029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger String having) { 57484029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger return buildUnionSubQuery( 57584029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger typeDiscriminatorColumn, unionColumns, columnsPresentInTable, 57684029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger computedColumnsOffset, typeDiscriminatorValue, selection, 57784029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger groupBy, having); 57884029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger } 57984029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger 58084029037239fec6e54327519c3e5ad30088c28ceJonas Schwertfeger /** 58154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Given a set of subqueries, all of which are SELECT statements, 58254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * construct a query that returns the union of what those 58354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * subqueries return. 58454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param subQueries an array of SQL SELECT statements, all of 58554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * which must have the same columns as the same positions in 58654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * their results 58754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param sortOrder How to order the rows, formatted as an SQL 58854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * ORDER BY clause (excluding the ORDER BY itself). Passing 58954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * null will use the default sort order, which may be unordered. 59054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @param limit The limit clause, which applies to the entire union result set 59154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * 59254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @return the resulting SQL SELECT statement 59354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */ 59454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project public String buildUnionQuery(String[] subQueries, String sortOrder, String limit) { 59554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project StringBuilder query = new StringBuilder(128); 59654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int subQueryCount = subQueries.length; 59754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String unionOperator = mDistinct ? " UNION " : " UNION ALL "; 59854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 59954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < subQueryCount; i++) { 60054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (i > 0) { 60154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append(unionOperator); 60254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 60354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project query.append(subQueries[i]); 60454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 60554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " ORDER BY ", sortOrder); 60654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project appendClause(query, " LIMIT ", limit); 60754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return query.toString(); 60854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 60954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 61054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project private String[] computeProjection(String[] projectionIn) { 61154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (projectionIn != null && projectionIn.length > 0) { 61254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (mProjectionMap != null) { 61354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = new String[projectionIn.length]; 61454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int length = projectionIn.length; 61554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 61654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project for (int i = 0; i < length; i++) { 61754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String userColumn = projectionIn[i]; 61854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String column = mProjectionMap.get(userColumn); 61954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 62099c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan if (column != null) { 62154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projection[i] = column; 62299c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan continue; 62354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 62499c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan 62550b1f8d3fc1379339119933e8f567547efb89aa5Daniel Lehmann if (!mStrict && 62640eb4aad2bbf88abe21f5868cc09d49ee1b05bf8Dmitri Plotnikov ( userColumn.contains(" AS ") || userColumn.contains(" as "))) { 62799c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan /* A column alias already exist */ 62899c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan projection[i] = userColumn; 62999c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan continue; 63099c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan } 63199c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan 63299c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan throw new IllegalArgumentException("Invalid column " 63399c4483cd77ff96c5181fda3d6e2fcf2ea50421bMichael Chan + projectionIn[i]); 63454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 63554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projection; 63654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else { 63754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projectionIn; 63854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 63954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } else if (mProjectionMap != null) { 64054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Return all columns in projection map. 64154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Set<Entry<String, String>> entrySet = mProjectionMap.entrySet(); 64254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project String[] projection = new String[entrySet.size()]; 64354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Iterator<Entry<String, String>> entryIter = entrySet.iterator(); 64454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project int i = 0; 64554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 64654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project while (entryIter.hasNext()) { 64754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project Entry<String, String> entry = entryIter.next(); 64854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project 64954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project // Don't include the _count column when people ask for no projection. 65054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project if (entry.getKey().equals(BaseColumns._COUNT)) { 65154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project continue; 65254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 65354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project projection[i++] = entry.getValue(); 65454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 65554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return projection; 65654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 65754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project return null; 65854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project } 65954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project} 660