blob: 4d96f12c794691cbaf02c845f4344858a274a069 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.database.sqlite;
18
Vasu Nori36957092010-03-11 14:57:53 -080019import android.util.Log;
20
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021/**
22 * A base class for compiled SQLite programs.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -070023 *
24 * SQLiteProgram is not internally synchronized so code using a SQLiteProgram from multiple
25 * threads should perform its own synchronization when using the SQLiteProgram.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026 */
27public abstract class SQLiteProgram extends SQLiteClosable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
Vasu Nori36957092010-03-11 14:57:53 -080029 private static final String TAG = "SQLiteProgram";
30
Vasu Nori14b60e72010-03-01 14:47:47 -080031 /** The database this program is compiled against.
32 * @deprecated do not use this
33 */
34 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 protected SQLiteDatabase mDatabase;
36
Vasu Nori5a03f362009-10-20 15:16:35 -070037 /** The SQL used to create this query */
38 /* package */ final String mSql;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 /**
41 * Native linkage, do not modify. This comes from the database and should not be modified
42 * in here or in the native code.
Vasu Nori14b60e72010-03-01 14:47:47 -080043 * @deprecated do not use this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 */
Vasu Nori14b60e72010-03-01 14:47:47 -080045 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 protected int nHandle = 0;
47
48 /**
Vasu Norie495d1f2010-01-06 16:34:19 -080049 * the SQLiteCompiledSql object for the given sql statement.
Vasu Nori5a03f362009-10-20 15:16:35 -070050 */
Vasu Norie495d1f2010-01-06 16:34:19 -080051 private SQLiteCompiledSql mCompiledSql;
Vasu Nori5a03f362009-10-20 15:16:35 -070052
53 /**
Vasu Norie495d1f2010-01-06 16:34:19 -080054 * SQLiteCompiledSql statement id is populated with the corresponding object from the above
55 * member. This member is used by the native_bind_* methods
Vasu Nori14b60e72010-03-01 14:47:47 -080056 * @deprecated do not use this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 */
Vasu Nori14b60e72010-03-01 14:47:47 -080058 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 protected int nStatement = 0;
60
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 /* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 mDatabase = db;
Vasu Norid606b4b2010-02-24 12:54:20 -080063 mSql = sql.trim();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 db.acquireReference();
65 db.addSQLiteClosable(this);
66 this.nHandle = db.mNativeHandle;
Vasu Nori5a03f362009-10-20 15:16:35 -070067
Vasu Nori49d02ac2010-03-05 21:49:30 -080068 // only cache CRUD statements
Vasu Norid606b4b2010-02-24 12:54:20 -080069 String prefixSql = mSql.substring(0, 6);
Vasu Nori49d02ac2010-03-05 21:49:30 -080070 if (!prefixSql.equalsIgnoreCase("INSERT") && !prefixSql.equalsIgnoreCase("UPDATE") &&
Vasu Nori8648e372010-03-09 12:33:39 -080071 !prefixSql.equalsIgnoreCase("REPLAC") &&
Vasu Nori49d02ac2010-03-05 21:49:30 -080072 !prefixSql.equalsIgnoreCase("DELETE") && !prefixSql.equalsIgnoreCase("SELECT")) {
Vasu Norid606b4b2010-02-24 12:54:20 -080073 mCompiledSql = new SQLiteCompiledSql(db, sql);
74 nStatement = mCompiledSql.nStatement;
75 // since it is not in the cache, no need to acquire() it.
76 return;
77 }
78
79 // it is not pragma
Vasu Norie495d1f2010-01-06 16:34:19 -080080 mCompiledSql = db.getCompiledStatementForSql(sql);
81 if (mCompiledSql == null) {
Vasu Nori5a03f362009-10-20 15:16:35 -070082 // create a new compiled-sql obj
Vasu Norie495d1f2010-01-06 16:34:19 -080083 mCompiledSql = new SQLiteCompiledSql(db, sql);
Vasu Nori5a03f362009-10-20 15:16:35 -070084
85 // add it to the cache of compiled-sqls
Vasu Nori1d726582010-02-24 12:42:46 -080086 // but before adding it and thus making it available for anyone else to use it,
87 // make sure it is acquired by me.
Vasu Norie8de2842010-02-18 13:35:42 -080088 mCompiledSql.acquire();
Vasu Nori1d726582010-02-24 12:42:46 -080089 db.addToCompiledQueries(sql, mCompiledSql);
Vasu Nori36957092010-03-11 14:57:53 -080090 if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
91 Log.v(TAG, "Created DbObj (id#" + mCompiledSql.nStatement +
92 ") for sql: " + sql);
93 }
Vasu Norie8de2842010-02-18 13:35:42 -080094 } else {
95 // it is already in compiled-sql cache.
Vasu Noriec37e422010-02-22 12:28:16 -080096 // try to acquire the object.
97 if (!mCompiledSql.acquire()) {
Vasu Nori36957092010-03-11 14:57:53 -080098 int last = mCompiledSql.nStatement;
Vasu Noriec37e422010-02-22 12:28:16 -080099 // the SQLiteCompiledSql in cache is in use by some other SQLiteProgram object.
Vasu Norie8de2842010-02-18 13:35:42 -0800100 // we can't have two different SQLiteProgam objects can't share the same
101 // CompiledSql object. create a new one.
102 // finalize it when I am done with it in "this" object.
103 mCompiledSql = new SQLiteCompiledSql(db, sql);
Vasu Nori36957092010-03-11 14:57:53 -0800104 if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
105 Log.v(TAG, "** possible bug ** Created NEW DbObj (id#" +
106 mCompiledSql.nStatement +
107 ") because the previously created DbObj (id#" + last +
108 ") was not released for sql:" + sql);
109 }
Vasu Norid606b4b2010-02-24 12:54:20 -0800110 // since it is not in the cache, no need to acquire() it.
Vasu Norie8de2842010-02-18 13:35:42 -0800111 }
Vasu Nori5a03f362009-10-20 15:16:35 -0700112 }
Vasu Norie495d1f2010-01-06 16:34:19 -0800113 nStatement = mCompiledSql.nStatement;
Vasu Nori5a03f362009-10-20 15:16:35 -0700114 }
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 @Override
117 protected void onAllReferencesReleased() {
Vasu Norie8de2842010-02-18 13:35:42 -0800118 releaseCompiledSqlIfNotInCache();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 mDatabase.releaseReference();
120 mDatabase.removeSQLiteClosable(this);
121 }
Vasu Nori5a03f362009-10-20 15:16:35 -0700122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 @Override
Vasu Nori5a03f362009-10-20 15:16:35 -0700124 protected void onAllReferencesReleasedFromContainer() {
Vasu Norie8de2842010-02-18 13:35:42 -0800125 releaseCompiledSqlIfNotInCache();
Vasu Nori5a03f362009-10-20 15:16:35 -0700126 mDatabase.releaseReference();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 }
128
Vasu Norie8de2842010-02-18 13:35:42 -0800129 private void releaseCompiledSqlIfNotInCache() {
Vasu Norie495d1f2010-01-06 16:34:19 -0800130 if (mCompiledSql == null) {
131 return;
132 }
133 synchronized(mDatabase.mCompiledQueries) {
134 if (!mDatabase.mCompiledQueries.containsValue(mCompiledSql)) {
Vasu Norie8de2842010-02-18 13:35:42 -0800135 // it is NOT in compiled-sql cache. i.e., responsibility of
Vasu Norid606b4b2010-02-24 12:54:20 -0800136 // releasing this statement is on me.
Vasu Norie495d1f2010-01-06 16:34:19 -0800137 mCompiledSql.releaseSqlStatement();
Vasu Norid606b4b2010-02-24 12:54:20 -0800138 mCompiledSql = null;
Vasu Norie495d1f2010-01-06 16:34:19 -0800139 nStatement = 0;
Vasu Norie8de2842010-02-18 13:35:42 -0800140 } else {
141 // it is in compiled-sql cache. reset its CompiledSql#mInUse flag
142 mCompiledSql.release();
Vasu Norie495d1f2010-01-06 16:34:19 -0800143 }
Vasu Nori36957092010-03-11 14:57:53 -0800144 }
Vasu Norie495d1f2010-01-06 16:34:19 -0800145 }
146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 /**
148 * Returns a unique identifier for this program.
Vasu Nori5a03f362009-10-20 15:16:35 -0700149 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 * @return a unique identifier for this program
151 */
152 public final int getUniqueId() {
Vasu Norie495d1f2010-01-06 16:34:19 -0800153 return nStatement;
Vasu Nori5a03f362009-10-20 15:16:35 -0700154 }
155
156 /* package */ String getSqlString() {
157 return mSql;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
159
160 /**
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800161 * @deprecated This method is deprecated and must not be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 *
163 * @param sql the SQL string to compile
164 * @param forceCompilation forces the SQL to be recompiled in the event that there is an
165 * existing compiled SQL program already around
166 */
Vasu Nori5a03f362009-10-20 15:16:35 -0700167 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 protected void compile(String sql, boolean forceCompilation) {
Vasu Nori5a03f362009-10-20 15:16:35 -0700169 // TODO is there a need for this?
170 }
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /**
173 * Bind a NULL value to this statement. The value remains bound until
174 * {@link #clearBindings} is called.
175 *
176 * @param index The 1-based index to the parameter to bind null to
177 */
178 public void bindNull(int index) {
Vasu Noric8e1f232010-04-13 15:05:09 -0700179 if (!mDatabase.isOpen()) {
180 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 acquireReference();
183 try {
184 native_bind_null(index);
185 } finally {
186 releaseReference();
187 }
188 }
189
190 /**
191 * Bind a long value to this statement. The value remains bound until
192 * {@link #clearBindings} is called.
193 *
194 * @param index The 1-based index to the parameter to bind
195 * @param value The value to bind
196 */
197 public void bindLong(int index, long value) {
Vasu Noric8e1f232010-04-13 15:05:09 -0700198 if (!mDatabase.isOpen()) {
199 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 acquireReference();
202 try {
203 native_bind_long(index, value);
204 } finally {
205 releaseReference();
206 }
207 }
208
209 /**
210 * Bind a double value to this statement. The value remains bound until
211 * {@link #clearBindings} is called.
212 *
213 * @param index The 1-based index to the parameter to bind
214 * @param value The value to bind
215 */
216 public void bindDouble(int index, double value) {
Vasu Noric8e1f232010-04-13 15:05:09 -0700217 if (!mDatabase.isOpen()) {
218 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 acquireReference();
221 try {
222 native_bind_double(index, value);
223 } finally {
224 releaseReference();
225 }
226 }
227
228 /**
229 * Bind a String value to this statement. The value remains bound until
230 * {@link #clearBindings} is called.
231 *
232 * @param index The 1-based index to the parameter to bind
233 * @param value The value to bind
234 */
235 public void bindString(int index, String value) {
236 if (value == null) {
237 throw new IllegalArgumentException("the bind value at index " + index + " is null");
238 }
Vasu Noric8e1f232010-04-13 15:05:09 -0700239 if (!mDatabase.isOpen()) {
240 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 acquireReference();
243 try {
244 native_bind_string(index, value);
245 } finally {
246 releaseReference();
247 }
248 }
249
250 /**
251 * Bind a byte array value to this statement. The value remains bound until
252 * {@link #clearBindings} is called.
253 *
254 * @param index The 1-based index to the parameter to bind
255 * @param value The value to bind
256 */
257 public void bindBlob(int index, byte[] value) {
258 if (value == null) {
259 throw new IllegalArgumentException("the bind value at index " + index + " is null");
260 }
Vasu Noric8e1f232010-04-13 15:05:09 -0700261 if (!mDatabase.isOpen()) {
262 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 acquireReference();
265 try {
266 native_bind_blob(index, value);
267 } finally {
268 releaseReference();
269 }
270 }
271
272 /**
273 * Clears all existing bindings. Unset bindings are treated as NULL.
274 */
275 public void clearBindings() {
Vasu Noric8e1f232010-04-13 15:05:09 -0700276 if (!mDatabase.isOpen()) {
277 throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 acquireReference();
280 try {
281 native_clear_bindings();
282 } finally {
283 releaseReference();
284 }
285 }
286
287 /**
288 * Release this program's resources, making it invalid.
289 */
290 public void close() {
Vasu Noric8e1f232010-04-13 15:05:09 -0700291 if (!mDatabase.isOpen()) {
Vasu Nori0dbb9cee2010-04-16 14:24:57 -0700292 return;
Vasu Noric8e1f232010-04-13 15:05:09 -0700293 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 mDatabase.lock();
295 try {
296 releaseReference();
297 } finally {
298 mDatabase.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 }
300 }
301
302 /**
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800303 * @deprecated This method is deprecated and must not be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 * Compiles SQL into a SQLite program.
Vasu Nori5a03f362009-10-20 15:16:35 -0700305 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 * <P>The database lock must be held when calling this method.
307 * @param sql The SQL to compile.
308 */
Vasu Nori5a03f362009-10-20 15:16:35 -0700309 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 protected final native void native_compile(String sql);
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800311
312 /**
313 * @deprecated This method is deprecated and must not be used.
314 */
Vasu Nori5a03f362009-10-20 15:16:35 -0700315 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 protected final native void native_finalize();
317
318 protected final native void native_bind_null(int index);
319 protected final native void native_bind_long(int index, long value);
320 protected final native void native_bind_double(int index, double value);
321 protected final native void native_bind_string(int index, String value);
322 protected final native void native_bind_blob(int index, byte[] value);
323 private final native void native_clear_bindings();
324}
325