SQLiteDebug.java revision 4dd4ab4cc322e82401f380aeb877daa4a20d7069
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.database.sqlite;
18
19import android.util.Log;
20
21/**
22 * Provides debugging info about all SQLite databases running in the current process.
23 *
24 * {@hide}
25 */
26public final class SQLiteDebug {
27    /**
28     * Controls the printing of SQL statements as they are executed.
29     */
30    public static final boolean DEBUG_SQL_STATEMENTS =
31            Log.isLoggable("SQLiteStatements", Log.VERBOSE);
32
33    /**
34     * Controls the printing of compiled-sql-statement cache stats.
35     */
36    public static final boolean DEBUG_SQL_CACHE =
37            Log.isLoggable("SQLiteCompiledSql", Log.VERBOSE);
38
39    /**
40     * Controls the capturing and printing of complete sql statement including the bind args and
41     * the database name.
42     */
43    public static final boolean DEBUG_CAPTURE_SQL =
44            Log.isLoggable("SQLiteCaptureSql", Log.VERBOSE);
45
46    /**
47     * Controls the stack trace reporting of active cursors being
48     * finalized.
49     */
50    public static final boolean DEBUG_ACTIVE_CURSOR_FINALIZATION =
51            Log.isLoggable("SQLiteCursorClosing", Log.VERBOSE);
52
53    /**
54     * Controls the tracking of time spent holding the database lock.
55     */
56    public static final boolean DEBUG_LOCK_TIME_TRACKING =
57            Log.isLoggable("SQLiteLockTime", Log.VERBOSE);
58
59    /**
60     * Controls the printing of stack traces when tracking the time spent holding the database lock.
61     */
62    public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE =
63            Log.isLoggable("SQLiteLockStackTrace", Log.VERBOSE);
64
65    /**
66     * Contains statistics about the active pagers in the current process.
67     *
68     * @see #getPagerStats(PagerStats)
69     */
70    public static class PagerStats {
71        /** The total number of bytes in all pagers in the current process */
72        public long totalBytes;
73        /** The number of bytes in referenced pages in all pagers in the current process */
74        public long referencedBytes;
75        /** The number of bytes in all database files opened in the current process */
76        public long databaseBytes;
77        /** The number of pagers opened in the current process */
78        public int numPagers;
79    }
80
81    /**
82     * Gathers statistics about all pagers in the current process.
83     */
84    public static native void getPagerStats(PagerStats stats);
85
86    /**
87     * Returns the size of the SQLite heap.
88     * @return The size of the SQLite heap in bytes.
89     */
90    public static native long getHeapSize();
91
92    /**
93     * Returns the amount of allocated memory in the SQLite heap.
94     * @return The allocated size in bytes.
95     */
96    public static native long getHeapAllocatedSize();
97
98    /**
99     * Returns the amount of free memory in the SQLite heap.
100     * @return The freed size in bytes.
101     */
102    public static native long getHeapFreeSize();
103
104    /**
105     * Determines the number of dirty belonging to the SQLite
106     * heap segments of this process.  pages[0] returns the number of
107     * shared pages, pages[1] returns the number of private pages
108     */
109    public static native void getHeapDirtyPages(int[] pages);
110
111    private static int sNumActiveCursorsFinalized = 0;
112
113    /**
114     * Returns the number of active cursors that have been finalized. This depends on the GC having
115     * run but is still useful for tests.
116     */
117    public static int getNumActiveCursorsFinalized() {
118        return sNumActiveCursorsFinalized;
119    }
120
121    static synchronized void notifyActiveCursorFinalized() {
122        sNumActiveCursorsFinalized++;
123    }
124
125    /**
126     * returns a  message containing the given database name (path) and the string built by
127     * replacing "?" characters in the given sql string with the corresponding
128     * positional values from the given param bindArgs.
129     *
130     * @param path the database name
131     * @param sql sql string with possibly "?" for bindargs
132     * @param bindArgs args for "?"s in the above string
133     * @return the String to be logged
134     */
135    /* package */ static String captureSql(String path, String sql, Object[] bindArgs) {
136        // how many bindargs in sql
137        sql = sql.trim();
138        String args[] = sql.split("\\?");
139        // how many "?"s in the given sql string?
140        int varArgsInSql = (sql.endsWith("?")) ? args.length : args.length - 1;
141
142        // how many bind args do we have in the given input param bindArgs
143        int bindArgsLen = (bindArgs == null) ? 0 : bindArgs.length;
144        if (varArgsInSql < bindArgsLen) {
145            return "too many bindArgs provided. " +
146                    "# of bindArgs = " + bindArgsLen + ", # of varargs = " + varArgsInSql +
147                    "; sql = " + sql;
148        }
149
150        // if there are no bindArgs, we are done. log the sql as is.
151        if (bindArgsLen == 0 && varArgsInSql == 0) {
152            return logSql(path, sql);
153        }
154
155        StringBuilder buf = new StringBuilder();
156
157        // take the supplied bindArgs and plug them into sql
158        for (int i = 0; i < bindArgsLen; i++) {
159            buf.append(args[i]);
160            buf.append(bindArgs[i]);
161        }
162
163        // does given sql have more varArgs than the supplied bindArgs
164        // if so, assign nulls to the extra varArgs in sql
165        for (int i = bindArgsLen; i < varArgsInSql; i ++) {
166            buf.append(args[i]);
167            buf.append("null");
168        }
169
170        // if there are any characters left in the given sql string AFTER the last "?"
171        // log them also. for example, if the given sql = "select * from test where a=? and b=1
172        // then the following code appends " and b=1" string to buf.
173        if (varArgsInSql < args.length) {
174            buf.append(args[varArgsInSql]);
175        }
176        return logSql(path, buf.toString());
177    }
178
179    private static String logSql(String path, String sql) {
180        return "captured_sql|" + path + "|" + sql + ";";
181    }
182}
183