1 /* 2 * Copyright (C) 2006 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.util.Log; 20 21 /** 22 * A base class for compiled SQLite programs. 23 */ 24 public abstract class SQLiteProgram extends SQLiteClosable { 25 private static final String TAG = "SQLiteProgram"; 26 27 /** The database this program is compiled against. */ 28 protected SQLiteDatabase mDatabase; 29 30 /** 31 * Native linkage, do not modify. This comes from the database and should not be modified 32 * in here or in the native code. 33 */ 34 protected int nHandle = 0; 35 36 /** 37 * Native linkage, do not modify. When non-0 this holds a reference to a valid 38 * sqlite3_statement object. It is only updated by the native code, but may be 39 * checked in this class when the database lock is held to determine if there 40 * is a valid native-side program or not. 41 */ 42 protected int nStatement = 0; 43 44 /** 45 * Used to find out where a cursor was allocated in case it never got 46 * released. 47 */ 48 private StackTraceElement[] mStackTraceElements; 49 SQLiteProgram(SQLiteDatabase db, String sql)50 /* package */ SQLiteProgram(SQLiteDatabase db, String sql) { 51 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 52 mStackTraceElements = new Exception().getStackTrace(); 53 } 54 55 mDatabase = db; 56 db.acquireReference(); 57 db.addSQLiteClosable(this); 58 this.nHandle = db.mNativeHandle; 59 compile(sql, false); 60 } 61 62 @Override onAllReferencesReleased()63 protected void onAllReferencesReleased() { 64 // Note that native_finalize() checks to make sure that nStatement is 65 // non-null before destroying it. 66 native_finalize(); 67 mDatabase.releaseReference(); 68 mDatabase.removeSQLiteClosable(this); 69 } 70 71 @Override onAllReferencesReleasedFromContainer()72 protected void onAllReferencesReleasedFromContainer(){ 73 // Note that native_finalize() checks to make sure that nStatement is 74 // non-null before destroying it. 75 native_finalize(); 76 mDatabase.releaseReference(); 77 } 78 79 /** 80 * Returns a unique identifier for this program. 81 * 82 * @return a unique identifier for this program 83 */ getUniqueId()84 public final int getUniqueId() { 85 return nStatement; 86 } 87 88 /** 89 * Compiles the given SQL into a SQLite byte code program using sqlite3_prepare_v2(). If 90 * this method has been called previously without a call to close and forCompilation is set 91 * to false the previous compilation will be used. Setting forceCompilation to true will 92 * always re-compile the program and should be done if you pass differing SQL strings to this 93 * method. 94 * 95 * <P>Note: this method acquires the database lock.</P> 96 * 97 * @param sql the SQL string to compile 98 * @param forceCompilation forces the SQL to be recompiled in the event that there is an 99 * existing compiled SQL program already around 100 */ compile(String sql, boolean forceCompilation)101 protected void compile(String sql, boolean forceCompilation) { 102 // Only compile if we don't have a valid statement already or the caller has 103 // explicitly requested a recompile. 104 if (nStatement == 0 || forceCompilation) { 105 mDatabase.lock(); 106 try { 107 // Note that the native_compile() takes care of destroying any previously 108 // existing programs before it compiles. 109 acquireReference(); 110 native_compile(sql); 111 } finally { 112 releaseReference(); 113 mDatabase.unlock(); 114 } 115 } 116 } 117 118 /** 119 * Bind a NULL value to this statement. The value remains bound until 120 * {@link #clearBindings} is called. 121 * 122 * @param index The 1-based index to the parameter to bind null to 123 */ bindNull(int index)124 public void bindNull(int index) { 125 acquireReference(); 126 try { 127 native_bind_null(index); 128 } finally { 129 releaseReference(); 130 } 131 } 132 133 /** 134 * Bind a long value to this statement. The value remains bound until 135 * {@link #clearBindings} is called. 136 * 137 * @param index The 1-based index to the parameter to bind 138 * @param value The value to bind 139 */ bindLong(int index, long value)140 public void bindLong(int index, long value) { 141 acquireReference(); 142 try { 143 native_bind_long(index, value); 144 } finally { 145 releaseReference(); 146 } 147 } 148 149 /** 150 * Bind a double value to this statement. The value remains bound until 151 * {@link #clearBindings} is called. 152 * 153 * @param index The 1-based index to the parameter to bind 154 * @param value The value to bind 155 */ bindDouble(int index, double value)156 public void bindDouble(int index, double value) { 157 acquireReference(); 158 try { 159 native_bind_double(index, value); 160 } finally { 161 releaseReference(); 162 } 163 } 164 165 /** 166 * Bind a String value to this statement. The value remains bound until 167 * {@link #clearBindings} is called. 168 * 169 * @param index The 1-based index to the parameter to bind 170 * @param value The value to bind 171 */ bindString(int index, String value)172 public void bindString(int index, String value) { 173 if (value == null) { 174 throw new IllegalArgumentException("the bind value at index " + index + " is null"); 175 } 176 acquireReference(); 177 try { 178 native_bind_string(index, value); 179 } finally { 180 releaseReference(); 181 } 182 } 183 184 /** 185 * Bind a byte array value to this statement. The value remains bound until 186 * {@link #clearBindings} is called. 187 * 188 * @param index The 1-based index to the parameter to bind 189 * @param value The value to bind 190 */ bindBlob(int index, byte[] value)191 public void bindBlob(int index, byte[] value) { 192 if (value == null) { 193 throw new IllegalArgumentException("the bind value at index " + index + " is null"); 194 } 195 acquireReference(); 196 try { 197 native_bind_blob(index, value); 198 } finally { 199 releaseReference(); 200 } 201 } 202 203 /** 204 * Clears all existing bindings. Unset bindings are treated as NULL. 205 */ clearBindings()206 public void clearBindings() { 207 acquireReference(); 208 try { 209 native_clear_bindings(); 210 } finally { 211 releaseReference(); 212 } 213 } 214 215 /** 216 * Release this program's resources, making it invalid. 217 */ close()218 public void close() { 219 mDatabase.lock(); 220 try { 221 releaseReference(); 222 } finally { 223 mDatabase.unlock(); 224 } 225 } 226 227 /** 228 * Make sure that the native resource is cleaned up. 229 */ 230 @Override finalize()231 protected void finalize() { 232 if (nStatement != 0) { 233 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { 234 String message = "Finalizing " + this + 235 " that has not been closed"; 236 237 Log.d(TAG, message + "\nThis cursor was created in:"); 238 for (StackTraceElement ste : mStackTraceElements) { 239 Log.d(TAG, " " + ste); 240 } 241 } 242 // when in finalize() it is already removed from weakhashmap 243 // so it is safe to not removed itself from db 244 onAllReferencesReleasedFromContainer(); 245 } 246 } 247 248 /** 249 * Compiles SQL into a SQLite program. 250 * 251 * <P>The database lock must be held when calling this method. 252 * @param sql The SQL to compile. 253 */ native_compile(String sql)254 protected final native void native_compile(String sql); native_finalize()255 protected final native void native_finalize(); 256 native_bind_null(int index)257 protected final native void native_bind_null(int index); native_bind_long(int index, long value)258 protected final native void native_bind_long(int index, long value); native_bind_double(int index, double value)259 protected final native void native_bind_double(int index, double value); native_bind_string(int index, String value)260 protected final native void native_bind_string(int index, String value); native_bind_blob(int index, byte[] value)261 protected final native void native_bind_blob(int index, byte[] value); native_clear_bindings()262 private final native void native_clear_bindings(); 263 } 264 265