• 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.compat.annotation.UnsupportedAppUsage;
20 import android.database.DatabaseUtils;
21 import android.os.Build;
22 import android.os.CancellationSignal;
23 
24 import java.util.Arrays;
25 
26 /**
27  * A base class for compiled SQLite programs.
28  * <p>
29  * This class is not thread-safe.
30  * </p>
31  */
32 public abstract class SQLiteProgram extends SQLiteClosable {
33     private static final String[] EMPTY_STRING_ARRAY = new String[0];
34 
35     private final SQLiteDatabase mDatabase;
36     @UnsupportedAppUsage
37     private final String mSql;
38     private final boolean mReadOnly;
39     private final String[] mColumnNames;
40     private final int mNumParameters;
41     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
42     private final Object[] mBindArgs;
43 
SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs, CancellationSignal cancellationSignalForPrepare)44     SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
45             CancellationSignal cancellationSignalForPrepare) {
46         mDatabase = db;
47         mSql = sql.trim();
48 
49         int n = DatabaseUtils.getSqlStatementType(mSql);
50         switch (n) {
51             case DatabaseUtils.STATEMENT_BEGIN:
52             case DatabaseUtils.STATEMENT_COMMIT:
53             case DatabaseUtils.STATEMENT_ABORT:
54                 mReadOnly = false;
55                 mColumnNames = EMPTY_STRING_ARRAY;
56                 mNumParameters = 0;
57                 break;
58 
59             default:
60                 boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
61                 SQLiteStatementInfo info = new SQLiteStatementInfo();
62                 db.getThreadSession().prepare(mSql,
63                         db.getThreadDefaultConnectionFlags(assumeReadOnly),
64                         cancellationSignalForPrepare, info);
65                 mReadOnly = info.readOnly;
66                 mColumnNames = info.columnNames;
67                 mNumParameters = info.numParameters;
68                 break;
69         }
70 
71         if (bindArgs != null && bindArgs.length > mNumParameters) {
72             throw new IllegalArgumentException("Too many bind arguments.  "
73                     + bindArgs.length + " arguments were provided but the statement needs "
74                     + mNumParameters + " arguments.");
75         }
76 
77         if (mNumParameters != 0) {
78             mBindArgs = new Object[mNumParameters];
79             if (bindArgs != null) {
80                 System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
81             }
82         } else {
83             mBindArgs = null;
84         }
85     }
86 
getDatabase()87     final SQLiteDatabase getDatabase() {
88         return mDatabase;
89     }
90 
getSql()91     final String getSql() {
92         return mSql;
93     }
94 
getBindArgs()95     final Object[] getBindArgs() {
96         return mBindArgs;
97     }
98 
getColumnNames()99     final String[] getColumnNames() {
100         return mColumnNames;
101     }
102 
103     /** @hide */
getSession()104     protected final SQLiteSession getSession() {
105         return mDatabase.getThreadSession();
106     }
107 
108     /** @hide */
getConnectionFlags()109     protected final int getConnectionFlags() {
110         return mDatabase.getThreadDefaultConnectionFlags(mReadOnly);
111     }
112 
113     /** @hide */
onCorruption()114     protected final void onCorruption() {
115         mDatabase.onCorruption();
116     }
117 
118     /**
119      * Unimplemented.
120      * @deprecated This method is deprecated and must not be used.
121      */
122     @Deprecated
getUniqueId()123     public final int getUniqueId() {
124         return -1;
125     }
126 
127     /**
128      * Bind a NULL value to this statement. The value remains bound until
129      * {@link #clearBindings} is called.
130      *
131      * @param index The 1-based index to the parameter to bind null to
132      */
bindNull(int index)133     public void bindNull(int index) {
134         bind(index, null);
135     }
136 
137     /**
138      * Bind a long value to this statement. The value remains bound until
139      * {@link #clearBindings} is called.
140      *addToBindArgs
141      * @param index The 1-based index to the parameter to bind
142      * @param value The value to bind
143      */
bindLong(int index, long value)144     public void bindLong(int index, long value) {
145         bind(index, value);
146     }
147 
148     /**
149      * Bind a double value to this statement. The value remains bound until
150      * {@link #clearBindings} is called.
151      *
152      * @param index The 1-based index to the parameter to bind
153      * @param value The value to bind
154      */
bindDouble(int index, double value)155     public void bindDouble(int index, double value) {
156         bind(index, value);
157     }
158 
159     /**
160      * Bind a String value to this statement. The value remains bound until
161      * {@link #clearBindings} is called.
162      *
163      * @param index The 1-based index to the parameter to bind
164      * @param value The value to bind, must not be null
165      */
bindString(int index, String value)166     public void bindString(int index, String value) {
167         if (value == null) {
168             throw new IllegalArgumentException("the bind value at index " + index + " is null");
169         }
170         bind(index, value);
171     }
172 
173     /**
174      * Bind a byte array value to this statement. The value remains bound until
175      * {@link #clearBindings} is called.
176      *
177      * @param index The 1-based index to the parameter to bind
178      * @param value The value to bind, must not be null
179      */
bindBlob(int index, byte[] value)180     public void bindBlob(int index, byte[] value) {
181         if (value == null) {
182             throw new IllegalArgumentException("the bind value at index " + index + " is null");
183         }
184         bind(index, value);
185     }
186 
187     /**
188      * Clears all existing bindings. Unset bindings are treated as NULL.
189      */
clearBindings()190     public void clearBindings() {
191         if (mBindArgs != null) {
192             Arrays.fill(mBindArgs, null);
193         }
194     }
195 
196     /**
197      * Given an array of String bindArgs, this method binds all of them in one single call.
198      *
199      * @param bindArgs the String array of bind args, none of which must be null.
200      */
bindAllArgsAsStrings(String[] bindArgs)201     public void bindAllArgsAsStrings(String[] bindArgs) {
202         if (bindArgs != null) {
203             for (int i = bindArgs.length; i != 0; i--) {
204                 bindString(i, bindArgs[i - 1]);
205             }
206         }
207     }
208 
209     @Override
onAllReferencesReleased()210     protected void onAllReferencesReleased() {
211         clearBindings();
212     }
213 
bind(int index, Object value)214     private void bind(int index, Object value) {
215         if (index < 1 || index > mNumParameters) {
216             throw new IllegalArgumentException("Cannot bind argument at index "
217                     + index + " because the index is out of range.  "
218                     + "The statement has " + mNumParameters + " parameters.");
219         }
220         mBindArgs[index - 1] = value;
221     }
222 }
223