• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 
17 package android.database.sqlite;
18 
19 import android.os.StrictMode;
20 import android.util.Log;
21 
22 /**
23  * This class encapsulates compilation of sql statement and release of the compiled statement obj.
24  * Once a sql statement is compiled, it is cached in {@link SQLiteDatabase}
25  * and it is released in one of the 2 following ways
26  * 1. when {@link SQLiteDatabase} object is closed.
27  * 2. if this is not cached in {@link SQLiteDatabase}, {@link android.database.Cursor#close()}
28  * releaases this obj.
29  */
30 /* package */ class SQLiteCompiledSql {
31 
32     private static final String TAG = "SQLiteCompiledSql";
33 
34     /** The database this program is compiled against. */
35     /* package */ final SQLiteDatabase mDatabase;
36 
37     /**
38      * Native linkage, do not modify. This comes from the database.
39      */
40     /* package */ final int nHandle;
41 
42     /**
43      * Native linkage, do not modify. When non-0 this holds a reference to a valid
44      * sqlite3_statement object. It is only updated by the native code, but may be
45      * checked in this class when the database lock is held to determine if there
46      * is a valid native-side program or not.
47      */
48     /* package */ int nStatement = 0;
49 
50     /** the following are for debugging purposes */
51     private String mSqlStmt = null;
52     private Throwable mStackTrace = null;
53 
54     /** when in cache and is in use, this member is set */
55     private boolean mInUse = false;
56 
SQLiteCompiledSql(SQLiteDatabase db, String sql)57     /* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
58         db.verifyDbIsOpen();
59         db.verifyLockOwner();
60         mDatabase = db;
61         mSqlStmt = sql;
62         mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
63         nHandle = db.mNativeHandle;
64         native_compile(sql);
65     }
66 
releaseSqlStatement()67     /* package */ void releaseSqlStatement() {
68         // Note that native_finalize() checks to make sure that nStatement is
69         // non-null before destroying it.
70         if (nStatement != 0) {
71             mDatabase.finalizeStatementLater(nStatement);
72             nStatement = 0;
73         }
74     }
75 
76     /**
77      * returns true if acquire() succeeds. false otherwise.
78      */
acquire()79     /* package */ synchronized boolean acquire() {
80         if (mInUse) {
81             // it is already in use.
82             return false;
83         }
84         mInUse = true;
85         return true;
86     }
87 
release()88     /* package */ synchronized void release() {
89         mInUse = false;
90     }
91 
releaseIfNotInUse()92     /* package */ synchronized void releaseIfNotInUse() {
93         // if it is not in use, release its memory from the database
94         if (!mInUse) {
95             releaseSqlStatement();
96         }
97     }
98 
99     /**
100      * Make sure that the native resource is cleaned up.
101      */
102     @Override
finalize()103     protected void finalize() throws Throwable {
104         try {
105             if (nStatement == 0) return;
106             // don't worry about finalizing this object if it is ALREADY in the
107             // queue of statements to be finalized later
108             if (mDatabase.isInQueueOfStatementsToBeFinalized(nStatement)) {
109                 return;
110             }
111             // finalizer should NEVER get called
112             // but if the database itself is not closed and is GC'ed, then
113             // all sub-objects attached to the database could end up getting GC'ed too.
114             // in that case, don't print any warning.
115             if (mInUse && StrictMode.vmSqliteObjectLeaksEnabled()) {
116                 int len = mSqlStmt.length();
117                 StrictMode.onSqliteObjectLeaked(
118                     "Releasing statement in a finalizer. Please ensure " +
119                     "that you explicitly call close() on your cursor: " +
120                     mSqlStmt.substring(0, (len > 1000) ? 1000 : len),
121                     mStackTrace);
122             }
123             releaseSqlStatement();
124         } finally {
125             super.finalize();
126         }
127     }
128 
toString()129     @Override public String toString() {
130         synchronized(this) {
131             StringBuilder buff = new StringBuilder();
132             buff.append(" nStatement=");
133             buff.append(nStatement);
134             buff.append(", mInUse=");
135             buff.append(mInUse);
136             buff.append(", db=");
137             buff.append(mDatabase.getPath());
138             buff.append(", db_connectionNum=");
139             buff.append(mDatabase.mConnectionNum);
140             buff.append(", sql=");
141             int len = mSqlStmt.length();
142             buff.append(mSqlStmt.substring(0, (len > 100) ? 100 : len));
143             return buff.toString();
144         }
145     }
146 
147     /**
148      * Compiles SQL into a SQLite program.
149      *
150      * <P>The database lock must be held when calling this method.
151      * @param sql The SQL to compile.
152      */
native_compile(String sql)153     private final native void native_compile(String sql);
154 }
155