add API to Cursor to get column value type

Change-Id: I3ef1bcdb2eb1c45f68e829ccb6e3ecde28076591
This commit is contained in:
Vasu Nori
2010-05-18 11:54:31 -07:00
parent 3e7432f823
commit 8b0dd7da36
13 changed files with 315 additions and 93 deletions

View File

@@ -55658,6 +55658,19 @@
<parameter name="column" type="int">
</parameter>
</method>
<method name="getType"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="column" type="int">
</parameter>
</method>
<method name="getUpdatedField"
return="java.lang.Object"
abstract="false"
@@ -56681,6 +56694,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getType"
return="int"
abstract="true"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="true"
@@ -56921,6 +56947,61 @@
<parameter name="observer" type="android.database.DataSetObserver">
</parameter>
</method>
<field name="FIELD_TYPE_BLOB"
type="int"
transient="false"
volatile="false"
value="4"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FIELD_TYPE_FLOAT"
type="int"
transient="false"
volatile="false"
value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FIELD_TYPE_INTEGER"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FIELD_TYPE_NULL"
type="int"
transient="false"
volatile="false"
value="0"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="FIELD_TYPE_STRING"
type="int"
transient="false"
volatile="false"
value="3"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</interface>
<class name="CursorIndexOutOfBoundsException"
extends="java.lang.IndexOutOfBoundsException"
@@ -57278,6 +57359,21 @@
<parameter name="col" type="int">
</parameter>
</method>
<method name="getType"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="row" type="int">
</parameter>
<parameter name="col" type="int">
</parameter>
</method>
<method name="isBlob"
return="boolean"
abstract="false"
@@ -57285,7 +57381,7 @@
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -57300,7 +57396,7 @@
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -57315,7 +57411,7 @@
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -57330,7 +57426,7 @@
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -57345,7 +57441,7 @@
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
deprecated="deprecated"
visibility="public"
>
<parameter name="row" type="int">
@@ -57756,6 +57852,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getType"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="false"
@@ -155557,6 +155666,19 @@
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getType"
return="int"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="columnIndex" type="int">
</parameter>
</method>
<method name="getWantsAllOnMoveCalls"
return="boolean"
abstract="false"

View File

@@ -51,6 +51,10 @@ public abstract class AbstractCursor implements CrossProcessCursor {
abstract public double getDouble(int column);
abstract public boolean isNull(int column);
public int getType(int column) {
throw new UnsupportedOperationException();
}
// TODO implement getBlob in all cursor types
public byte[] getBlob(int column) {
throw new UnsupportedOperationException("getBlob is not supported");

View File

@@ -149,63 +149,36 @@ public abstract class AbstractWindowedCursor extends AbstractCursor
}
}
return mWindow.isNull(mPos, columnIndex);
return mWindow.getType(mPos, columnIndex) == Cursor.FIELD_TYPE_NULL;
}
public boolean isBlob(int columnIndex)
public boolean isBlob(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_BLOB;
}
public boolean isString(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_STRING;
}
public boolean isLong(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_INTEGER;
}
public boolean isFloat(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_FLOAT;
}
@Override
public int getType(int columnIndex)
{
checkPosition();
synchronized(mUpdatedRows) {
if (isFieldUpdated(columnIndex)) {
Object object = getUpdatedField(columnIndex);
return object == null || object instanceof byte[];
return DatabaseUtils.getTypeOfObject(getUpdatedField(columnIndex));
}
}
return mWindow.isBlob(mPos, columnIndex);
}
public boolean isString(int columnIndex)
{
checkPosition();
synchronized(mUpdatedRows) {
if (isFieldUpdated(columnIndex)) {
Object object = getUpdatedField(columnIndex);
return object == null || object instanceof String;
}
}
return mWindow.isString(mPos, columnIndex);
}
public boolean isLong(int columnIndex)
{
checkPosition();
synchronized(mUpdatedRows) {
if (isFieldUpdated(columnIndex)) {
Object object = getUpdatedField(columnIndex);
return object != null && (object instanceof Integer || object instanceof Long);
}
}
return mWindow.isLong(mPos, columnIndex);
}
public boolean isFloat(int columnIndex)
{
checkPosition();
synchronized(mUpdatedRows) {
if (isFieldUpdated(columnIndex)) {
Object object = getUpdatedField(columnIndex);
return object != null && (object instanceof Float || object instanceof Double);
}
}
return mWindow.isFloat(mPos, columnIndex);
return mWindow.getType(mPos, columnIndex);
}
@Override

View File

@@ -30,6 +30,25 @@ import java.util.Map;
* threads should perform its own synchronization when using the Cursor.
*/
public interface Cursor {
/*
* Values returned by {@link #getType(int)}.
* These should be consistent with the corresponding types defined in CursorWindow.h
*/
/** Value returned by {@link #getType(int)} if the specified column is null */
static final int FIELD_TYPE_NULL = 0;
/** Value returned by {@link #getType(int)} if the specified column type is integer */
static final int FIELD_TYPE_INTEGER = 1;
/** Value returned by {@link #getType(int)} if the specified column type is float */
static final int FIELD_TYPE_FLOAT = 2;
/** Value returned by {@link #getType(int)} if the specified column type is string */
static final int FIELD_TYPE_STRING = 3;
/** Value returned by {@link #getType(int)} if the specified column type is blob */
static final int FIELD_TYPE_BLOB = 4;
/**
* Returns the numbers of rows in the cursor.
*
@@ -278,6 +297,27 @@ public interface Cursor {
*/
double getDouble(int columnIndex);
/**
* Returns data type of the given column's value.
* The preferred type of the column is returned but the data may be converted to other types
* as documented in the get-type methods such as {@link #getInt(int)}, {@link #getFloat(int)}
* etc.
*<p>
* Returned column types are
* <ul>
* <li>{@link #FIELD_TYPE_NULL}</li>
* <li>{@link #FIELD_TYPE_INTEGER}</li>
* <li>{@link #FIELD_TYPE_FLOAT}</li>
* <li>{@link #FIELD_TYPE_STRING}</li>
* <li>{@link #FIELD_TYPE_BLOB}</li>
*</ul>
*</p>
*
* @param columnIndex the zero-based index of the target column.
* @return column value type
*/
int getType(int columnIndex);
/**
* Returns <code>true</code> if the value in the indicated column is null.
*

View File

@@ -217,14 +217,11 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL}
* @deprecated use {@link #getType(int, int)} instead
*/
@Deprecated
public boolean isNull(int row, int col) {
acquireReference();
try {
return isNull_native(row - mStartPos, col);
} finally {
releaseReference();
}
return getType(row, col) == Cursor.FIELD_TYPE_NULL;
}
private native boolean isNull_native(int row, int col);
@@ -247,20 +244,43 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
private native byte[] getBlob_native(int row, int col);
/**
* Returns data type of the given column's value.
*<p>
* Returned column types are
* <ul>
* <li>{@link Cursor#FIELD_TYPE_NULL}</li>
* <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
* <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
* <li>{@link Cursor#FIELD_TYPE_STRING}</li>
* <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
*</ul>
*</p>
*
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return the value type
*/
public int getType(int row, int col) {
acquireReference();
try {
return getType_native(row - mStartPos, col);
} finally {
releaseReference();
}
}
/**
* Checks if a field contains either a blob or is null.
*
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL} or a blob
* @deprecated use {@link #getType(int, int)} instead
*/
@Deprecated
public boolean isBlob(int row, int col) {
acquireReference();
try {
return isBlob_native(row - mStartPos, col);
} finally {
releaseReference();
}
return getType(row, col) == Cursor.FIELD_TYPE_BLOB;
}
/**
@@ -269,14 +289,11 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is a long
* @deprecated use {@link #getType(int, int)} instead
*/
@Deprecated
public boolean isLong(int row, int col) {
acquireReference();
try {
return isInteger_native(row - mStartPos, col);
} finally {
releaseReference();
}
return getType(row, col) == Cursor.FIELD_TYPE_INTEGER;
}
/**
@@ -285,14 +302,11 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is a float
* @deprecated use {@link #getType(int, int)} instead
*/
@Deprecated
public boolean isFloat(int row, int col) {
acquireReference();
try {
return isFloat_native(row - mStartPos, col);
} finally {
releaseReference();
}
return getType(row, col) == Cursor.FIELD_TYPE_FLOAT;
}
/**
@@ -301,20 +315,18 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
* @param row the row to read from, row - getStartPosition() being the actual row in the window
* @param col the column to read from
* @return {@code true} if given field is {@code NULL} or a String
* @deprecated use {@link #getType(int, int)} instead
*/
@Deprecated
public boolean isString(int row, int col) {
acquireReference();
try {
return isString_native(row - mStartPos, col);
} finally {
releaseReference();
}
return getType(row, col) == Cursor.FIELD_TYPE_STRING;
}
private native boolean isBlob_native(int row, int col);
private native boolean isString_native(int row, int col);
private native boolean isInteger_native(int row, int col);
private native boolean isFloat_native(int row, int col);
private native int getType_native(int row, int col);
/**
* Returns a String for the given field.

View File

@@ -130,6 +130,10 @@ public class CursorWrapper implements Cursor {
return mCursor.isLast();
}
public int getType(int columnIndex) {
return mCursor.getType(columnIndex);
}
public boolean isNull(int columnIndex) {
return mCursor.isNull(columnIndex);
}

View File

@@ -192,6 +192,37 @@ public class DatabaseUtils {
}
}
/**
* Returns data type of the given object's value.
*<p>
* Returned values are
* <ul>
* <li>{@link Cursor#FIELD_TYPE_NULL}</li>
* <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
* <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
* <li>{@link Cursor#FIELD_TYPE_STRING}</li>
* <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
*</ul>
*</p>
*
* @param obj the object whose value type is to be returned
* @return object value type
* @hide
*/
public static int getTypeOfObject(Object obj) {
if (obj == null) {
return Cursor.FIELD_TYPE_NULL;
} else if (obj instanceof byte[]) {
return Cursor.FIELD_TYPE_BLOB;
} else if (obj instanceof Float || obj instanceof Double) {
return Cursor.FIELD_TYPE_FLOAT;
} else if (obj instanceof Long || obj instanceof Integer) {
return Cursor.FIELD_TYPE_INTEGER;
} else {
return Cursor.FIELD_TYPE_STRING;
}
}
/**
* Appends an SQL string to the given StringBuilder, including the opening
* and closing single quotes. Any single quotes internal to sqlString will

View File

@@ -271,6 +271,11 @@ public class MatrixCursor extends AbstractCursor {
return Double.parseDouble(value.toString());
}
@Override
public int getType(int column) {
return DatabaseUtils.getTypeOfObject(get(column));
}
@Override
public boolean isNull(int column) {
return get(column) == null;

View File

@@ -128,6 +128,11 @@ public class MergeCursor extends AbstractCursor
return mCursor.getDouble(column);
}
@Override
public int getType(int column) {
return mCursor.getType(column);
}
@Override
public boolean isNull(int column)
{

View File

@@ -217,6 +217,11 @@ public class SortCursor extends AbstractCursor
return mCursor.getDouble(column);
}
@Override
public int getType(int column) {
return mCursor.getType(column);
}
@Override
public boolean isNull(int column)
{

View File

@@ -652,6 +652,22 @@ static void freeLastRow(JNIEnv * env, jobject object) {
window->freeLastRow();
}
static jint getType_native(JNIEnv* env, jobject object, jint row, jint column)
{
int32_t err;
CursorWindow * window = GET_WINDOW(env, object);
LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window);
field_slot_t field;
err = window->read_field_slot(row, column, &field);
if (err != 0) {
throwExceptionWithRowCol(env, row, column);
return NULL;
}
return field.type;
}
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
@@ -679,6 +695,7 @@ static JNINativeMethod sMethods[] =
{"isString_native", "(II)Z", (void *)isString_native},
{"isFloat_native", "(II)Z", (void *)isFloat_native},
{"isInteger_native", "(II)Z", (void *)isInteger_native},
{"getType_native", "(II)I", (void *)getType_native},
};
int register_android_database_CursorWindow(JNIEnv * env)

View File

@@ -1,16 +1,16 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -80,11 +80,11 @@ typedef struct
} data;
} __attribute__((packed)) field_slot_t;
#define FIELD_TYPE_NULL 0
#define FIELD_TYPE_INTEGER 1
#define FIELD_TYPE_FLOAT 2
#define FIELD_TYPE_STRING 3
#define FIELD_TYPE_BLOB 4
#define FIELD_TYPE_NULL 5
/**
* This class stores a set of rows from a database in a buffer. The begining of the
@@ -170,7 +170,7 @@ public:
row_slot_t * allocRowSlot();
row_slot_t * getRowSlot(int row);
/**
* return NULL if Failed to find rowSlot or
* Invalid rowSlot

View File

@@ -191,4 +191,8 @@ public class MockCursor implements Cursor {
public void unregisterDataSetObserver(DataSetObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
public int getType(int columnIndex) {
throw new UnsupportedOperationException("unimplemented mock method");
}
}