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