• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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