1b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar/*
2b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * Copyright (C) 2017 The Android Open Source Project
3b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar *
4b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * you may not use this file except in compliance with the License.
6b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * You may obtain a copy of the License at
7b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar *
8b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar *
10b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * Unless required by applicable law or agreed to in writing, software
11b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * See the License for the specific language governing permissions and
14b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * limitations under the License.
15b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar */
16b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room;
18b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
1964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.db.SupportSQLiteProgram;
2064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.db.SupportSQLiteQuery;
21b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport android.support.annotation.IntDef;
228fed7d5361340af73d78232244697117675ac5c3Yigit Boyarimport android.support.annotation.RestrictTo;
23b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport android.support.annotation.VisibleForTesting;
24b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
259691051d4acf7de89396388ca195f0c569257804Yigit Boyarimport java.lang.annotation.Retention;
269691051d4acf7de89396388ca195f0c569257804Yigit Boyarimport java.lang.annotation.RetentionPolicy;
27b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport java.util.Arrays;
28b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport java.util.Iterator;
29b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport java.util.Map;
30b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarimport java.util.TreeMap;
31b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
32b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar/**
33b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * This class is used as an intermediate place to keep binding arguments so that we can run
34b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * Cursor queries with correct types rather than passing everything as a string.
35b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * <p>
36b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar * Because it is relatively a big object, they are pooled and must be released after each use.
3764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar *
388fed7d5361340af73d78232244697117675ac5c3Yigit Boyar * @hide
39b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar */
40b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar@SuppressWarnings("unused")
418fed7d5361340af73d78232244697117675ac5c3Yigit Boyar@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
42b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyarpublic class RoomSQLiteQuery implements SupportSQLiteQuery, SupportSQLiteProgram {
43b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
44b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
458fed7d5361340af73d78232244697117675ac5c3Yigit Boyar    // Maximum number of queries we'll keep cached.
46b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    static final int POOL_LIMIT = 15;
47b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
48b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
498fed7d5361340af73d78232244697117675ac5c3Yigit Boyar    // Once we hit POOL_LIMIT, we'll bring the pool size back to the desired number. We always
508fed7d5361340af73d78232244697117675ac5c3Yigit Boyar    // clear the bigger queries (# of arguments).
51b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    static final int DESIRED_POOL_SIZE = 10;
52b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private volatile String mQuery;
53b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
54b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
55b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    final long[] mLongBindings;
56b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
57b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
58b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    final double[] mDoubleBindings;
59b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
60b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
61b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    final String[] mStringBindings;
62b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
63b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
64b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    final byte[][] mBlobBindings;
65b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
66b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Binding
67b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private final int[] mBindingTypes;
68b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
69b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
70b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    final int mCapacity;
71b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    // number of arguments in the query
72b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
73b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
74b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    int mArgCount;
75b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
76b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
77b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
78b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @VisibleForTesting
79b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    static final TreeMap<Integer, RoomSQLiteQuery> sQueryPool = new TreeMap<>();
80b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
81b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    /**
82b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * Returns a new RoomSQLiteQuery that can accept the given number of arguments and holds the
83b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * given query.
84b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     *
85b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * @param query         The query to prepare
86b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * @param argumentCount The number of query arguments
87b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * @return A RoomSQLiteQuery that holds the given query and has space for the given number of
88b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * arguments.
89b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     */
908fed7d5361340af73d78232244697117675ac5c3Yigit Boyar    @SuppressWarnings("WeakerAccess")
91b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public static RoomSQLiteQuery acquire(String query, int argumentCount) {
92b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        synchronized (sQueryPool) {
93b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            final Map.Entry<Integer, RoomSQLiteQuery> entry =
94b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    sQueryPool.ceilingEntry(argumentCount);
95b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            if (entry != null) {
96b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                sQueryPool.remove(entry.getKey());
97b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                final RoomSQLiteQuery sqliteQuery = entry.getValue();
98b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                sqliteQuery.init(query, argumentCount);
99b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                return sqliteQuery;
100b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            }
101b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        }
102b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        RoomSQLiteQuery sqLiteQuery = new RoomSQLiteQuery(argumentCount);
103b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        sqLiteQuery.init(query, argumentCount);
104b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        return sqLiteQuery;
105b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
106b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
107b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private RoomSQLiteQuery(int capacity) {
108b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mCapacity = capacity;
109b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        // because, 1 based indices... we don't want to offsets everything with 1 all the time.
110b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        int limit = capacity + 1;
111b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        //noinspection WrongConstant
112b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes = new int[limit];
113b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mLongBindings = new long[limit];
114b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mDoubleBindings = new double[limit];
115b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mStringBindings = new String[limit];
116b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBlobBindings = new byte[limit][];
117b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
118b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
119b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @SuppressWarnings("WeakerAccess")
120b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    void init(String query, int argCount) {
121b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mQuery = query;
122b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mArgCount = argCount;
123b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
124b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
125b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    /**
126b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     * Releases the query back to the pool.
1278fed7d5361340af73d78232244697117675ac5c3Yigit Boyar     * <p>
1288fed7d5361340af73d78232244697117675ac5c3Yigit Boyar     * After released, the statement might be returned when {@link #acquire(String, int)} is called
1298fed7d5361340af73d78232244697117675ac5c3Yigit Boyar     * so you should never re-use it after releasing.
130b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar     */
1318fed7d5361340af73d78232244697117675ac5c3Yigit Boyar    @SuppressWarnings("WeakerAccess")
132b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void release() {
133b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        synchronized (sQueryPool) {
134b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            sQueryPool.put(mCapacity, this);
135b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            prunePoolLocked();
136b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        }
137b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
138b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
139b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static void prunePoolLocked() {
140b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        if (sQueryPool.size() > POOL_LIMIT) {
141b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            int toBeRemoved = sQueryPool.size() - DESIRED_POOL_SIZE;
142b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            final Iterator<Integer> iterator = sQueryPool.descendingKeySet().iterator();
143b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            while (toBeRemoved-- > 0) {
144b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                iterator.next();
145b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                iterator.remove();
146b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            }
147b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        }
148b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
149b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
150b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
151b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public String getSql() {
152b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        return mQuery;
153b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
154b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
1559fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik    public int getArgCount() {
1569fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        return mArgCount;
1579fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik    }
1589fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik
159b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
160b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindTo(SupportSQLiteProgram program) {
161b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        for (int index = 1; index <= mArgCount; index++) {
162b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            switch (mBindingTypes[index]) {
163b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                case NULL:
164b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    program.bindNull(index);
165b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    break;
166b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                case LONG:
167b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    program.bindLong(index, mLongBindings[index]);
168b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    break;
169b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                case DOUBLE:
170b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    program.bindDouble(index, mDoubleBindings[index]);
171b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    break;
172b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                case STRING:
173b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    program.bindString(index, mStringBindings[index]);
174b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    break;
175b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                case BLOB:
176b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    program.bindBlob(index, mBlobBindings[index]);
177b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar                    break;
178b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar            }
179b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        }
180b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
181b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
182b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
183b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindNull(int index) {
184b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes[index] = NULL;
185b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
186b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
187b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
188b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindLong(int index, long value) {
189b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes[index] = LONG;
190b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mLongBindings[index] = value;
191b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
192b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
193b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
194b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindDouble(int index, double value) {
195b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes[index] = DOUBLE;
196b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mDoubleBindings[index] = value;
197b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
198b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
199b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
200b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindString(int index, String value) {
201b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes[index] = STRING;
202b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mStringBindings[index] = value;
203b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
204b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
205b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
206b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void bindBlob(int index, byte[] value) {
207b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBindingTypes[index] = BLOB;
208b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mBlobBindings[index] = value;
209b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
210b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
2110d1b036f6868844705cd3b57e96d373edd09b3d5Yigit Boyar    @Override
2120d1b036f6868844705cd3b57e96d373edd09b3d5Yigit Boyar    public void close() throws Exception {
2130d1b036f6868844705cd3b57e96d373edd09b3d5Yigit Boyar        // no-op. not calling release because it is internal API.
2140d1b036f6868844705cd3b57e96d373edd09b3d5Yigit Boyar    }
2150d1b036f6868844705cd3b57e96d373edd09b3d5Yigit Boyar
2169fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik    /**
2179fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik     * Copies arguments from another RoomSQLiteQuery into this query.
2189fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik     *
2199fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik     * @param other The other query, which holds the arguments to be copied.
2209fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik     */
2219fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik    public void copyArgumentsFrom(RoomSQLiteQuery other) {
2229fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        int argCount = other.getArgCount() + 1; // +1 for the binding offsets
2239fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        System.arraycopy(other.mBindingTypes, 0, mBindingTypes, 0, argCount);
2249fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        System.arraycopy(other.mLongBindings, 0, mLongBindings, 0, argCount);
2259fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        System.arraycopy(other.mStringBindings, 0, mStringBindings, 0, argCount);
2269fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        System.arraycopy(other.mBlobBindings, 0, mBlobBindings, 0, argCount);
2279fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik        System.arraycopy(other.mDoubleBindings, 0, mDoubleBindings, 0, argCount);
2289fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik    }
2299fd8e6171bbdc37f5516fe15b2d96f4ae926ef1aChris Craik
230b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @Override
231b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    public void clearBindings() {
232b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        Arrays.fill(mBindingTypes, NULL);
233b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        Arrays.fill(mStringBindings, null);
234b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        Arrays.fill(mBlobBindings, null);
235b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        mQuery = null;
236b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar        // no need to clear others
237b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
238b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
239b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static final int NULL = 1;
240b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static final int LONG = 2;
241b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static final int DOUBLE = 3;
242b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static final int STRING = 4;
243b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    private static final int BLOB = 5;
244b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar
2459691051d4acf7de89396388ca195f0c569257804Yigit Boyar    @Retention(RetentionPolicy.SOURCE)
246b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @IntDef({NULL, LONG, DOUBLE, STRING, BLOB})
247b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    @interface Binding {
248b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar    }
249b030dcb5b7a62854c0bfe85bf04eaf60caeb83bbYigit Boyar}
250