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