CursorWindow.java revision 34ad57f0e844cd97f59d4ab22087d60d58650ba4
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
17package android.database;
18
19import android.content.res.Resources;
20import android.database.sqlite.SQLiteClosable;
21import android.os.IBinder;
22import android.os.Parcel;
23import android.os.Parcelable;
24
25/**
26 * A buffer containing multiple cursor rows.
27 */
28public class CursorWindow extends SQLiteClosable implements Parcelable {
29    /** The cursor window size. resource xml file specifies the value in kB.
30     * convert it to bytes here by multiplying with 1024.
31     */
32    private static final int sCursorWindowSize =
33        Resources.getSystem().getInteger(
34                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
35
36    /** The pointer to the native window class */
37    @SuppressWarnings("unused")
38    private int nWindow;
39
40    private int mStartPos;
41
42    /**
43     * Creates a new empty window.
44     *
45     * @param localWindow true if this window will be used in this process only
46     */
47    public CursorWindow(boolean localWindow) {
48        mStartPos = 0;
49        native_init(sCursorWindowSize, localWindow);
50    }
51
52    /**
53     * Returns the starting position of this window within the entire
54     * Cursor's result set.
55     *
56     * @return the starting position of this window within the entire
57     * Cursor's result set.
58     */
59    public int getStartPosition() {
60        return mStartPos;
61    }
62
63    /**
64     * Set the start position of cursor window
65     * @param pos
66     */
67    public void setStartPosition(int pos) {
68        mStartPos = pos;
69    }
70
71    /**
72     * Returns the number of rows in this window.
73     *
74     * @return the number of rows in this window.
75     */
76    public int getNumRows() {
77        acquireReference();
78        try {
79            return getNumRows_native();
80        } finally {
81            releaseReference();
82        }
83    }
84
85    private native int getNumRows_native();
86    /**
87     * Set number of Columns
88     * @param columnNum
89     * @return true if success
90     */
91    public boolean setNumColumns(int columnNum) {
92        acquireReference();
93        try {
94            return setNumColumns_native(columnNum);
95        } finally {
96            releaseReference();
97        }
98    }
99
100    private native boolean setNumColumns_native(int columnNum);
101
102    /**
103     * Allocate a row in cursor window
104     * @return false if cursor window is out of memory
105     */
106    public boolean allocRow(){
107        acquireReference();
108        try {
109            return allocRow_native();
110        } finally {
111            releaseReference();
112        }
113    }
114
115    private native boolean allocRow_native();
116
117    /**
118     * Free the last row
119     */
120    public void freeLastRow(){
121        acquireReference();
122        try {
123            freeLastRow_native();
124        } finally {
125            releaseReference();
126        }
127    }
128
129    private native void freeLastRow_native();
130
131    /**
132     * copy byte array to cursor window
133     * @param value
134     * @param row
135     * @param col
136     * @return false if fail to copy
137     */
138    public boolean putBlob(byte[] value, int row, int col) {
139        acquireReference();
140        try {
141            return putBlob_native(value, row - mStartPos, col);
142        } finally {
143            releaseReference();
144        }
145    }
146
147    private native boolean putBlob_native(byte[] value, int row, int col);
148
149    /**
150     * Copy String to cursor window
151     * @param value
152     * @param row
153     * @param col
154     * @return false if fail to copy
155     */
156    public boolean putString(String value, int row, int col) {
157        acquireReference();
158        try {
159            return putString_native(value, row - mStartPos, col);
160        } finally {
161            releaseReference();
162        }
163    }
164
165    private native boolean putString_native(String value, int row, int col);
166
167    /**
168     * Copy integer to cursor window
169     * @param value
170     * @param row
171     * @param col
172     * @return false if fail to copy
173     */
174    public boolean putLong(long value, int row, int col) {
175        acquireReference();
176        try {
177            return putLong_native(value, row - mStartPos, col);
178        } finally {
179            releaseReference();
180        }
181    }
182
183    private native boolean putLong_native(long value, int row, int col);
184
185
186    /**
187     * Copy double to cursor window
188     * @param value
189     * @param row
190     * @param col
191     * @return false if fail to copy
192     */
193    public boolean putDouble(double value, int row, int col) {
194        acquireReference();
195        try {
196            return putDouble_native(value, row - mStartPos, col);
197        } finally {
198            releaseReference();
199        }
200    }
201
202    private native boolean putDouble_native(double value, int row, int col);
203
204    /**
205     * Set the [row, col] value to NULL
206     * @param row
207     * @param col
208     * @return false if fail to copy
209     */
210    public boolean putNull(int row, int col) {
211        acquireReference();
212        try {
213            return putNull_native(row - mStartPos, col);
214        } finally {
215            releaseReference();
216        }
217    }
218
219    private native boolean putNull_native(int row, int col);
220
221
222    /**
223     * Returns {@code true} if given field is {@code NULL}.
224     *
225     * @param row the row to read from, row - getStartPosition() being the actual row in the window
226     * @param col the column to read from
227     * @return {@code true} if given field is {@code NULL}
228     * @deprecated use {@link #getType(int, int)} instead
229     */
230    @Deprecated
231    public boolean isNull(int row, int col) {
232        return getType(row, col) == Cursor.FIELD_TYPE_NULL;
233    }
234
235    /**
236     * Returns a byte array for the given field.
237     *
238     * @param row the row to read from, row - getStartPosition() being the actual row in the window
239     * @param col the column to read from
240     * @return a String value for the given field
241     */
242    public byte[] getBlob(int row, int col) {
243        acquireReference();
244        try {
245            return getBlob_native(row - mStartPos, col);
246        } finally {
247            releaseReference();
248        }
249    }
250
251    /**
252     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array.
253     *
254     * <p>If the value is null, then <code>null</code> is returned. If the
255     * type of column <code>col</code> is a string type, then the result
256     * is the array of bytes that make up the internal representation of the
257     * string value. If the type of column <code>col</code> is integral or floating-point,
258     * then an {@link SQLiteException} is thrown.
259     */
260    private native byte[] getBlob_native(int row, int col);
261
262    /**
263     * Returns data type of the given column's value.
264     *<p>
265     * Returned column types are
266     * <ul>
267     *   <li>{@link Cursor#FIELD_TYPE_NULL}</li>
268     *   <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
269     *   <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
270     *   <li>{@link Cursor#FIELD_TYPE_STRING}</li>
271     *   <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
272     *</ul>
273     *</p>
274     *
275     * @param row the row to read from, row - getStartPosition() being the actual row in the window
276     * @param col the column to read from
277     * @return the value type
278     */
279    public int getType(int row, int col) {
280        acquireReference();
281        try {
282            return getType_native(row - mStartPos, col);
283        } finally {
284            releaseReference();
285        }
286    }
287
288    /**
289     * Checks if a field contains either a blob or is null.
290     *
291     * @param row the row to read from, row - getStartPosition() being the actual row in the window
292     * @param col the column to read from
293     * @return {@code true} if given field is {@code NULL} or a blob
294     * @deprecated use {@link #getType(int, int)} instead
295     */
296    @Deprecated
297    public boolean isBlob(int row, int col) {
298        int type = getType(row, col);
299        return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL;
300    }
301
302    /**
303     * Checks if a field contains a long
304     *
305     * @param row the row to read from, row - getStartPosition() being the actual row in the window
306     * @param col the column to read from
307     * @return {@code true} if given field is a long
308     * @deprecated use {@link #getType(int, int)} instead
309     */
310    @Deprecated
311    public boolean isLong(int row, int col) {
312        return getType(row, col) == Cursor.FIELD_TYPE_INTEGER;
313    }
314
315    /**
316     * Checks if a field contains a float.
317     *
318     * @param row the row to read from, row - getStartPosition() being the actual row in the window
319     * @param col the column to read from
320     * @return {@code true} if given field is a float
321     * @deprecated use {@link #getType(int, int)} instead
322     */
323    @Deprecated
324    public boolean isFloat(int row, int col) {
325        return getType(row, col) == Cursor.FIELD_TYPE_FLOAT;
326    }
327
328    /**
329     * Checks if a field contains either a String or is null.
330     *
331     * @param row the row to read from, row - getStartPosition() being the actual row in the window
332     * @param col the column to read from
333     * @return {@code true} if given field is {@code NULL} or a String
334     * @deprecated use {@link #getType(int, int)} instead
335     */
336    @Deprecated
337    public boolean isString(int row, int col) {
338        int type = getType(row, col);
339        return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL;
340    }
341
342    private native int getType_native(int row, int col);
343
344    /**
345     * Returns a String for the given field.
346     *
347     * @param row the row to read from, row - getStartPosition() being the actual row in the window
348     * @param col the column to read from
349     * @return a String value for the given field
350     */
351    public String getString(int row, int col) {
352        acquireReference();
353        try {
354            return getString_native(row - mStartPos, col);
355        } finally {
356            releaseReference();
357        }
358    }
359
360    /**
361     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>.
362     *
363     * <p>If the value is null, then <code>null</code> is returned. If the
364     * type of column <code>col</code> is integral, then the result is the string
365     * that is obtained by formatting the integer value with the <code>printf</code>
366     * family of functions using format specifier <code>%lld</code>. If the
367     * type of column <code>col</code> is floating-point, then the result is the string
368     * that is obtained by formatting the floating-point value with the
369     * <code>printf</code> family of functions using format specifier <code>%g</code>.
370     * If the type of column <code>col</code> is a blob type, then an
371     * {@link SQLiteException} is thrown.
372     */
373    private native String getString_native(int row, int col);
374
375    /**
376     * copy the text for the given field in the provided char array.
377     *
378     * @param row the row to read from, row - getStartPosition() being the actual row in the window
379     * @param col the column to read from
380     * @param buffer the CharArrayBuffer to copy the text into,
381     * If the requested string is larger than the buffer
382     * a new char buffer will be created to hold the string. and assigne to
383     * CharArrayBuffer.data
384      */
385    public void copyStringToBuffer(int row, int col, CharArrayBuffer buffer) {
386        if (buffer == null) {
387            throw new IllegalArgumentException("CharArrayBuffer should not be null");
388        }
389        if (buffer.data == null) {
390            buffer.data = new char[64];
391        }
392        acquireReference();
393        try {
394            char[] newbuf = copyStringToBuffer_native(
395                    row - mStartPos, col, buffer.data.length, buffer);
396            if (newbuf != null) {
397                buffer.data = newbuf;
398            }
399        } finally {
400            releaseReference();
401        }
402    }
403
404    private native char[] copyStringToBuffer_native(
405            int row, int col, int bufferSize, CharArrayBuffer buffer);
406
407    /**
408     * Returns a long for the given field.
409     * row is 0 based
410     *
411     * @param row the row to read from, row - getStartPosition() being the actual row in the window
412     * @param col the column to read from
413     * @return a long value for the given field
414     */
415    public long getLong(int row, int col) {
416        acquireReference();
417        try {
418            return getLong_native(row - mStartPos, col);
419        } finally {
420            releaseReference();
421        }
422    }
423
424    /**
425     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>.
426     *
427     * <p>If the value is null, then <code>0L</code> is returned. If the
428     * type of column <code>col</code> is a string type, then the result
429     * is the <code>long</code> that is obtained by parsing the string value with
430     * <code>strtoll</code>. If the type of column <code>col</code> is
431     * floating-point, then the result is the floating-point value casted to a <code>long</code>.
432     * If the type of column <code>col</code> is a blob type, then an
433     * {@link SQLiteException} is thrown.
434     */
435    private native long getLong_native(int row, int col);
436
437    /**
438     * Returns a double for the given field.
439     * row is 0 based
440     *
441     * @param row the row to read from, row - getStartPosition() being the actual row in the window
442     * @param col the column to read from
443     * @return a double value for the given field
444     */
445    public double getDouble(int row, int col) {
446        acquireReference();
447        try {
448            return getDouble_native(row - mStartPos, col);
449        } finally {
450            releaseReference();
451        }
452    }
453
454    /**
455     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>.
456     *
457     * <p>If the value is null, then <code>0.0</code> is returned. If the
458     * type of column <code>col</code> is a string type, then the result
459     * is the <code>double</code> that is obtained by parsing the string value with
460     * <code>strtod</code>. If the type of column <code>col</code> is
461     * integral, then the result is the integer value casted to a <code>double</code>.
462     * If the type of column <code>col</code> is a blob type, then an
463     * {@link SQLiteException} is thrown.
464     */
465    private native double getDouble_native(int row, int col);
466
467    /**
468     * Returns a short for the given field.
469     * row is 0 based
470     *
471     * @param row the row to read from, row - getStartPosition() being the actual row in the window
472     * @param col the column to read from
473     * @return a short value for the given field
474     */
475    public short getShort(int row, int col) {
476        acquireReference();
477        try {
478            return (short) getLong_native(row - mStartPos, col);
479        } finally {
480            releaseReference();
481        }
482    }
483
484    /**
485     * Returns an int for the given field.
486     *
487     * @param row the row to read from, row - getStartPosition() being the actual row in the window
488     * @param col the column to read from
489     * @return an int value for the given field
490     */
491    public int getInt(int row, int col) {
492        acquireReference();
493        try {
494            return (int) getLong_native(row - mStartPos, col);
495        } finally {
496            releaseReference();
497        }
498    }
499
500    /**
501     * Returns a float for the given field.
502     * row is 0 based
503     *
504     * @param row the row to read from, row - getStartPosition() being the actual row in the window
505     * @param col the column to read from
506     * @return a float value for the given field
507     */
508    public float getFloat(int row, int col) {
509        acquireReference();
510        try {
511            return (float) getDouble_native(row - mStartPos, col);
512        } finally {
513            releaseReference();
514        }
515    }
516
517    /**
518     * Clears out the existing contents of the window, making it safe to reuse
519     * for new data. Note that the number of columns in the window may NOT
520     * change across a call to clear().
521     */
522    public void clear() {
523        acquireReference();
524        try {
525            mStartPos = 0;
526            native_clear();
527        } finally {
528            releaseReference();
529        }
530    }
531
532    /** Clears out the native side of things */
533    private native void native_clear();
534
535    /**
536     * Cleans up the native resources associated with the window.
537     */
538    public void close() {
539        releaseReference();
540    }
541
542    private native void close_native();
543
544    @Override
545    protected void finalize() {
546        // Just in case someone forgot to call close...
547        close_native();
548    }
549
550    public static final Parcelable.Creator<CursorWindow> CREATOR
551            = new Parcelable.Creator<CursorWindow>() {
552        public CursorWindow createFromParcel(Parcel source) {
553            return new CursorWindow(source);
554        }
555
556        public CursorWindow[] newArray(int size) {
557            return new CursorWindow[size];
558        }
559    };
560
561    public static CursorWindow newFromParcel(Parcel p) {
562        return CREATOR.createFromParcel(p);
563    }
564
565    public int describeContents() {
566        return 0;
567    }
568
569    public void writeToParcel(Parcel dest, int flags) {
570        dest.writeStrongBinder(native_getBinder());
571        dest.writeInt(mStartPos);
572    }
573
574    private CursorWindow(Parcel source) {
575        IBinder nativeBinder = source.readStrongBinder();
576        mStartPos = source.readInt();
577
578        native_init(nativeBinder);
579    }
580
581    /** Get the binder for the native side of the window */
582    private native IBinder native_getBinder();
583
584    /** Does the native side initialization for an empty window */
585    private native void native_init(int cursorWindowSize, boolean localOnly);
586
587    /** Does the native side initialization with an existing binder from another process */
588    private native void native_init(IBinder nativeBinder);
589
590    @Override
591    protected void onAllReferencesReleased() {
592        close_native();
593    }
594}
595