CursorWindow.java revision adf41944584f67378481e84cb7661f0a39028bd8
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     */
221    public boolean isNull(int row, int col) {
222        acquireReference();
223        try {
224            return isNull_native(row - mStartPos, col);
225        } finally {
226            releaseReference();
227        }
228    }
229
230    private native boolean isNull_native(int row, int col);
231
232    /**
233     * Returns a byte array for the given field.
234     *
235     * @param row the row to read from, row - getStartPosition() being the actual row in the window
236     * @param col the column to read from
237     * @return a String value for the given field
238     */
239    public byte[] getBlob(int row, int col) {
240        acquireReference();
241        try {
242            return getBlob_native(row - mStartPos, col);
243        } finally {
244            releaseReference();
245        }
246    }
247
248    /**
249     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array.
250     *
251     * <p>If the value is null, then <code>null</code> is returned. If the
252     * type of column <code>col</code> is a string type, then the result
253     * is the array of bytes that make up the internal representation of the
254     * string value. If the type of column <code>col</code> is integral or floating-point,
255     * then an {@link SQLiteException} is thrown.
256     */
257    private native byte[] getBlob_native(int row, int col);
258
259    /**
260     * Checks if a field contains either a blob or is null.
261     *
262     * @param row the row to read from, row - getStartPosition() being the actual row in the window
263     * @param col the column to read from
264     * @return {@code true} if given field is {@code NULL} or a blob
265     */
266    public boolean isBlob(int row, int col) {
267        acquireReference();
268        try {
269            return isBlob_native(row - mStartPos, col);
270        } finally {
271            releaseReference();
272        }
273    }
274
275    /**
276     * Checks if a field contains a long
277     *
278     * @param row the row to read from, row - getStartPosition() being the actual row in the window
279     * @param col the column to read from
280     * @return {@code true} if given field is a long
281     */
282    public boolean isLong(int row, int col) {
283        acquireReference();
284        try {
285            return isInteger_native(row - mStartPos, col);
286        } finally {
287            releaseReference();
288        }
289    }
290
291    /**
292     * Checks if a field contains a float.
293     *
294     * @param row the row to read from, row - getStartPosition() being the actual row in the window
295     * @param col the column to read from
296     * @return {@code true} if given field is a float
297     */
298    public boolean isFloat(int row, int col) {
299        acquireReference();
300        try {
301            return isFloat_native(row - mStartPos, col);
302        } finally {
303            releaseReference();
304        }
305    }
306
307    /**
308     * Checks if a field contains either a String or is null.
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 {@code NULL} or a String
313     */
314    public boolean isString(int row, int col) {
315        acquireReference();
316        try {
317            return isString_native(row - mStartPos, col);
318        } finally {
319            releaseReference();
320        }
321    }
322
323    private native boolean isBlob_native(int row, int col);
324    private native boolean isString_native(int row, int col);
325    private native boolean isInteger_native(int row, int col);
326    private native boolean isFloat_native(int row, int col);
327
328    /**
329     * Returns a String for the given field.
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 a String value for the given field
334     */
335    public String getString(int row, int col) {
336        acquireReference();
337        try {
338            return getString_native(row - mStartPos, col);
339        } finally {
340            releaseReference();
341        }
342    }
343
344    /**
345     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>.
346     *
347     * <p>If the value is null, then <code>null</code> is returned. If the
348     * type of column <code>col</code> is integral, then the result is the string
349     * that is obtained by formatting the integer value with the <code>printf</code>
350     * family of functions using format specifier <code>%lld</code>. If the
351     * type of column <code>col</code> is floating-point, then the result is the string
352     * that is obtained by formatting the floating-point value with the
353     * <code>printf</code> family of functions using format specifier <code>%g</code>.
354     * If the type of column <code>col</code> is a blob type, then an
355     * {@link SQLiteException} is thrown.
356     */
357    private native String getString_native(int row, int col);
358
359    /**
360     * copy the text for the given field in the provided char array.
361     *
362     * @param row the row to read from, row - getStartPosition() being the actual row in the window
363     * @param col the column to read from
364     * @param buffer the CharArrayBuffer to copy the text into,
365     * If the requested string is larger than the buffer
366     * a new char buffer will be created to hold the string. and assigne to
367     * CharArrayBuffer.data
368      */
369    public void copyStringToBuffer(int row, int col, CharArrayBuffer buffer) {
370        if (buffer == null) {
371            throw new IllegalArgumentException("CharArrayBuffer should not be null");
372        }
373        if (buffer.data == null) {
374            buffer.data = new char[64];
375        }
376        acquireReference();
377        try {
378            char[] newbuf = copyStringToBuffer_native(
379                    row - mStartPos, col, buffer.data.length, buffer);
380            if (newbuf != null) {
381                buffer.data = newbuf;
382            }
383        } finally {
384            releaseReference();
385        }
386    }
387
388    private native char[] copyStringToBuffer_native(
389            int row, int col, int bufferSize, CharArrayBuffer buffer);
390
391    /**
392     * Returns a long for the given field.
393     * row is 0 based
394     *
395     * @param row the row to read from, row - getStartPosition() being the actual row in the window
396     * @param col the column to read from
397     * @return a long value for the given field
398     */
399    public long getLong(int row, int col) {
400        acquireReference();
401        try {
402            return getLong_native(row - mStartPos, col);
403        } finally {
404            releaseReference();
405        }
406    }
407
408    /**
409     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>.
410     *
411     * <p>If the value is null, then <code>0L</code> is returned. If the
412     * type of column <code>col</code> is a string type, then the result
413     * is the <code>long</code> that is obtained by parsing the string value with
414     * <code>strtoll</code>. If the type of column <code>col</code> is
415     * floating-point, then the result is the floating-point value casted to a <code>long</code>.
416     * If the type of column <code>col</code> is a blob type, then an
417     * {@link SQLiteException} is thrown.
418     */
419    private native long getLong_native(int row, int col);
420
421    /**
422     * Returns a double for the given field.
423     * row is 0 based
424     *
425     * @param row the row to read from, row - getStartPosition() being the actual row in the window
426     * @param col the column to read from
427     * @return a double value for the given field
428     */
429    public double getDouble(int row, int col) {
430        acquireReference();
431        try {
432            return getDouble_native(row - mStartPos, col);
433        } finally {
434            releaseReference();
435        }
436    }
437
438    /**
439     * Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>.
440     *
441     * <p>If the value is null, then <code>0.0</code> is returned. If the
442     * type of column <code>col</code> is a string type, then the result
443     * is the <code>double</code> that is obtained by parsing the string value with
444     * <code>strtod</code>. If the type of column <code>col</code> is
445     * integral, then the result is the integer value casted to a <code>double</code>.
446     * If the type of column <code>col</code> is a blob type, then an
447     * {@link SQLiteException} is thrown.
448     */
449    private native double getDouble_native(int row, int col);
450
451    /**
452     * Returns a short for the given field.
453     * row is 0 based
454     *
455     * @param row the row to read from, row - getStartPosition() being the actual row in the window
456     * @param col the column to read from
457     * @return a short value for the given field
458     */
459    public short getShort(int row, int col) {
460        acquireReference();
461        try {
462            return (short) getLong_native(row - mStartPos, col);
463        } finally {
464            releaseReference();
465        }
466    }
467
468    /**
469     * Returns an int for the given field.
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 an int value for the given field
474     */
475    public int getInt(int row, int col) {
476        acquireReference();
477        try {
478            return (int) getLong_native(row - mStartPos, col);
479        } finally {
480            releaseReference();
481        }
482    }
483
484    /**
485     * Returns a float for the given field.
486     * row is 0 based
487     *
488     * @param row the row to read from, row - getStartPosition() being the actual row in the window
489     * @param col the column to read from
490     * @return a float value for the given field
491     */
492    public float getFloat(int row, int col) {
493        acquireReference();
494        try {
495            return (float) getDouble_native(row - mStartPos, col);
496        } finally {
497            releaseReference();
498        }
499    }
500
501    /**
502     * Clears out the existing contents of the window, making it safe to reuse
503     * for new data. Note that the number of columns in the window may NOT
504     * change across a call to clear().
505     */
506    public void clear() {
507        acquireReference();
508        try {
509            mStartPos = 0;
510            native_clear();
511        } finally {
512            releaseReference();
513        }
514    }
515
516    /** Clears out the native side of things */
517    private native void native_clear();
518
519    /**
520     * Cleans up the native resources associated with the window.
521     */
522    public void close() {
523        releaseReference();
524    }
525
526    private native void close_native();
527
528    @Override
529    protected void finalize() {
530        // Just in case someone forgot to call close...
531        close_native();
532    }
533
534    public static final Parcelable.Creator<CursorWindow> CREATOR
535            = new Parcelable.Creator<CursorWindow>() {
536        public CursorWindow createFromParcel(Parcel source) {
537            return new CursorWindow(source);
538        }
539
540        public CursorWindow[] newArray(int size) {
541            return new CursorWindow[size];
542        }
543    };
544
545    public static CursorWindow newFromParcel(Parcel p) {
546        return CREATOR.createFromParcel(p);
547    }
548
549    public int describeContents() {
550        return 0;
551    }
552
553    public void writeToParcel(Parcel dest, int flags) {
554        dest.writeStrongBinder(native_getBinder());
555        dest.writeInt(mStartPos);
556    }
557
558    private CursorWindow(Parcel source) {
559        IBinder nativeBinder = source.readStrongBinder();
560        mStartPos = source.readInt();
561
562        native_init(nativeBinder);
563    }
564
565    /** Get the binder for the native side of the window */
566    private native IBinder native_getBinder();
567
568    /** Does the native side initialization for an empty window */
569    private native void native_init(boolean localOnly);
570
571    /** Does the native side initialization with an existing binder from another process */
572    private native void native_init(IBinder nativeBinder);
573
574    @Override
575    protected void onAllReferencesReleased() {
576        close_native();
577    }
578}
579