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