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