19d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki/* 29d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Copyright (C) 2016 The Android Open Source Project 39d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * 49d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 59d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * you may not use this file except in compliance with the License. 69d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * You may obtain a copy of the License at 79d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * 89d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 99d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * 109d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Unless required by applicable law or agreed to in writing, software 119d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 129d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * See the License for the specific language governing permissions and 149d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * limitations under the License 159d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki */ 169d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 179d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukipackage com.android.providers.contacts.sqlite; 189d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 199d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport android.database.Cursor; 209d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport android.database.sqlite.SQLiteDatabase; 219d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport android.util.Log; 229d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 239d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport com.android.providers.contacts.AbstractContactsProvider; 249d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 258411b174dee903acf8f7d16a8f46da2a7265f1abMakoto Onukiimport com.google.common.annotations.VisibleForTesting; 268411b174dee903acf8f7d16a8f46da2a7265f1abMakoto Onuki 279d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport java.util.ArrayList; 289d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukiimport java.util.List; 299d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 309d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki/** 319d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Class to extract table/view/column names from databases. 329d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki */ 338411b174dee903acf8f7d16a8f46da2a7265f1abMakoto Onuki@VisibleForTesting 349d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onukipublic class DatabaseAnalyzer { 359d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki private static final String TAG = "DatabaseAnalyzer"; 369d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 379d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki private static final boolean VERBOSE_LOGGING = AbstractContactsProvider.VERBOSE_LOGGING; 389d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 399d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki private DatabaseAnalyzer() { 409d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 419d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 429d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki /** 439d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Find and return all table/view names in a db. 449d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki */ 459d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki private static List<String> findTablesAndViews(SQLiteDatabase db) { 469d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final List<String> ret = new ArrayList<>(); 479d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki try (final Cursor c = db.rawQuery( 489d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki "SELECT name FROM sqlite_master WHERE type in (\"table\", \"view\")", null)) { 499d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki while (c.moveToNext()) { 5079e61b15a11698197da4bb78cd1be469a38b9c35Makoto Onuki ret.add(c.getString(0).toLowerCase()); 519d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 529d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 539d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki return ret; 549d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 559d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 569d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki /** 579d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Find all columns in a table/view. 589d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki */ 599d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki private static List<String> findColumns(SQLiteDatabase db, String table) { 609d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final List<String> ret = new ArrayList<>(); 619d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 629d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki // Open the table/view but requests 0 rows. 639d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final Cursor c = db.rawQuery("SELECT * FROM " + table + " WHERE 0 LIMIT 0", null); 649d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki try { 659d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki // Collect the column names. 669d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki for (int i = 0; i < c.getColumnCount(); i++) { 6779e61b15a11698197da4bb78cd1be469a38b9c35Makoto Onuki ret.add(c.getColumnName(i).toLowerCase()); 689d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 699d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } finally { 709d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki c.close(); 719d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 729d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki return ret; 739d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 749d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki 759d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki /** 769d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * Return all table/view names that clients shouldn't use in their queries -- basically the 779d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * result contains all table/view names, except for the names that are column names of any 789d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki * tables. 799d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki */ 808411b174dee903acf8f7d16a8f46da2a7265f1abMakoto Onuki @VisibleForTesting 819d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki public static List<String> findTableViewsAllowingColumns(SQLiteDatabase db) { 829d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final List<String> tables = findTablesAndViews(db); 839d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki if (VERBOSE_LOGGING) { 849d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki Log.d(TAG, "Tables and views:"); 859d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 869d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final List<String> ret = new ArrayList<>(tables); // Start with the table/view list. 879d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki for (String name : tables) { 889d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki if (VERBOSE_LOGGING) { 899d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki Log.d(TAG, " " + name); 909d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 919d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki final List<String> columns = findColumns(db, name); 929d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki if (VERBOSE_LOGGING) { 939d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki Log.d(TAG, " Columns: " + columns); 949d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 959d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki for (String c : columns) { 969d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki if (ret.remove(c)) { 979d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki Log.d(TAG, "Removing [" + c + "] from disallow list"); 989d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 999d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 1009d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 1019d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki return ret; 1029d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki } 1039d70f53e0d2eda1356af27b2a083c96257ff872eMakoto Onuki} 104