diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/database | |
parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/database')
45 files changed, 0 insertions, 9816 deletions
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java deleted file mode 100644 index 76f0860..0000000 --- a/core/java/android/database/AbstractCursor.java +++ /dev/null @@ -1,636 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.content.ContentResolver; -import android.net.Uri; -import android.util.Config; -import android.util.Log; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; - -import java.lang.ref.WeakReference; -import java.lang.UnsupportedOperationException; -import java.util.HashMap; -import java.util.Map; - - -/** - * This is an abstract cursor class that handles a lot of the common code - * that all cursors need to deal with and is provided for convenience reasons. - */ -public abstract class AbstractCursor implements CrossProcessCursor { - private static final String TAG = "Cursor"; - - DataSetObservable mDataSetObservable = new DataSetObservable(); - ContentObservable mContentObservable = new ContentObservable(); - - /* -------------------------------------------------------- */ - /* These need to be implemented by subclasses */ - abstract public int getCount(); - - abstract public String[] getColumnNames(); - - abstract public String getString(int column); - abstract public short getShort(int column); - abstract public int getInt(int column); - abstract public long getLong(int column); - abstract public float getFloat(int column); - abstract public double getDouble(int column); - abstract public boolean isNull(int column); - - // TODO implement getBlob in all cursor types - public byte[] getBlob(int column) { - throw new UnsupportedOperationException("getBlob is not supported"); - } - /* -------------------------------------------------------- */ - /* Methods that may optionally be implemented by subclasses */ - - /** - * returns a pre-filled window, return NULL if no such window - */ - public CursorWindow getWindow() { - return null; - } - - public int getColumnCount() { - return getColumnNames().length; - } - - public void deactivate() { - deactivateInternal(); - } - - /** - * @hide - */ - public void deactivateInternal() { - if (mSelfObserver != null) { - mContentResolver.unregisterContentObserver(mSelfObserver); - mSelfObserverRegistered = false; - } - mDataSetObservable.notifyInvalidated(); - } - - public boolean requery() { - if (mSelfObserver != null && mSelfObserverRegistered == false) { - mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver); - mSelfObserverRegistered = true; - } - mDataSetObservable.notifyChanged(); - return true; - } - - public boolean isClosed() { - return mClosed; - } - - public void close() { - mClosed = true; - mContentObservable.unregisterAll(); - deactivateInternal(); - } - - /** - * @hide - * @deprecated - */ - public boolean commitUpdates(Map<? extends Long,? extends Map<String,Object>> values) { - return false; - } - - /** - * @hide - * @deprecated - */ - public boolean deleteRow() { - return false; - } - - /** - * This function is called every time the cursor is successfully scrolled - * to a new position, giving the subclass a chance to update any state it - * may have. If it returns false the move function will also do so and the - * cursor will scroll to the beforeFirst position. - * - * @param oldPosition the position that we're moving from - * @param newPosition the position that we're moving to - * @return true if the move is successful, false otherwise - */ - public boolean onMove(int oldPosition, int newPosition) { - return true; - } - - - public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { - // Default implementation, uses getString - String result = getString(columnIndex); - if (result != null) { - char[] data = buffer.data; - if (data == null || data.length < result.length()) { - buffer.data = result.toCharArray(); - } else { - result.getChars(0, result.length(), data, 0); - } - buffer.sizeCopied = result.length(); - } - } - - /* -------------------------------------------------------- */ - /* Implementation */ - public AbstractCursor() { - mPos = -1; - mRowIdColumnIndex = -1; - mCurrentRowID = null; - mUpdatedRows = new HashMap<Long, Map<String, Object>>(); - } - - public final int getPosition() { - return mPos; - } - - public final boolean moveToPosition(int position) { - // Make sure position isn't past the end of the cursor - final int count = getCount(); - if (position >= count) { - mPos = count; - return false; - } - - // Make sure position isn't before the beginning of the cursor - if (position < 0) { - mPos = -1; - return false; - } - - // Check for no-op moves, and skip the rest of the work for them - if (position == mPos) { - return true; - } - - boolean result = onMove(mPos, position); - if (result == false) { - mPos = -1; - } else { - mPos = position; - if (mRowIdColumnIndex != -1) { - mCurrentRowID = Long.valueOf(getLong(mRowIdColumnIndex)); - } - } - - return result; - } - - /** - * Copy data from cursor to CursorWindow - * @param position start position of data - * @param window - */ - public void fillWindow(int position, CursorWindow window) { - if (position < 0 || position > getCount()) { - return; - } - window.acquireReference(); - try { - int oldpos = mPos; - mPos = position - 1; - window.clear(); - window.setStartPosition(position); - int columnNum = getColumnCount(); - window.setNumColumns(columnNum); - while (moveToNext() && window.allocRow()) { - for (int i = 0; i < columnNum; i++) { - String field = getString(i); - if (field != null) { - if (!window.putString(field, mPos, i)) { - window.freeLastRow(); - break; - } - } else { - if (!window.putNull(mPos, i)) { - window.freeLastRow(); - break; - } - } - } - } - - mPos = oldpos; - } catch (IllegalStateException e){ - // simply ignore it - } finally { - window.releaseReference(); - } - } - - public final boolean move(int offset) { - return moveToPosition(mPos + offset); - } - - public final boolean moveToFirst() { - return moveToPosition(0); - } - - public final boolean moveToLast() { - return moveToPosition(getCount() - 1); - } - - public final boolean moveToNext() { - return moveToPosition(mPos + 1); - } - - public final boolean moveToPrevious() { - return moveToPosition(mPos - 1); - } - - public final boolean isFirst() { - return mPos == 0 && getCount() != 0; - } - - public final boolean isLast() { - int cnt = getCount(); - return mPos == (cnt - 1) && cnt != 0; - } - - public final boolean isBeforeFirst() { - if (getCount() == 0) { - return true; - } - return mPos == -1; - } - - public final boolean isAfterLast() { - if (getCount() == 0) { - return true; - } - return mPos == getCount(); - } - - public int getColumnIndex(String columnName) { - // Hack according to bug 903852 - final int periodIndex = columnName.lastIndexOf('.'); - if (periodIndex != -1) { - Exception e = new Exception(); - Log.e(TAG, "requesting column name with table name -- " + columnName, e); - columnName = columnName.substring(periodIndex + 1); - } - - String columnNames[] = getColumnNames(); - int length = columnNames.length; - for (int i = 0; i < length; i++) { - if (columnNames[i].equalsIgnoreCase(columnName)) { - return i; - } - } - - if (Config.LOGV) { - if (getCount() > 0) { - Log.w("AbstractCursor", "Unknown column " + columnName); - } - } - return -1; - } - - public int getColumnIndexOrThrow(String columnName) { - final int index = getColumnIndex(columnName); - if (index < 0) { - throw new IllegalArgumentException("column '" + columnName + "' does not exist"); - } - return index; - } - - public String getColumnName(int columnIndex) { - return getColumnNames()[columnIndex]; - } - - /** - * @hide - * @deprecated - */ - public boolean updateBlob(int columnIndex, byte[] value) { - return update(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateString(int columnIndex, String value) { - return update(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateShort(int columnIndex, short value) { - return update(columnIndex, Short.valueOf(value)); - } - - /** - * @hide - * @deprecated - */ - public boolean updateInt(int columnIndex, int value) { - return update(columnIndex, Integer.valueOf(value)); - } - - /** - * @hide - * @deprecated - */ - public boolean updateLong(int columnIndex, long value) { - return update(columnIndex, Long.valueOf(value)); - } - - /** - * @hide - * @deprecated - */ - public boolean updateFloat(int columnIndex, float value) { - return update(columnIndex, Float.valueOf(value)); - } - - /** - * @hide - * @deprecated - */ - public boolean updateDouble(int columnIndex, double value) { - return update(columnIndex, Double.valueOf(value)); - } - - /** - * @hide - * @deprecated - */ - public boolean updateToNull(int columnIndex) { - return update(columnIndex, null); - } - - /** - * @hide - * @deprecated - */ - public boolean update(int columnIndex, Object obj) { - if (!supportsUpdates()) { - return false; - } - - // Long.valueOf() returns null sometimes! -// Long rowid = Long.valueOf(getLong(mRowIdColumnIndex)); - Long rowid = new Long(getLong(mRowIdColumnIndex)); - if (rowid == null) { - throw new IllegalStateException("null rowid. mRowIdColumnIndex = " + mRowIdColumnIndex); - } - - synchronized(mUpdatedRows) { - Map<String, Object> row = mUpdatedRows.get(rowid); - if (row == null) { - row = new HashMap<String, Object>(); - mUpdatedRows.put(rowid, row); - } - row.put(getColumnNames()[columnIndex], obj); - } - - return true; - } - - /** - * Returns <code>true</code> if there are pending updates that have not yet been committed. - * - * @return <code>true</code> if there are pending updates that have not yet been committed. - * @hide - * @deprecated - */ - public boolean hasUpdates() { - synchronized(mUpdatedRows) { - return mUpdatedRows.size() > 0; - } - } - - /** - * @hide - * @deprecated - */ - public void abortUpdates() { - synchronized(mUpdatedRows) { - mUpdatedRows.clear(); - } - } - - /** - * @hide - * @deprecated - */ - public boolean commitUpdates() { - return commitUpdates(null); - } - - /** - * @hide - * @deprecated - */ - public boolean supportsUpdates() { - return mRowIdColumnIndex != -1; - } - - public void registerContentObserver(ContentObserver observer) { - mContentObservable.registerObserver(observer); - } - - public void unregisterContentObserver(ContentObserver observer) { - // cursor will unregister all observers when it close - if (!mClosed) { - mContentObservable.unregisterObserver(observer); - } - } - - /** - * @hide pending API council approval - */ - protected void notifyDataSetChange() { - mDataSetObservable.notifyChanged(); - } - - /** - * @hide pending API council approval - */ - protected DataSetObservable getDataSetObservable() { - return mDataSetObservable; - - } - public void registerDataSetObserver(DataSetObserver observer) { - mDataSetObservable.registerObserver(observer); - - } - - public void unregisterDataSetObserver(DataSetObserver observer) { - mDataSetObservable.unregisterObserver(observer); - } - - /** - * Subclasses must call this method when they finish committing updates to notify all - * observers. - * - * @param selfChange - */ - protected void onChange(boolean selfChange) { - synchronized (mSelfObserverLock) { - mContentObservable.dispatchChange(selfChange); - if (mNotifyUri != null && selfChange) { - mContentResolver.notifyChange(mNotifyUri, mSelfObserver); - } - } - } - - /** - * Specifies a content URI to watch for changes. - * - * @param cr The content resolver from the caller's context. - * @param notifyUri The URI to watch for changes. This can be a - * specific row URI, or a base URI for a whole class of content. - */ - public void setNotificationUri(ContentResolver cr, Uri notifyUri) { - synchronized (mSelfObserverLock) { - mNotifyUri = notifyUri; - mContentResolver = cr; - if (mSelfObserver != null) { - mContentResolver.unregisterContentObserver(mSelfObserver); - } - mSelfObserver = new SelfContentObserver(this); - mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver); - mSelfObserverRegistered = true; - } - } - - public boolean getWantsAllOnMoveCalls() { - return false; - } - - public Bundle getExtras() { - return Bundle.EMPTY; - } - - public Bundle respond(Bundle extras) { - return Bundle.EMPTY; - } - - /** - * This function returns true if the field has been updated and is - * used in conjunction with {@link #getUpdatedField} to allow subclasses to - * support reading uncommitted updates. NOTE: This function and - * {@link #getUpdatedField} should be called together inside of a - * block synchronized on mUpdatedRows. - * - * @param columnIndex the column index of the field to check - * @return true if the field has been updated, false otherwise - */ - protected boolean isFieldUpdated(int columnIndex) { - if (mRowIdColumnIndex != -1 && mUpdatedRows.size() > 0) { - Map<String, Object> updates = mUpdatedRows.get(mCurrentRowID); - if (updates != null && updates.containsKey(getColumnNames()[columnIndex])) { - return true; - } - } - return false; - } - - /** - * This function returns the uncommitted updated value for the field - * at columnIndex. NOTE: This function and {@link #isFieldUpdated} should - * be called together inside of a block synchronized on mUpdatedRows. - * - * @param columnIndex the column index of the field to retrieve - * @return the updated value - */ - protected Object getUpdatedField(int columnIndex) { - Map<String, Object> updates = mUpdatedRows.get(mCurrentRowID); - return updates.get(getColumnNames()[columnIndex]); - } - - /** - * This function throws CursorIndexOutOfBoundsException if - * the cursor position is out of bounds. Subclass implementations of - * the get functions should call this before attempting - * to retrieve data. - * - * @throws CursorIndexOutOfBoundsException - */ - protected void checkPosition() { - if (-1 == mPos || getCount() == mPos) { - throw new CursorIndexOutOfBoundsException(mPos, getCount()); - } - } - - @Override - protected void finalize() { - if (mSelfObserver != null && mSelfObserverRegistered == true) { - mContentResolver.unregisterContentObserver(mSelfObserver); - } - } - - /** - * Cursors use this class to track changes others make to their URI. - */ - protected static class SelfContentObserver extends ContentObserver { - WeakReference<AbstractCursor> mCursor; - - public SelfContentObserver(AbstractCursor cursor) { - super(null); - mCursor = new WeakReference<AbstractCursor>(cursor); - } - - @Override - public boolean deliverSelfNotifications() { - return false; - } - - @Override - public void onChange(boolean selfChange) { - AbstractCursor cursor = mCursor.get(); - if (cursor != null) { - cursor.onChange(false); - } - } - } - - /** - * This HashMap contains a mapping from Long rowIDs to another Map - * that maps from String column names to new values. A NULL value means to - * remove an existing value, and all numeric values are in their class - * forms, i.e. Integer, Long, Float, etc. - */ - protected HashMap<Long, Map<String, Object>> mUpdatedRows; - - /** - * This must be set to the index of the row ID column by any - * subclass that wishes to support updates. - */ - protected int mRowIdColumnIndex; - - protected int mPos; - protected Long mCurrentRowID; - protected ContentResolver mContentResolver; - protected boolean mClosed = false; - private Uri mNotifyUri; - private ContentObserver mSelfObserver; - final private Object mSelfObserverLock = new Object(); - private boolean mSelfObserverRegistered; -} diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java deleted file mode 100644 index 4ac0aef..0000000 --- a/core/java/android/database/AbstractWindowedCursor.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * A base class for Cursors that store their data in {@link CursorWindow}s. - */ -public abstract class AbstractWindowedCursor extends AbstractCursor -{ - @Override - public byte[] getBlob(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - return (byte[])getUpdatedField(columnIndex); - } - } - - return mWindow.getBlob(mPos, columnIndex); - } - - @Override - public String getString(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - return (String)getUpdatedField(columnIndex); - } - } - - return mWindow.getString(mPos, columnIndex); - } - - @Override - public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - super.copyStringToBuffer(columnIndex, buffer); - } - } - - mWindow.copyStringToBuffer(mPos, columnIndex, buffer); - } - - @Override - public short getShort(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Number value = (Number)getUpdatedField(columnIndex); - return value.shortValue(); - } - } - - return mWindow.getShort(mPos, columnIndex); - } - - @Override - public int getInt(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Number value = (Number)getUpdatedField(columnIndex); - return value.intValue(); - } - } - - return mWindow.getInt(mPos, columnIndex); - } - - @Override - public long getLong(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Number value = (Number)getUpdatedField(columnIndex); - return value.longValue(); - } - } - - return mWindow.getLong(mPos, columnIndex); - } - - @Override - public float getFloat(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Number value = (Number)getUpdatedField(columnIndex); - return value.floatValue(); - } - } - - return mWindow.getFloat(mPos, columnIndex); - } - - @Override - public double getDouble(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Number value = (Number)getUpdatedField(columnIndex); - return value.doubleValue(); - } - } - - return mWindow.getDouble(mPos, columnIndex); - } - - @Override - public boolean isNull(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - return getUpdatedField(columnIndex) == null; - } - } - - return mWindow.isNull(mPos, columnIndex); - } - - public boolean isBlob(int columnIndex) - { - checkPosition(); - - synchronized(mUpdatedRows) { - if (isFieldUpdated(columnIndex)) { - Object object = getUpdatedField(columnIndex); - return object == null || object instanceof byte[]; - } - } - - return mWindow.isBlob(mPos, columnIndex); - } - - @Override - protected void checkPosition() - { - super.checkPosition(); - - if (mWindow == null) { - throw new StaleDataException("Access closed cursor"); - } - } - - @Override - public CursorWindow getWindow() { - return mWindow; - } - - /** - * Set a new cursor window to cursor, usually set a remote cursor window - * @param window cursor window - */ - public void setWindow(CursorWindow window) { - if (mWindow != null) { - mWindow.close(); - } - mWindow = window; - } - - public boolean hasWindow() { - return mWindow != null; - } - - /** - * This needs be updated in {@link #onMove} by subclasses, and - * needs to be set to NULL when the contents of the cursor change. - */ - protected CursorWindow mWindow; -} diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java deleted file mode 100644 index baa94d8..0000000 --- a/core/java/android/database/BulkCursorNative.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.os.Binder; -import android.os.RemoteException; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Bundle; - -import java.util.HashMap; -import java.util.Map; - -/** - * Native implementation of the bulk cursor. This is only for use in implementing - * IPC, application code should use the Cursor interface. - * - * {@hide} - */ -public abstract class BulkCursorNative extends Binder implements IBulkCursor -{ - public BulkCursorNative() - { - attachInterface(this, descriptor); - } - - /** - * Cast a Binder object into a content resolver interface, generating - * a proxy if needed. - */ - static public IBulkCursor asInterface(IBinder obj) - { - if (obj == null) { - return null; - } - IBulkCursor in = (IBulkCursor)obj.queryLocalInterface(descriptor); - if (in != null) { - return in; - } - - return new BulkCursorProxy(obj); - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - try { - switch (code) { - case GET_CURSOR_WINDOW_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - int startPos = data.readInt(); - CursorWindow window = getWindow(startPos); - if (window == null) { - reply.writeInt(0); - return true; - } - reply.writeNoException(); - reply.writeInt(1); - window.writeToParcel(reply, 0); - return true; - } - - case COUNT_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - int count = count(); - reply.writeNoException(); - reply.writeInt(count); - return true; - } - - case GET_COLUMN_NAMES_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - String[] columnNames = getColumnNames(); - reply.writeNoException(); - reply.writeInt(columnNames.length); - int length = columnNames.length; - for (int i = 0; i < length; i++) { - reply.writeString(columnNames[i]); - } - return true; - } - - case DEACTIVATE_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - deactivate(); - reply.writeNoException(); - return true; - } - - case CLOSE_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - close(); - reply.writeNoException(); - return true; - } - - case REQUERY_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - IContentObserver observer = - IContentObserver.Stub.asInterface(data.readStrongBinder()); - CursorWindow window = CursorWindow.CREATOR.createFromParcel(data); - int count = requery(observer, window); - reply.writeNoException(); - reply.writeInt(count); - reply.writeBundle(getExtras()); - return true; - } - - case UPDATE_ROWS_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - // TODO - what ClassLoader should be passed to readHashMap? - // TODO - switch to Bundle - HashMap<Long, Map<String, Object>> values = data.readHashMap(null); - boolean result = updateRows(values); - reply.writeNoException(); - reply.writeInt((result == true ? 1 : 0)); - return true; - } - - case DELETE_ROW_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - int position = data.readInt(); - boolean result = deleteRow(position); - reply.writeNoException(); - reply.writeInt((result == true ? 1 : 0)); - return true; - } - - case ON_MOVE_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - int position = data.readInt(); - onMove(position); - reply.writeNoException(); - return true; - } - - case WANTS_ON_MOVE_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - boolean result = getWantsAllOnMoveCalls(); - reply.writeNoException(); - reply.writeInt(result ? 1 : 0); - return true; - } - - case GET_EXTRAS_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - Bundle extras = getExtras(); - reply.writeNoException(); - reply.writeBundle(extras); - return true; - } - - case RESPOND_TRANSACTION: { - data.enforceInterface(IBulkCursor.descriptor); - Bundle extras = data.readBundle(); - Bundle returnExtras = respond(extras); - reply.writeNoException(); - reply.writeBundle(returnExtras); - return true; - } - } - } catch (Exception e) { - DatabaseUtils.writeExceptionToParcel(reply, e); - return true; - } - - return super.onTransact(code, data, reply, flags); - } - - public IBinder asBinder() - { - return this; - } -} - - -final class BulkCursorProxy implements IBulkCursor { - private IBinder mRemote; - private Bundle mExtras; - - public BulkCursorProxy(IBinder remote) - { - mRemote = remote; - mExtras = null; - } - - public IBinder asBinder() - { - return mRemote; - } - - public CursorWindow getWindow(int startPos) throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeInt(startPos); - - mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - CursorWindow window = null; - if (reply.readInt() == 1) { - window = CursorWindow.newFromParcel(reply); - } - - data.recycle(); - reply.recycle(); - - return window; - } - - public void onMove(int position) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeInt(position); - - mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); - } - - public int count() throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - boolean result = mRemote.transact(COUNT_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - int count; - if (result == false) { - count = -1; - } else { - count = reply.readInt(); - } - data.recycle(); - reply.recycle(); - return count; - } - - public String[] getColumnNames() throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(GET_COLUMN_NAMES_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - String[] columnNames = null; - int numColumns = reply.readInt(); - columnNames = new String[numColumns]; - for (int i = 0; i < numColumns; i++) { - columnNames[i] = reply.readString(); - } - - data.recycle(); - reply.recycle(); - return columnNames; - } - - public void deactivate() throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0); - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); - } - - public void close() throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(CLOSE_TRANSACTION, data, reply, 0); - DatabaseUtils.readExceptionFromParcel(reply); - - data.recycle(); - reply.recycle(); - } - - public int requery(IContentObserver observer, CursorWindow window) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeStrongInterface(observer); - window.writeToParcel(data, 0); - - boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - int count; - if (!result) { - count = -1; - } else { - count = reply.readInt(); - mExtras = reply.readBundle(); - } - - data.recycle(); - reply.recycle(); - - return count; - } - - public boolean updateRows(Map values) throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeMap(values); - - mRemote.transact(UPDATE_ROWS_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - boolean result = (reply.readInt() == 1 ? true : false); - - data.recycle(); - reply.recycle(); - - return result; - } - - public boolean deleteRow(int position) throws RemoteException - { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeInt(position); - - mRemote.transact(DELETE_ROW_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - boolean result = (reply.readInt() == 1 ? true : false); - - data.recycle(); - reply.recycle(); - - return result; - } - - public boolean getWantsAllOnMoveCalls() throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(WANTS_ON_MOVE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - int result = reply.readInt(); - data.recycle(); - reply.recycle(); - return result != 0; - } - - public Bundle getExtras() throws RemoteException { - if (mExtras == null) { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - mExtras = reply.readBundle(); - data.recycle(); - reply.recycle(); - } - return mExtras; - } - - public Bundle respond(Bundle extras) throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IBulkCursor.descriptor); - - data.writeBundle(extras); - - mRemote.transact(RESPOND_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionFromParcel(reply); - - Bundle returnExtras = reply.readBundle(); - data.recycle(); - reply.recycle(); - return returnExtras; - } -} - diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java deleted file mode 100644 index c26810a..0000000 --- a/core/java/android/database/BulkCursorToCursorAdaptor.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.os.RemoteException; -import android.os.Bundle; -import android.util.Log; - -import java.util.Map; - -/** - * Adapts an {@link IBulkCursor} to a {@link Cursor} for use in the local - * process. - * - * {@hide} - */ -public final class BulkCursorToCursorAdaptor extends AbstractWindowedCursor { - private static final String TAG = "BulkCursor"; - - private SelfContentObserver mObserverBridge; - private IBulkCursor mBulkCursor; - private int mCount; - private String[] mColumns; - private boolean mWantsAllOnMoveCalls; - - public void set(IBulkCursor bulkCursor) { - mBulkCursor = bulkCursor; - - try { - mCount = mBulkCursor.count(); - mWantsAllOnMoveCalls = mBulkCursor.getWantsAllOnMoveCalls(); - - // Search for the rowID column index and set it for our parent - mColumns = mBulkCursor.getColumnNames(); - int length = mColumns.length; - for (int i = 0; i < length; i++) { - if (mColumns[i].equals("_id")) { - mRowIdColumnIndex = i; - break; - } - } - } catch (RemoteException ex) { - Log.e(TAG, "Setup failed because the remote process is dead"); - } - } - - /** - * Gets a SelfDataChangeOberserver that can be sent to a remote - * process to receive change notifications over IPC. - * - * @return A SelfContentObserver hooked up to this Cursor - */ - public synchronized IContentObserver getObserver() { - if (mObserverBridge == null) { - mObserverBridge = new SelfContentObserver(this); - } - return mObserverBridge.getContentObserver(); - } - - @Override - public int getCount() { - return mCount; - } - - @Override - public boolean onMove(int oldPosition, int newPosition) { - try { - // Make sure we have the proper window - if (mWindow != null) { - if (newPosition < mWindow.getStartPosition() || - newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) { - mWindow = mBulkCursor.getWindow(newPosition); - } else if (mWantsAllOnMoveCalls) { - mBulkCursor.onMove(newPosition); - } - } else { - mWindow = mBulkCursor.getWindow(newPosition); - } - } catch (RemoteException ex) { - // We tried to get a window and failed - Log.e(TAG, "Unable to get window because the remote process is dead"); - return false; - } - - // Couldn't obtain a window, something is wrong - if (mWindow == null) { - return false; - } - - return true; - } - - @Override - public void deactivate() { - // This will call onInvalidated(), so make sure to do it before calling release, - // which is what actually makes the data set invalid. - super.deactivate(); - - try { - mBulkCursor.deactivate(); - } catch (RemoteException ex) { - Log.w(TAG, "Remote process exception when deactivating"); - } - mWindow = null; - } - - @Override - public void close() { - super.close(); - try { - mBulkCursor.close(); - } catch (RemoteException ex) { - Log.w(TAG, "Remote process exception when closing"); - } - mWindow = null; - } - - @Override - public boolean requery() { - try { - int oldCount = mCount; - //TODO get the window from a pool somewhere to avoid creating the memory dealer - mCount = mBulkCursor.requery(getObserver(), new CursorWindow( - false /* the window will be accessed across processes */)); - if (mCount != -1) { - mPos = -1; - mWindow = null; - - // super.requery() will call onChanged. Do it here instead of relying on the - // observer from the far side so that observers can see a correct value for mCount - // when responding to onChanged. - super.requery(); - return true; - } else { - deactivate(); - return false; - } - } catch (Exception ex) { - Log.e(TAG, "Unable to requery because the remote process exception " + ex.getMessage()); - deactivate(); - return false; - } - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean deleteRow() { - try { - boolean result = mBulkCursor.deleteRow(mPos); - if (result != false) { - // The window contains the old value, discard it - mWindow = null; - - // Fix up the position - mCount = mBulkCursor.count(); - if (mPos < mCount) { - int oldPos = mPos; - mPos = -1; - moveToPosition(oldPos); - } else { - mPos = mCount; - } - - // Send the change notification - onChange(true); - } - return result; - } catch (RemoteException ex) { - Log.e(TAG, "Unable to delete row because the remote process is dead"); - return false; - } - } - - @Override - public String[] getColumnNames() { - return mColumns; - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean commitUpdates(Map<? extends Long, - ? extends Map<String,Object>> additionalValues) { - if (!supportsUpdates()) { - Log.e(TAG, "commitUpdates not supported on this cursor, did you include the _id column?"); - return false; - } - - synchronized(mUpdatedRows) { - if (additionalValues != null) { - mUpdatedRows.putAll(additionalValues); - } - - if (mUpdatedRows.size() <= 0) { - return false; - } - - try { - boolean result = mBulkCursor.updateRows(mUpdatedRows); - - if (result == true) { - mUpdatedRows.clear(); - - // Send the change notification - onChange(true); - } - return result; - } catch (RemoteException ex) { - Log.e(TAG, "Unable to commit updates because the remote process is dead"); - return false; - } - } - } - - @Override - public Bundle getExtras() { - try { - return mBulkCursor.getExtras(); - } catch (RemoteException e) { - // This should never happen because the system kills processes that are using remote - // cursors when the provider process is killed. - throw new RuntimeException(e); - } - } - - @Override - public Bundle respond(Bundle extras) { - try { - return mBulkCursor.respond(extras); - } catch (RemoteException e) { - // This should never happen because the system kills processes that are using remote - // cursors when the provider process is killed. - throw new RuntimeException(e); - } - } -} - diff --git a/core/java/android/database/CharArrayBuffer.java b/core/java/android/database/CharArrayBuffer.java deleted file mode 100644 index 73781b7..0000000 --- a/core/java/android/database/CharArrayBuffer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * This is used for {@link Cursor#copyStringToBuffer} - */ -public final class CharArrayBuffer { - public CharArrayBuffer(int size) { - data = new char[size]; - } - - public CharArrayBuffer(char[] buf) { - data = buf; - } - - public char[] data; // In and out parameter - public int sizeCopied; // Out parameter -} diff --git a/core/java/android/database/ContentObservable.java b/core/java/android/database/ContentObservable.java deleted file mode 100644 index 8d7b7c5..0000000 --- a/core/java/android/database/ContentObservable.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * A specialization of Observable for ContentObserver that provides methods for - * invoking the various callback methods of ContentObserver. - */ -public class ContentObservable extends Observable<ContentObserver> { - - @Override - public void registerObserver(ContentObserver observer) { - super.registerObserver(observer); - } - - /** - * invokes dispatchUpdate on each observer, unless the observer doesn't want - * self-notifications and the update is from a self-notification - * @param selfChange - */ - public void dispatchChange(boolean selfChange) { - synchronized(mObservers) { - for (ContentObserver observer : mObservers) { - if (!selfChange || observer.deliverSelfNotifications()) { - observer.dispatchChange(selfChange); - } - } - } - } - - /** - * invokes onChange on each observer - * @param selfChange - */ - public void notifyChange(boolean selfChange) { - synchronized(mObservers) { - for (ContentObserver observer : mObservers) { - observer.onChange(selfChange); - } - } - } -} diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java deleted file mode 100644 index 3b829a3..0000000 --- a/core/java/android/database/ContentObserver.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.os.Handler; - -/** - * Receives call backs for changes to content. Must be implemented by objects which are added - * to a {@link ContentObservable}. - */ -public abstract class ContentObserver { - - private Transport mTransport; - - // Protects mTransport - private Object lock = new Object(); - - /* package */ Handler mHandler; - - private final class NotificationRunnable implements Runnable { - - private boolean mSelf; - - public NotificationRunnable(boolean self) { - mSelf = self; - } - - public void run() { - ContentObserver.this.onChange(mSelf); - } - } - - private static final class Transport extends IContentObserver.Stub { - ContentObserver mContentObserver; - - public Transport(ContentObserver contentObserver) { - mContentObserver = contentObserver; - } - - public boolean deliverSelfNotifications() { - ContentObserver contentObserver = mContentObserver; - if (contentObserver != null) { - return contentObserver.deliverSelfNotifications(); - } - return false; - } - - public void onChange(boolean selfChange) { - ContentObserver contentObserver = mContentObserver; - if (contentObserver != null) { - contentObserver.dispatchChange(selfChange); - } - } - - public void releaseContentObserver() { - mContentObserver = null; - } - } - - /** - * onChange() will happen on the provider Handler. - * - * @param handler The handler to run {@link #onChange} on. - */ - public ContentObserver(Handler handler) { - mHandler = handler; - } - - /** - * Gets access to the binder transport object. Not for public consumption. - * - * {@hide} - */ - public IContentObserver getContentObserver() { - synchronized(lock) { - if (mTransport == null) { - mTransport = new Transport(this); - } - return mTransport; - } - } - - /** - * Gets access to the binder transport object, and unlinks the transport object - * from the ContentObserver. Not for public consumption. - * - * {@hide} - */ - public IContentObserver releaseContentObserver() { - synchronized(lock) { - Transport oldTransport = mTransport; - if (oldTransport != null) { - oldTransport.releaseContentObserver(); - mTransport = null; - } - return oldTransport; - } - } - - /** - * Returns true if this observer is interested in notifications for changes - * made through the cursor the observer is registered with. - */ - public boolean deliverSelfNotifications() { - return false; - } - - /** - * This method is called when a change occurs to the cursor that - * is being observed. - * - * @param selfChange true if the update was caused by a call to <code>commit</code> on the - * cursor that is being observed. - */ - public void onChange(boolean selfChange) {} - - public final void dispatchChange(boolean selfChange) { - if (mHandler == null) { - onChange(selfChange); - } else { - mHandler.post(new NotificationRunnable(selfChange)); - } - } -} diff --git a/core/java/android/database/CrossProcessCursor.java b/core/java/android/database/CrossProcessCursor.java deleted file mode 100644 index 77ba3a5..0000000 --- a/core/java/android/database/CrossProcessCursor.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -public interface CrossProcessCursor extends Cursor{ - /** - * returns a pre-filled window, return NULL if no such window - */ - CursorWindow getWindow(); - - /** - * copies cursor data into the window start at pos - */ - void fillWindow(int pos, CursorWindow winow); - - /** - * This function is called every time the cursor is successfully scrolled - * to a new position, giving the subclass a chance to update any state it - * may have. If it returns false the move function will also do so and the - * cursor will scroll to the beforeFirst position. - * - * @param oldPosition the position that we're moving from - * @param newPosition the position that we're moving to - * @return true if the move is successful, false otherwise - */ - boolean onMove(int oldPosition, int newPosition); - -} diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java deleted file mode 100644 index 79178f4..0000000 --- a/core/java/android/database/Cursor.java +++ /dev/null @@ -1,587 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.content.ContentResolver; -import android.net.Uri; -import android.os.Bundle; - -import java.util.Map; - -/** - * This interface provides random read-write access to the result set returned - * by a database query. - */ -public interface Cursor { - /** - * Returns the numbers of rows in the cursor. - * - * @return the number of rows in the cursor. - */ - int getCount(); - - /** - * Returns the current position of the cursor in the row set. - * The value is zero-based. When the row set is first returned the cursor - * will be at positon -1, which is before the first row. After the - * last row is returned another call to next() will leave the cursor past - * the last entry, at a position of count(). - * - * @return the current cursor position. - */ - int getPosition(); - - /** - * Move the cursor by a relative amount, forward or backward, from the - * current position. Positive offsets move forwards, negative offsets move - * backwards. If the final position is outside of the bounds of the result - * set then the resultant position will be pinned to -1 or count() depending - * on whether the value is off the front or end of the set, respectively. - * - * <p>This method will return true if the requested destination was - * reachable, otherwise, it returns false. For example, if the cursor is at - * currently on the second entry in the result set and move(-5) is called, - * the position will be pinned at -1, and false will be returned. - * - * @param offset the offset to be applied from the current position. - * @return whether the requested move fully succeeded. - */ - boolean move(int offset); - - /** - * Move the cursor to an absolute position. The valid - * range of values is -1 <= position <= count. - * - * <p>This method will return true if the request destination was reachable, - * otherwise, it returns false. - * - * @param position the zero-based position to move to. - * @return whether the requested move fully succeeded. - */ - boolean moveToPosition(int position); - - /** - * Move the cursor to the first row. - * - * <p>This method will return false if the cursor is empty. - * - * @return whether the move succeeded. - */ - boolean moveToFirst(); - - /** - * Move the cursor to the last row. - * - * <p>This method will return false if the cursor is empty. - * - * @return whether the move succeeded. - */ - boolean moveToLast(); - - /** - * Move the cursor to the next row. - * - * <p>This method will return false if the cursor is already past the - * last entry in the result set. - * - * @return whether the move succeeded. - */ - boolean moveToNext(); - - /** - * Move the cursor to the previous row. - * - * <p>This method will return false if the cursor is already before the - * first entry in the result set. - * - * @return whether the move succeeded. - */ - boolean moveToPrevious(); - - /** - * Returns whether the cursor is pointing to the first row. - * - * @return whether the cursor is pointing at the first entry. - */ - boolean isFirst(); - - /** - * Returns whether the cursor is pointing to the last row. - * - * @return whether the cursor is pointing at the last entry. - */ - boolean isLast(); - - /** - * Returns whether the cursor is pointing to the position before the first - * row. - * - * @return whether the cursor is before the first result. - */ - boolean isBeforeFirst(); - - /** - * Returns whether the cursor is pointing to the position after the last - * row. - * - * @return whether the cursor is after the last result. - */ - boolean isAfterLast(); - - /** - * Removes the row at the current cursor position from the underlying data - * store. After this method returns the cursor will be pointing to the row - * after the row that is deleted. This has the side effect of decrementing - * the result of count() by one. - * <p> - * The query must have the row ID column in its selection, otherwise this - * call will fail. - * - * @hide - * @return whether the record was successfully deleted. - * @deprecated use {@link ContentResolver#delete(Uri, String, String[])} - */ - @Deprecated - boolean deleteRow(); - - /** - * Returns the zero-based index for the given column name, or -1 if the column doesn't exist. - * If you expect the column to exist use {@link #getColumnIndexOrThrow(String)} instead, which - * will make the error more clear. - * - * @param columnName the name of the target column. - * @return the zero-based column index for the given column name, or -1 if - * the column name does not exist. - * @see #getColumnIndexOrThrow(String) - */ - int getColumnIndex(String columnName); - - /** - * Returns the zero-based index for the given column name, or throws - * {@link IllegalArgumentException} if the column doesn't exist. If you're not sure if - * a column will exist or not use {@link #getColumnIndex(String)} and check for -1, which - * is more efficient than catching the exceptions. - * - * @param columnName the name of the target column. - * @return the zero-based column index for the given column name - * @see #getColumnIndex(String) - * @throws IllegalArgumentException if the column does not exist - */ - int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException; - - /** - * Returns the column name at the given zero-based column index. - * - * @param columnIndex the zero-based index of the target column. - * @return the column name for the given column index. - */ - String getColumnName(int columnIndex); - - /** - * Returns a string array holding the names of all of the columns in the - * result set in the order in which they were listed in the result. - * - * @return the names of the columns returned in this query. - */ - String[] getColumnNames(); - - /** - * Return total number of columns - * @return number of columns - */ - int getColumnCount(); - - /** - * Returns the value of the requested column as a byte array. - * - * <p>If the native content of that column is not blob exception may throw - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a byte array. - */ - byte[] getBlob(int columnIndex); - - /** - * Returns the value of the requested column as a String. - * - * <p>If the native content of that column is not text the result will be - * the result of passing the column value to String.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a String. - */ - String getString(int columnIndex); - - /** - * Retrieves the requested column text and stores it in the buffer provided. - * If the buffer size is not sufficient, a new char buffer will be allocated - * and assigned to CharArrayBuffer.data - * @param columnIndex the zero-based index of the target column. - * if the target column is null, return buffer - * @param buffer the buffer to copy the text into. - */ - void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer); - - /** - * Returns the value of the requested column as a short. - * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Short.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a short. - */ - short getShort(int columnIndex); - - /** - * Returns the value of the requested column as an int. - * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Integer.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as an int. - */ - int getInt(int columnIndex); - - /** - * Returns the value of the requested column as a long. - * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Long.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a long. - */ - long getLong(int columnIndex); - - /** - * Returns the value of the requested column as a float. - * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Float.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a float. - */ - float getFloat(int columnIndex); - - /** - * Returns the value of the requested column as a double. - * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Double.valueOf(x). - * - * @param columnIndex the zero-based index of the target column. - * @return the value of that column as a double. - */ - double getDouble(int columnIndex); - - /** - * Returns <code>true</code> if the value in the indicated column is null. - * - * @param columnIndex the zero-based index of the target column. - * @return whether the column value is null. - */ - boolean isNull(int columnIndex); - - /** - * Returns <code>true</code> if the cursor supports updates. - * - * @return whether the cursor supports updates. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean supportsUpdates(); - - /** - * Returns <code>true</code> if there are pending updates that have not yet been committed. - * - * @return <code>true</code> if there are pending updates that have not yet been committed. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean hasUpdates(); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateBlob(int columnIndex, byte[] value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateString(int columnIndex, String value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateShort(int columnIndex, short value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateInt(int columnIndex, int value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateLong(int columnIndex, long value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateFloat(int columnIndex, float value); - - /** - * Updates the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @param value the new value. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateDouble(int columnIndex, double value); - - /** - * Removes the value for the given column in the row the cursor is - * currently pointing at. Updates are not committed to the backing store - * until {@link #commitUpdates()} is called. - * - * @param columnIndex the zero-based index of the target column. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean updateToNull(int columnIndex); - - /** - * Atomically commits all updates to the backing store. After completion, - * this method leaves the data in an inconsistent state and you should call - * {@link #requery} before reading data from the cursor again. - * - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean commitUpdates(); - - /** - * Atomically commits all updates to the backing store, as well as the - * updates included in values. After completion, - * this method leaves the data in an inconsistent state and you should call - * {@link #requery} before reading data from the cursor again. - * - * @param values A map from row IDs to Maps associating column names with - * updated values. A null value indicates the field should be - removed. - * @return whether the operation succeeded. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - boolean commitUpdates(Map<? extends Long, - ? extends Map<String,Object>> values); - - /** - * Reverts all updates made to the cursor since the last call to - * commitUpdates. - * @hide - * @deprecated use the {@link ContentResolver} update methods instead of the Cursor - * update methods - */ - @Deprecated - void abortUpdates(); - - /** - * Deactivates the Cursor, making all calls on it fail until {@link #requery} is called. - * Inactive Cursors use fewer resources than active Cursors. - * Calling {@link #requery} will make the cursor active again. - */ - void deactivate(); - - /** - * Performs the query that created the cursor again, refreshing its - * contents. This may be done at any time, including after a call to {@link - * #deactivate}. - * - * @return true if the requery succeeded, false if not, in which case the - * cursor becomes invalid. - */ - boolean requery(); - - /** - * Closes the Cursor, releasing all of its resources and making it completely invalid. - * Unlike {@link #deactivate()} a call to {@link #requery()} will not make the Cursor valid - * again. - */ - void close(); - - /** - * return true if the cursor is closed - * @return true if the cursor is closed. - */ - boolean isClosed(); - - /** - * Register an observer that is called when changes happen to the content backing this cursor. - * Typically the data set won't change until {@link #requery()} is called. - * - * @param observer the object that gets notified when the content backing the cursor changes. - * @see #unregisterContentObserver(ContentObserver) - */ - void registerContentObserver(ContentObserver observer); - - /** - * Unregister an observer that has previously been registered with this - * cursor via {@link #registerContentObserver}. - * - * @param observer the object to unregister. - * @see #registerContentObserver(ContentObserver) - */ - void unregisterContentObserver(ContentObserver observer); - - /** - * Register an observer that is called when changes happen to the contents - * of the this cursors data set, for example, when the data set is changed via - * {@link #requery()}, {@link #deactivate()}, or {@link #close()}. - * - * @param observer the object that gets notified when the cursors data set changes. - * @see #unregisterDataSetObserver(DataSetObserver) - */ - void registerDataSetObserver(DataSetObserver observer); - - /** - * Unregister an observer that has previously been registered with this - * cursor via {@link #registerContentObserver}. - * - * @param observer the object to unregister. - * @see #registerDataSetObserver(DataSetObserver) - */ - void unregisterDataSetObserver(DataSetObserver observer); - - /** - * Register to watch a content URI for changes. This can be the URI of a specific data row (for - * example, "content://my_provider_type/23"), or a a generic URI for a content type. - * - * @param cr The content resolver from the caller's context. The listener attached to - * this resolver will be notified. - * @param uri The content URI to watch. - */ - void setNotificationUri(ContentResolver cr, Uri uri); - - /** - * onMove() will only be called across processes if this method returns true. - * @return whether all cursor movement should result in a call to onMove(). - */ - boolean getWantsAllOnMoveCalls(); - - /** - * Returns a bundle of extra values. This is an optional way for cursors to provide out-of-band - * metadata to their users. One use of this is for reporting on the progress of network requests - * that are required to fetch data for the cursor. - * - * <p>These values may only change when requery is called. - * @return cursor-defined values, or Bundle.EMTPY if there are no values. Never null. - */ - Bundle getExtras(); - - /** - * This is an out-of-band way for the the user of a cursor to communicate with the cursor. The - * structure of each bundle is entirely defined by the cursor. - * - * <p>One use of this is to tell a cursor that it should retry its network request after it - * reported an error. - * @param extras extra values, or Bundle.EMTPY. Never null. - * @return extra values, or Bundle.EMTPY. Never null. - */ - Bundle respond(Bundle extras); -} diff --git a/core/java/android/database/CursorIndexOutOfBoundsException.java b/core/java/android/database/CursorIndexOutOfBoundsException.java deleted file mode 100644 index 1f77d00..0000000 --- a/core/java/android/database/CursorIndexOutOfBoundsException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * An exception indicating that a cursor is out of bounds. - */ -public class CursorIndexOutOfBoundsException extends IndexOutOfBoundsException { - - public CursorIndexOutOfBoundsException(int index, int size) { - super("Index " + index + " requested, with a size of " + size); - } - - public CursorIndexOutOfBoundsException(String message) { - super(message); - } -} diff --git a/core/java/android/database/CursorJoiner.java b/core/java/android/database/CursorJoiner.java deleted file mode 100644 index e3c2988..0000000 --- a/core/java/android/database/CursorJoiner.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import java.util.Iterator; - -/** - * Does a join on two cursors using the specified columns. The cursors must already - * be sorted on each of the specified columns in ascending order. This joiner only - * supports the case where the tuple of key column values is unique. - * <p> - * Typical usage: - * - * <pre> - * CursorJoiner joiner = new CursorJoiner(cursorA, keyColumnsofA, cursorB, keyColumnsofB); - * for (CursorJointer.Result joinerResult : joiner) { - * switch (joinerResult) { - * case LEFT: - * // handle case where a row in cursorA is unique - * break; - * case RIGHT: - * // handle case where a row in cursorB is unique - * break; - * case BOTH: - * // handle case where a row with the same key is in both cursors - * break; - * } - * } - * </pre> - */ -public final class CursorJoiner - implements Iterator<CursorJoiner.Result>, Iterable<CursorJoiner.Result> { - private Cursor mCursorLeft; - private Cursor mCursorRight; - private boolean mCompareResultIsValid; - private Result mCompareResult; - private int[] mColumnsLeft; - private int[] mColumnsRight; - private String[] mValues; - - /** - * The result of a call to next(). - */ - public enum Result { - /** The row currently pointed to by the left cursor is unique */ - RIGHT, - /** The row currently pointed to by the right cursor is unique */ - LEFT, - /** The rows pointed to by both cursors are the same */ - BOTH - } - - /** - * Initializes the CursorJoiner and resets the cursors to the first row. The left and right - * column name arrays must have the same number of columns. - * @param cursorLeft The left cursor to compare - * @param columnNamesLeft The column names to compare from the left cursor - * @param cursorRight The right cursor to compare - * @param columnNamesRight The column names to compare from the right cursor - */ - public CursorJoiner( - Cursor cursorLeft, String[] columnNamesLeft, - Cursor cursorRight, String[] columnNamesRight) { - if (columnNamesLeft.length != columnNamesRight.length) { - throw new IllegalArgumentException( - "you must have the same number of columns on the left and right, " - + columnNamesLeft.length + " != " + columnNamesRight.length); - } - - mCursorLeft = cursorLeft; - mCursorRight = cursorRight; - - mCursorLeft.moveToFirst(); - mCursorRight.moveToFirst(); - - mCompareResultIsValid = false; - - mColumnsLeft = buildColumnIndiciesArray(cursorLeft, columnNamesLeft); - mColumnsRight = buildColumnIndiciesArray(cursorRight, columnNamesRight); - - mValues = new String[mColumnsLeft.length * 2]; - } - - public Iterator<Result> iterator() { - return this; - } - - /** - * Lookup the indicies of the each column name and return them in an array. - * @param cursor the cursor that contains the columns - * @param columnNames the array of names to lookup - * @return an array of column indices - */ - private int[] buildColumnIndiciesArray(Cursor cursor, String[] columnNames) { - int[] columns = new int[columnNames.length]; - for (int i = 0; i < columnNames.length; i++) { - columns[i] = cursor.getColumnIndexOrThrow(columnNames[i]); - } - return columns; - } - - /** - * Returns whether or not there are more rows to compare using next(). - * @return true if there are more rows to compare - */ - public boolean hasNext() { - if (mCompareResultIsValid) { - switch (mCompareResult) { - case BOTH: - return !mCursorLeft.isLast() || !mCursorRight.isLast(); - - case LEFT: - return !mCursorLeft.isLast() || !mCursorRight.isAfterLast(); - - case RIGHT: - return !mCursorLeft.isAfterLast() || !mCursorRight.isLast(); - - default: - throw new IllegalStateException("bad value for mCompareResult, " - + mCompareResult); - } - } else { - return !mCursorLeft.isAfterLast() || !mCursorRight.isAfterLast(); - } - } - - /** - * Returns the comparison result of the next row from each cursor. If one cursor - * has no more rows but the other does then subsequent calls to this will indicate that - * the remaining rows are unique. - * <p> - * The caller must check that hasNext() returns true before calling this. - * <p> - * Once next() has been called the cursors specified in the result of the call to - * next() are guaranteed to point to the row that was indicated. Reading values - * from the cursor that was not indicated in the call to next() will result in - * undefined behavior. - * @return LEFT, if the row pointed to by the left cursor is unique, RIGHT - * if the row pointed to by the right cursor is unique, BOTH if the rows in both - * cursors are the same. - */ - public Result next() { - if (!hasNext()) { - throw new IllegalStateException("you must only call next() when hasNext() is true"); - } - incrementCursors(); - assert hasNext(); - - boolean hasLeft = !mCursorLeft.isAfterLast(); - boolean hasRight = !mCursorRight.isAfterLast(); - - if (hasLeft && hasRight) { - populateValues(mValues, mCursorLeft, mColumnsLeft, 0 /* start filling at index 0 */); - populateValues(mValues, mCursorRight, mColumnsRight, 1 /* start filling at index 1 */); - switch (compareStrings(mValues)) { - case -1: - mCompareResult = Result.LEFT; - break; - case 0: - mCompareResult = Result.BOTH; - break; - case 1: - mCompareResult = Result.RIGHT; - break; - } - } else if (hasLeft) { - mCompareResult = Result.LEFT; - } else { - assert hasRight; - mCompareResult = Result.RIGHT; - } - mCompareResultIsValid = true; - return mCompareResult; - } - - public void remove() { - throw new UnsupportedOperationException("not implemented"); - } - - /** - * Reads the strings from the cursor that are specifed in the columnIndicies - * array and saves them in values beginning at startingIndex, skipping a slot - * for each value. If columnIndicies has length 3 and startingIndex is 1, the - * values will be stored in slots 1, 3, and 5. - * @param values the String[] to populate - * @param cursor the cursor from which to read - * @param columnIndicies the indicies of the values to read from the cursor - * @param startingIndex the slot in which to start storing values, and must be either 0 or 1. - */ - private static void populateValues(String[] values, Cursor cursor, int[] columnIndicies, - int startingIndex) { - assert startingIndex == 0 || startingIndex == 1; - for (int i = 0; i < columnIndicies.length; i++) { - values[startingIndex + i*2] = cursor.getString(columnIndicies[i]); - } - } - - /** - * Increment the cursors past the rows indicated in the most recent call to next(). - * This will only have an affect once per call to next(). - */ - private void incrementCursors() { - if (mCompareResultIsValid) { - switch (mCompareResult) { - case LEFT: - mCursorLeft.moveToNext(); - break; - case RIGHT: - mCursorRight.moveToNext(); - break; - case BOTH: - mCursorLeft.moveToNext(); - mCursorRight.moveToNext(); - break; - } - mCompareResultIsValid = false; - } - } - - /** - * Compare the values. Values contains n pairs of strings. If all the pairs of strings match - * then returns 0. Otherwise returns the comparison result of the first non-matching pair - * of values, -1 if the first of the pair is less than the second of the pair or 1 if it - * is greater. - * @param values the n pairs of values to compare - * @return -1, 0, or 1 as described above. - */ - private static int compareStrings(String... values) { - if ((values.length % 2) != 0) { - throw new IllegalArgumentException("you must specify an even number of values"); - } - - for (int index = 0; index < values.length; index+=2) { - if (values[index] == null) { - if (values[index+1] == null) continue; - return -1; - } - - if (values[index+1] == null) { - return 1; - } - - int comp = values[index].compareTo(values[index+1]); - if (comp != 0) { - return comp < 0 ? -1 : 1; - } - } - - return 0; - } -} diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java deleted file mode 100644 index 19ad946..0000000 --- a/core/java/android/database/CursorToBulkCursorAdaptor.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.database.sqlite.SQLiteMisuseException; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Config; -import android.util.Log; - -import java.util.Map; - - -/** - * Wraps a BulkCursor around an existing Cursor making it remotable. - * - * {@hide} - */ -public final class CursorToBulkCursorAdaptor extends BulkCursorNative - implements IBinder.DeathRecipient { - private static final String TAG = "Cursor"; - private final CrossProcessCursor mCursor; - private CursorWindow mWindow; - private final String mProviderName; - private final boolean mReadOnly; - private ContentObserverProxy mObserver; - - private static final class ContentObserverProxy extends ContentObserver - { - protected IContentObserver mRemote; - - public ContentObserverProxy(IContentObserver remoteObserver, DeathRecipient recipient) { - super(null); - mRemote = remoteObserver; - try { - remoteObserver.asBinder().linkToDeath(recipient, 0); - } catch (RemoteException e) { - // Do nothing, the far side is dead - } - } - - public boolean unlinkToDeath(DeathRecipient recipient) { - return mRemote.asBinder().unlinkToDeath(recipient, 0); - } - - @Override - public boolean deliverSelfNotifications() { - // The far side handles the self notifications. - return false; - } - - @Override - public void onChange(boolean selfChange) { - try { - mRemote.onChange(selfChange); - } catch (RemoteException ex) { - // Do nothing, the far side is dead - } - } - } - - public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer, String providerName, - boolean allowWrite, CursorWindow window) { - try { - mCursor = (CrossProcessCursor) cursor; - if (mCursor instanceof AbstractWindowedCursor) { - AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor) cursor; - if (windowedCursor.hasWindow()) { - if (Log.isLoggable(TAG, Log.VERBOSE) || Config.LOGV) { - Log.v(TAG, "Cross process cursor has a local window before setWindow in " - + providerName, new RuntimeException()); - } - } - windowedCursor.setWindow(window); - } else { - mWindow = window; - mCursor.fillWindow(0, window); - } - } catch (ClassCastException e) { - // TODO Implement this case. - throw new UnsupportedOperationException( - "Only CrossProcessCursor cursors are supported across process for now", e); - } - mProviderName = providerName; - mReadOnly = !allowWrite; - - createAndRegisterObserverProxy(observer); - } - - public void binderDied() { - mCursor.close(); - if (mWindow != null) { - mWindow.close(); - } - } - - public CursorWindow getWindow(int startPos) { - mCursor.moveToPosition(startPos); - - if (mWindow != null) { - if (startPos < mWindow.getStartPosition() || - startPos >= (mWindow.getStartPosition() + mWindow.getNumRows())) { - mCursor.fillWindow(startPos, mWindow); - } - return mWindow; - } else { - return ((AbstractWindowedCursor)mCursor).getWindow(); - } - } - - public void onMove(int position) { - mCursor.onMove(mCursor.getPosition(), position); - } - - public int count() { - return mCursor.getCount(); - } - - public String[] getColumnNames() { - return mCursor.getColumnNames(); - } - - public void deactivate() { - maybeUnregisterObserverProxy(); - mCursor.deactivate(); - } - - public void close() { - maybeUnregisterObserverProxy(); - mCursor.deactivate(); - - } - - public int requery(IContentObserver observer, CursorWindow window) { - if (mWindow == null) { - ((AbstractWindowedCursor)mCursor).setWindow(window); - } - try { - if (!mCursor.requery()) { - return -1; - } - } catch (IllegalStateException e) { - IllegalStateException leakProgram = new IllegalStateException( - mProviderName + " Requery misuse db, mCursor isClosed:" + - mCursor.isClosed(), e); - throw leakProgram; - } - - if (mWindow != null) { - mCursor.fillWindow(0, window); - mWindow = window; - } - maybeUnregisterObserverProxy(); - createAndRegisterObserverProxy(observer); - return mCursor.getCount(); - } - - public boolean getWantsAllOnMoveCalls() { - return mCursor.getWantsAllOnMoveCalls(); - } - - /** - * Create a ContentObserver from the observer and register it as an observer on the - * underlying cursor. - * @param observer the IContentObserver that wants to monitor the cursor - * @throws IllegalStateException if an observer is already registered - */ - private void createAndRegisterObserverProxy(IContentObserver observer) { - if (mObserver != null) { - throw new IllegalStateException("an observer is already registered"); - } - mObserver = new ContentObserverProxy(observer, this); - mCursor.registerContentObserver(mObserver); - } - - /** Unregister the observer if it is already registered. */ - private void maybeUnregisterObserverProxy() { - if (mObserver != null) { - mCursor.unregisterContentObserver(mObserver); - mObserver.unlinkToDeath(this); - mObserver = null; - } - } - - public boolean updateRows(Map<? extends Long, ? extends Map<String, Object>> values) { - if (mReadOnly) { - Log.w("ContentProvider", "Permission Denial: modifying " - + mProviderName - + " from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return false; - } - return mCursor.commitUpdates(values); - } - - public boolean deleteRow(int position) { - if (mReadOnly) { - Log.w("ContentProvider", "Permission Denial: modifying " - + mProviderName - + " from pid=" + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return false; - } - if (mCursor.moveToPosition(position) == false) { - return false; - } - return mCursor.deleteRow(); - } - - public Bundle getExtras() { - return mCursor.getExtras(); - } - - public Bundle respond(Bundle extras) { - return mCursor.respond(extras); - } -} diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java deleted file mode 100644 index 8e26730..0000000 --- a/core/java/android/database/CursorWindow.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.database.sqlite.SQLiteClosable; -import android.os.IBinder; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * A buffer containing multiple cursor rows. - */ -public class CursorWindow extends SQLiteClosable implements Parcelable { - /** The pointer to the native window class */ - @SuppressWarnings("unused") - private int nWindow; - - private int mStartPos; - - /** - * Creates a new empty window. - * - * @param localWindow true if this window will be used in this process only - */ - public CursorWindow(boolean localWindow) { - mStartPos = 0; - native_init(localWindow); - } - - /** - * Returns the starting position of this window within the entire - * Cursor's result set. - * - * @return the starting position of this window within the entire - * Cursor's result set. - */ - public int getStartPosition() { - return mStartPos; - } - - /** - * Set the start position of cursor window - * @param pos - */ - public void setStartPosition(int pos) { - mStartPos = pos; - } - - /** - * Returns the number of rows in this window. - * - * @return the number of rows in this window. - */ - public int getNumRows() { - acquireReference(); - try { - return getNumRows_native(); - } finally { - releaseReference(); - } - } - - private native int getNumRows_native(); - /** - * Set number of Columns - * @param columnNum - * @return true if success - */ - public boolean setNumColumns(int columnNum) { - acquireReference(); - try { - return setNumColumns_native(columnNum); - } finally { - releaseReference(); - } - } - - private native boolean setNumColumns_native(int columnNum); - - /** - * Allocate a row in cursor window - * @return false if cursor window is out of memory - */ - public boolean allocRow(){ - acquireReference(); - try { - return allocRow_native(); - } finally { - releaseReference(); - } - } - - private native boolean allocRow_native(); - - /** - * Free the last row - */ - public void freeLastRow(){ - acquireReference(); - try { - freeLastRow_native(); - } finally { - releaseReference(); - } - } - - private native void freeLastRow_native(); - - /** - * copy byte array to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy - */ - public boolean putBlob(byte[] value, int row, int col) { - acquireReference(); - try { - return putBlob_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean putBlob_native(byte[] value, int row, int col); - - /** - * Copy String to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy - */ - public boolean putString(String value, int row, int col) { - acquireReference(); - try { - return putString_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean putString_native(String value, int row, int col); - - /** - * Copy integer to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy - */ - public boolean putLong(long value, int row, int col) { - acquireReference(); - try { - return putLong_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean putLong_native(long value, int row, int col); - - - /** - * Copy double to cursor window - * @param value - * @param row - * @param col - * @return false if fail to copy - */ - public boolean putDouble(double value, int row, int col) { - acquireReference(); - try { - return putDouble_native(value, row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean putDouble_native(double value, int row, int col); - - /** - * Set the [row, col] value to NULL - * @param row - * @param col - * @return false if fail to copy - */ - public boolean putNull(int row, int col) { - acquireReference(); - try { - return putNull_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean putNull_native(int row, int col); - - - /** - * Returns {@code true} if given field is {@code 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} - */ - public boolean isNull(int row, int col) { - acquireReference(); - try { - return isNull_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean isNull_native(int row, int col); - - /** - * Returns a byte array for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a String value for the given field - */ - public byte[] getBlob(int row, int col) { - acquireReference(); - try { - return getBlob_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native byte[] getBlob_native(int row, int col); - - /** - * 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 - */ - public boolean isBlob(int row, int col) { - acquireReference(); - try { - return isBlob_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native boolean isBlob_native(int row, int col); - - /** - * Returns a String for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a String value for the given field - */ - public String getString(int row, int col) { - acquireReference(); - try { - return getString_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native String getString_native(int row, int col); - - /** - * copy the text for the given field in the provided char array. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @param buffer the CharArrayBuffer to copy the text into, - * If the requested string is larger than the buffer - * a new char buffer will be created to hold the string. and assigne to - * CharArrayBuffer.data - */ - public void copyStringToBuffer(int row, int col, CharArrayBuffer buffer) { - if (buffer == null) { - throw new IllegalArgumentException("CharArrayBuffer should not be null"); - } - if (buffer.data == null) { - buffer.data = new char[64]; - } - acquireReference(); - try { - char[] newbuf = copyStringToBuffer_native( - row - mStartPos, col, buffer.data.length, buffer); - if (newbuf != null) { - buffer.data = newbuf; - } - } finally { - releaseReference(); - } - } - - private native char[] copyStringToBuffer_native( - int row, int col, int bufferSize, CharArrayBuffer buffer); - - /** - * Returns a long for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a long value for the given field - */ - public long getLong(int row, int col) { - acquireReference(); - try { - return getLong_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native long getLong_native(int row, int col); - - /** - * Returns a double for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a double value for the given field - */ - public double getDouble(int row, int col) { - acquireReference(); - try { - return getDouble_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - private native double getDouble_native(int row, int col); - - /** - * Returns a short for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a short value for the given field - */ - public short getShort(int row, int col) { - acquireReference(); - try { - return (short) getLong_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - /** - * Returns an int for the given field. - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return an int value for the given field - */ - public int getInt(int row, int col) { - acquireReference(); - try { - return (int) getLong_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - /** - * Returns a float for the given field. - * row is 0 based - * - * @param row the row to read from, row - getStartPosition() being the actual row in the window - * @param col the column to read from - * @return a float value for the given field - */ - public float getFloat(int row, int col) { - acquireReference(); - try { - return (float) getDouble_native(row - mStartPos, col); - } finally { - releaseReference(); - } - } - - /** - * Clears out the existing contents of the window, making it safe to reuse - * for new data. Note that the number of columns in the window may NOT - * change across a call to clear(). - */ - public void clear() { - acquireReference(); - try { - mStartPos = 0; - native_clear(); - } finally { - releaseReference(); - } - } - - /** Clears out the native side of things */ - private native void native_clear(); - - /** - * Cleans up the native resources associated with the window. - */ - public void close() { - releaseReference(); - } - - private native void close_native(); - - @Override - protected void finalize() { - // Just in case someone forgot to call close... - close_native(); - } - - public static final Parcelable.Creator<CursorWindow> CREATOR - = new Parcelable.Creator<CursorWindow>() { - public CursorWindow createFromParcel(Parcel source) { - return new CursorWindow(source); - } - - public CursorWindow[] newArray(int size) { - return new CursorWindow[size]; - } - }; - - public static CursorWindow newFromParcel(Parcel p) { - return CREATOR.createFromParcel(p); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeStrongBinder(native_getBinder()); - dest.writeInt(mStartPos); - } - - private CursorWindow(Parcel source) { - IBinder nativeBinder = source.readStrongBinder(); - mStartPos = source.readInt(); - - native_init(nativeBinder); - } - - /** Get the binder for the native side of the window */ - private native IBinder native_getBinder(); - - /** Does the native side initialization for an empty window */ - private native void native_init(boolean localOnly); - - /** Does the native side initialization with an existing binder from another process */ - private native void native_init(IBinder nativeBinder); - - @Override - protected void onAllReferencesReleased() { - close_native(); - } -} diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java deleted file mode 100644 index f0aa7d7..0000000 --- a/core/java/android/database/CursorWrapper.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.content.ContentResolver; -import android.database.CharArrayBuffer; -import android.net.Uri; -import android.os.Bundle; - -import java.util.Map; - -/** - * Wrapper class for Cursor that delegates all calls to the actual cursor object - */ - -public class CursorWrapper implements Cursor { - - public CursorWrapper(Cursor cursor) { - mCursor = cursor; - } - - /** - * @hide - * @deprecated - */ - public void abortUpdates() { - mCursor.abortUpdates(); - } - - public void close() { - mCursor.close(); - } - - public boolean isClosed() { - return mCursor.isClosed(); - } - - /** - * @hide - * @deprecated - */ - public boolean commitUpdates() { - return mCursor.commitUpdates(); - } - - /** - * @hide - * @deprecated - */ - public boolean commitUpdates( - Map<? extends Long, ? extends Map<String, Object>> values) { - return mCursor.commitUpdates(values); - } - - public int getCount() { - return mCursor.getCount(); - } - - public void deactivate() { - mCursor.deactivate(); - } - - /** - * @hide - * @deprecated - */ - public boolean deleteRow() { - return mCursor.deleteRow(); - } - - public boolean moveToFirst() { - return mCursor.moveToFirst(); - } - - public int getColumnCount() { - return mCursor.getColumnCount(); - } - - public int getColumnIndex(String columnName) { - return mCursor.getColumnIndex(columnName); - } - - public int getColumnIndexOrThrow(String columnName) - throws IllegalArgumentException { - return mCursor.getColumnIndexOrThrow(columnName); - } - - public String getColumnName(int columnIndex) { - return mCursor.getColumnName(columnIndex); - } - - public String[] getColumnNames() { - return mCursor.getColumnNames(); - } - - public double getDouble(int columnIndex) { - return mCursor.getDouble(columnIndex); - } - - public Bundle getExtras() { - return mCursor.getExtras(); - } - - public float getFloat(int columnIndex) { - return mCursor.getFloat(columnIndex); - } - - public int getInt(int columnIndex) { - return mCursor.getInt(columnIndex); - } - - public long getLong(int columnIndex) { - return mCursor.getLong(columnIndex); - } - - public short getShort(int columnIndex) { - return mCursor.getShort(columnIndex); - } - - public String getString(int columnIndex) { - return mCursor.getString(columnIndex); - } - - public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { - mCursor.copyStringToBuffer(columnIndex, buffer); - } - - public byte[] getBlob(int columnIndex) { - return mCursor.getBlob(columnIndex); - } - - public boolean getWantsAllOnMoveCalls() { - return mCursor.getWantsAllOnMoveCalls(); - } - - /** - * @hide - * @deprecated - */ - public boolean hasUpdates() { - return mCursor.hasUpdates(); - } - - public boolean isAfterLast() { - return mCursor.isAfterLast(); - } - - public boolean isBeforeFirst() { - return mCursor.isBeforeFirst(); - } - - public boolean isFirst() { - return mCursor.isFirst(); - } - - public boolean isLast() { - return mCursor.isLast(); - } - - public boolean isNull(int columnIndex) { - return mCursor.isNull(columnIndex); - } - - public boolean moveToLast() { - return mCursor.moveToLast(); - } - - public boolean move(int offset) { - return mCursor.move(offset); - } - - public boolean moveToPosition(int position) { - return mCursor.moveToPosition(position); - } - - public boolean moveToNext() { - return mCursor.moveToNext(); - } - - public int getPosition() { - return mCursor.getPosition(); - } - - public boolean moveToPrevious() { - return mCursor.moveToPrevious(); - } - - public void registerContentObserver(ContentObserver observer) { - mCursor.registerContentObserver(observer); - } - - public void registerDataSetObserver(DataSetObserver observer) { - mCursor.registerDataSetObserver(observer); - } - - public boolean requery() { - return mCursor.requery(); - } - - public Bundle respond(Bundle extras) { - return mCursor.respond(extras); - } - - public void setNotificationUri(ContentResolver cr, Uri uri) { - mCursor.setNotificationUri(cr, uri); - } - - /** - * @hide - * @deprecated - */ - public boolean supportsUpdates() { - return mCursor.supportsUpdates(); - } - - public void unregisterContentObserver(ContentObserver observer) { - mCursor.unregisterContentObserver(observer); - } - - public void unregisterDataSetObserver(DataSetObserver observer) { - mCursor.unregisterDataSetObserver(observer); - } - - /** - * @hide - * @deprecated - */ - public boolean updateDouble(int columnIndex, double value) { - return mCursor.updateDouble(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateFloat(int columnIndex, float value) { - return mCursor.updateFloat(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateInt(int columnIndex, int value) { - return mCursor.updateInt(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateLong(int columnIndex, long value) { - return mCursor.updateLong(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateShort(int columnIndex, short value) { - return mCursor.updateShort(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateString(int columnIndex, String value) { - return mCursor.updateString(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateBlob(int columnIndex, byte[] value) { - return mCursor.updateBlob(columnIndex, value); - } - - /** - * @hide - * @deprecated - */ - public boolean updateToNull(int columnIndex) { - return mCursor.updateToNull(columnIndex); - } - - private Cursor mCursor; - -} - diff --git a/core/java/android/database/DataSetObservable.java b/core/java/android/database/DataSetObservable.java deleted file mode 100644 index 9200e81..0000000 --- a/core/java/android/database/DataSetObservable.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * A specialization of Observable for DataSetObserver that provides methods for - * invoking the various callback methods of DataSetObserver. - */ -public class DataSetObservable extends Observable<DataSetObserver> { - /** - * Invokes onChanged on each observer. Called when the data set being observed has - * changed, and which when read contains the new state of the data. - */ - public void notifyChanged() { - synchronized(mObservers) { - for (DataSetObserver observer : mObservers) { - observer.onChanged(); - } - } - } - - /** - * Invokes onInvalidated on each observer. Called when the data set being monitored - * has changed such that it is no longer valid. - */ - public void notifyInvalidated() { - synchronized (mObservers) { - for (DataSetObserver observer : mObservers) { - observer.onInvalidated(); - } - } - } -} diff --git a/core/java/android/database/DataSetObserver.java b/core/java/android/database/DataSetObserver.java deleted file mode 100644 index 28616c8..0000000 --- a/core/java/android/database/DataSetObserver.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * Receives call backs when a data set has been changed, or made invalid. The typically data sets - * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s. - * DataSetObserver must be implemented by objects which are added to a DataSetObservable. - */ -public abstract class DataSetObserver { - /** - * This method is called when the entire data set has changed, - * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}. - */ - public void onChanged() { - // Do nothing - } - - /** - * This method is called when the entire data becomes invalid, - * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a - * {@link Cursor}. - */ - public void onInvalidated() { - // Do nothing - } -} diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java deleted file mode 100644 index 10f3806..0000000 --- a/core/java/android/database/DatabaseUtils.java +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import org.apache.commons.codec.binary.Hex; - -import android.content.ContentValues; -import android.content.Context; -import android.database.sqlite.SQLiteAbortException; -import android.database.sqlite.SQLiteConstraintException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDatabaseCorruptException; -import android.database.sqlite.SQLiteDiskIOException; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteFullException; -import android.database.sqlite.SQLiteProgram; -import android.database.sqlite.SQLiteStatement; -import android.os.Parcel; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.io.FileNotFoundException; -import java.io.PrintStream; -import java.text.Collator; -import java.util.HashMap; -import java.util.Map; - -/** - * Static utility methods for dealing with databases and {@link Cursor}s. - */ -public class DatabaseUtils { - private static final String TAG = "DatabaseUtils"; - - private static final boolean DEBUG = false; - private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; - - private static final String[] countProjection = new String[]{"count(*)"}; - - /** - * Special function for writing an exception result at the header of - * a parcel, to be used when returning an exception from a transaction. - * exception will be re-thrown by the function in another process - * @param reply Parcel to write to - * @param e The Exception to be written. - * @see Parcel#writeNoException - * @see Parcel#writeException - */ - public static final void writeExceptionToParcel(Parcel reply, Exception e) { - int code = 0; - boolean logException = true; - if (e instanceof FileNotFoundException) { - code = 1; - logException = false; - } else if (e instanceof IllegalArgumentException) { - code = 2; - } else if (e instanceof UnsupportedOperationException) { - code = 3; - } else if (e instanceof SQLiteAbortException) { - code = 4; - } else if (e instanceof SQLiteConstraintException) { - code = 5; - } else if (e instanceof SQLiteDatabaseCorruptException) { - code = 6; - } else if (e instanceof SQLiteFullException) { - code = 7; - } else if (e instanceof SQLiteDiskIOException) { - code = 8; - } else if (e instanceof SQLiteException) { - code = 9; - } else { - reply.writeException(e); - Log.e(TAG, "Writing exception to parcel", e); - return; - } - reply.writeInt(code); - reply.writeString(e.getMessage()); - - if (logException) { - Log.e(TAG, "Writing exception to parcel", e); - } - } - - /** - * Special function for reading an exception result from the header of - * a parcel, to be used after receiving the result of a transaction. This - * will throw the exception for you if it had been written to the Parcel, - * otherwise return and let you read the normal result data from the Parcel. - * @param reply Parcel to read from - * @see Parcel#writeNoException - * @see Parcel#readException - */ - public static final void readExceptionFromParcel(Parcel reply) { - int code = reply.readInt(); - if (code == 0) return; - String msg = reply.readString(); - DatabaseUtils.readExceptionFromParcel(reply, msg, code); - } - - public static void readExceptionWithFileNotFoundExceptionFromParcel( - Parcel reply) throws FileNotFoundException { - int code = reply.readInt(); - if (code == 0) return; - String msg = reply.readString(); - if (code == 1) { - throw new FileNotFoundException(msg); - } else { - DatabaseUtils.readExceptionFromParcel(reply, msg, code); - } - } - - private static final void readExceptionFromParcel(Parcel reply, String msg, int code) { - switch (code) { - case 2: - throw new IllegalArgumentException(msg); - case 3: - throw new UnsupportedOperationException(msg); - case 4: - throw new SQLiteAbortException(msg); - case 5: - throw new SQLiteConstraintException(msg); - case 6: - throw new SQLiteDatabaseCorruptException(msg); - case 7: - throw new SQLiteFullException(msg); - case 8: - throw new SQLiteDiskIOException(msg); - case 9: - throw new SQLiteException(msg); - default: - reply.readException(code, msg); - } - } - - /** - * Binds the given Object to the given SQLiteProgram using the proper - * typing. For example, bind numbers as longs/doubles, and everything else - * as a string by call toString() on it. - * - * @param prog the program to bind the object to - * @param index the 1-based index to bind at - * @param value the value to bind - */ - public static void bindObjectToProgram(SQLiteProgram prog, int index, - Object value) { - if (value == null) { - prog.bindNull(index); - } else if (value instanceof Double || value instanceof Float) { - prog.bindDouble(index, ((Number)value).doubleValue()); - } else if (value instanceof Number) { - prog.bindLong(index, ((Number)value).longValue()); - } else if (value instanceof Boolean) { - Boolean bool = (Boolean)value; - if (bool) { - prog.bindLong(index, 1); - } else { - prog.bindLong(index, 0); - } - } else if (value instanceof byte[]){ - prog.bindBlob(index, (byte[]) value); - } else { - prog.bindString(index, value.toString()); - } - } - - /** - * Appends an SQL string to the given StringBuilder, including the opening - * and closing single quotes. Any single quotes internal to sqlString will - * be escaped. - * - * This method is deprecated because we want to encourage everyone - * to use the "?" binding form. However, when implementing a - * ContentProvider, one may want to add WHERE clauses that were - * not provided by the caller. Since "?" is a positional form, - * using it in this case could break the caller because the - * indexes would be shifted to accomodate the ContentProvider's - * internal bindings. In that case, it may be necessary to - * construct a WHERE clause manually. This method is useful for - * those cases. - * - * @param sb the StringBuilder that the SQL string will be appended to - * @param sqlString the raw string to be appended, which may contain single - * quotes - */ - public static void appendEscapedSQLString(StringBuilder sb, String sqlString) { - sb.append('\''); - if (sqlString.indexOf('\'') != -1) { - int length = sqlString.length(); - for (int i = 0; i < length; i++) { - char c = sqlString.charAt(i); - if (c == '\'') { - sb.append('\''); - } - sb.append(c); - } - } else - sb.append(sqlString); - sb.append('\''); - } - - /** - * SQL-escape a string. - */ - public static String sqlEscapeString(String value) { - StringBuilder escaper = new StringBuilder(); - - DatabaseUtils.appendEscapedSQLString(escaper, value); - - return escaper.toString(); - } - - /** - * Appends an Object to an SQL string with the proper escaping, etc. - */ - public static final void appendValueToSql(StringBuilder sql, Object value) { - if (value == null) { - sql.append("NULL"); - } else if (value instanceof Boolean) { - Boolean bool = (Boolean)value; - if (bool) { - sql.append('1'); - } else { - sql.append('0'); - } - } else { - appendEscapedSQLString(sql, value.toString()); - } - } - - /** - * Concatenates two SQL WHERE clauses, handling empty or null values. - * @hide - */ - public static String concatenateWhere(String a, String b) { - if (TextUtils.isEmpty(a)) { - return b; - } - if (TextUtils.isEmpty(b)) { - return a; - } - - return "(" + a + ") AND (" + b + ")"; - } - - /** - * return the collation key - * @param name - * @return the collation key - */ - public static String getCollationKey(String name) { - byte [] arr = getCollationKeyInBytes(name); - try { - return new String(arr, 0, getKeyLen(arr), "ISO8859_1"); - } catch (Exception ex) { - return ""; - } - } - - /** - * return the collation key in hex format - * @param name - * @return the collation key in hex format - */ - public static String getHexCollationKey(String name) { - byte [] arr = getCollationKeyInBytes(name); - char[] keys = Hex.encodeHex(arr); - return new String(keys, 0, getKeyLen(arr) * 2); - } - - private static int getKeyLen(byte[] arr) { - if (arr[arr.length - 1] != 0) { - return arr.length; - } else { - // remove zero "termination" - return arr.length-1; - } - } - - private static byte[] getCollationKeyInBytes(String name) { - if (mColl == null) { - mColl = Collator.getInstance(); - mColl.setStrength(Collator.PRIMARY); - } - return mColl.getCollationKey(name).toByteArray(); - } - - private static Collator mColl = null; - /** - * Prints the contents of a Cursor to System.out. The position is restored - * after printing. - * - * @param cursor the cursor to print - */ - public static void dumpCursor(Cursor cursor) { - dumpCursor(cursor, System.out); - } - - /** - * Prints the contents of a Cursor to a PrintSteam. The position is restored - * after printing. - * - * @param cursor the cursor to print - * @param stream the stream to print to - */ - public static void dumpCursor(Cursor cursor, PrintStream stream) { - stream.println(">>>>> Dumping cursor " + cursor); - if (cursor != null) { - int startPos = cursor.getPosition(); - - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - dumpCurrentRow(cursor, stream); - } - cursor.moveToPosition(startPos); - } - stream.println("<<<<<"); - } - - /** - * Prints the contents of a Cursor to a StringBuilder. The position - * is restored after printing. - * - * @param cursor the cursor to print - * @param sb the StringBuilder to print to - */ - public static void dumpCursor(Cursor cursor, StringBuilder sb) { - sb.append(">>>>> Dumping cursor " + cursor + "\n"); - if (cursor != null) { - int startPos = cursor.getPosition(); - - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - dumpCurrentRow(cursor, sb); - } - cursor.moveToPosition(startPos); - } - sb.append("<<<<<\n"); - } - - /** - * Prints the contents of a Cursor to a String. The position is restored - * after printing. - * - * @param cursor the cursor to print - * @return a String that contains the dumped cursor - */ - public static String dumpCursorToString(Cursor cursor) { - StringBuilder sb = new StringBuilder(); - dumpCursor(cursor, sb); - return sb.toString(); - } - - /** - * Prints the contents of a Cursor's current row to System.out. - * - * @param cursor the cursor to print from - */ - public static void dumpCurrentRow(Cursor cursor) { - dumpCurrentRow(cursor, System.out); - } - - /** - * Prints the contents of a Cursor's current row to a PrintSteam. - * - * @param cursor the cursor to print - * @param stream the stream to print to - */ - public static void dumpCurrentRow(Cursor cursor, PrintStream stream) { - String[] cols = cursor.getColumnNames(); - stream.println("" + cursor.getPosition() + " {"); - int length = cols.length; - for (int i = 0; i< length; i++) { - String value; - try { - value = cursor.getString(i); - } catch (SQLiteException e) { - // assume that if the getString threw this exception then the column is not - // representable by a string, e.g. it is a BLOB. - value = "<unprintable>"; - } - stream.println(" " + cols[i] + '=' + value); - } - stream.println("}"); - } - - /** - * Prints the contents of a Cursor's current row to a StringBuilder. - * - * @param cursor the cursor to print - * @param sb the StringBuilder to print to - */ - public static void dumpCurrentRow(Cursor cursor, StringBuilder sb) { - String[] cols = cursor.getColumnNames(); - sb.append("" + cursor.getPosition() + " {\n"); - int length = cols.length; - for (int i = 0; i < length; i++) { - String value; - try { - value = cursor.getString(i); - } catch (SQLiteException e) { - // assume that if the getString threw this exception then the column is not - // representable by a string, e.g. it is a BLOB. - value = "<unprintable>"; - } - sb.append(" " + cols[i] + '=' + value + "\n"); - } - sb.append("}\n"); - } - - /** - * Dump the contents of a Cursor's current row to a String. - * - * @param cursor the cursor to print - * @return a String that contains the dumped cursor row - */ - public static String dumpCurrentRowToString(Cursor cursor) { - StringBuilder sb = new StringBuilder(); - dumpCurrentRow(cursor, sb); - return sb.toString(); - } - - /** - * Reads a String out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The TEXT field to read - * @param values The {@link ContentValues} to put the value into, with the field as the key - */ - public static void cursorStringToContentValues(Cursor cursor, String field, - ContentValues values) { - cursorStringToContentValues(cursor, field, values, field); - } - - /** - * Reads a String out of a field in a Cursor and writes it to an InsertHelper. - * - * @param cursor The cursor to read from - * @param field The TEXT field to read - * @param inserter The InsertHelper to bind into - * @param index the index of the bind entry in the InsertHelper - */ - public static void cursorStringToInsertHelper(Cursor cursor, String field, - InsertHelper inserter, int index) { - inserter.bind(index, cursor.getString(cursor.getColumnIndexOrThrow(field))); - } - - /** - * Reads a String out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The TEXT field to read - * @param values The {@link ContentValues} to put the value into, with the field as the key - * @param key The key to store the value with in the map - */ - public static void cursorStringToContentValues(Cursor cursor, String field, - ContentValues values, String key) { - values.put(key, cursor.getString(cursor.getColumnIndexOrThrow(field))); - } - - /** - * Reads an Integer out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The INTEGER field to read - * @param values The {@link ContentValues} to put the value into, with the field as the key - */ - public static void cursorIntToContentValues(Cursor cursor, String field, ContentValues values) { - cursorIntToContentValues(cursor, field, values, field); - } - - /** - * Reads a Integer out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The INTEGER field to read - * @param values The {@link ContentValues} to put the value into, with the field as the key - * @param key The key to store the value with in the map - */ - public static void cursorIntToContentValues(Cursor cursor, String field, ContentValues values, - String key) { - int colIndex = cursor.getColumnIndex(field); - if (!cursor.isNull(colIndex)) { - values.put(key, cursor.getInt(colIndex)); - } else { - values.put(key, (Integer) null); - } - } - - /** - * Reads a Long out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The INTEGER field to read - * @param values The {@link ContentValues} to put the value into, with the field as the key - */ - public static void cursorLongToContentValues(Cursor cursor, String field, ContentValues values) - { - cursorLongToContentValues(cursor, field, values, field); - } - - /** - * Reads a Long out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The INTEGER field to read - * @param values The {@link ContentValues} to put the value into - * @param key The key to store the value with in the map - */ - public static void cursorLongToContentValues(Cursor cursor, String field, ContentValues values, - String key) { - int colIndex = cursor.getColumnIndex(field); - if (!cursor.isNull(colIndex)) { - Long value = Long.valueOf(cursor.getLong(colIndex)); - values.put(key, value); - } else { - values.put(key, (Long) null); - } - } - - /** - * Reads a Double out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The REAL field to read - * @param values The {@link ContentValues} to put the value into - */ - public static void cursorDoubleToCursorValues(Cursor cursor, String field, ContentValues values) - { - cursorDoubleToContentValues(cursor, field, values, field); - } - - /** - * Reads a Double out of a field in a Cursor and writes it to a Map. - * - * @param cursor The cursor to read from - * @param field The REAL field to read - * @param values The {@link ContentValues} to put the value into - * @param key The key to store the value with in the map - */ - public static void cursorDoubleToContentValues(Cursor cursor, String field, - ContentValues values, String key) { - int colIndex = cursor.getColumnIndex(field); - if (!cursor.isNull(colIndex)) { - values.put(key, cursor.getDouble(colIndex)); - } else { - values.put(key, (Double) null); - } - } - - /** - * Read the entire contents of a cursor row and store them in a ContentValues. - * - * @param cursor the cursor to read from. - * @param values the {@link ContentValues} to put the row into. - */ - public static void cursorRowToContentValues(Cursor cursor, ContentValues values) { - AbstractWindowedCursor awc = - (cursor instanceof AbstractWindowedCursor) ? (AbstractWindowedCursor) cursor : null; - - String[] columns = cursor.getColumnNames(); - int length = columns.length; - for (int i = 0; i < length; i++) { - if (awc != null && awc.isBlob(i)) { - values.put(columns[i], cursor.getBlob(i)); - } else { - values.put(columns[i], cursor.getString(i)); - } - } - } - - /** - * Query the table for the number of rows in the table. - * @param db the database the table is in - * @param table the name of the table to query - * @return the number of rows in the table - */ - public static long queryNumEntries(SQLiteDatabase db, String table) { - Cursor cursor = db.query(table, countProjection, - null, null, null, null, null); - cursor.moveToFirst(); - long count = cursor.getLong(0); - cursor.deactivate(); - return count; - } - - /** - * Utility method to run the query on the db and return the value in the - * first column of the first row. - */ - public static long longForQuery(SQLiteDatabase db, String query, String[] selectionArgs) { - SQLiteStatement prog = db.compileStatement(query); - try { - return longForQuery(prog, selectionArgs); - } finally { - prog.close(); - } - } - - /** - * Utility method to run the pre-compiled query and return the value in the - * first column of the first row. - */ - public static long longForQuery(SQLiteStatement prog, String[] selectionArgs) { - if (selectionArgs != null) { - int size = selectionArgs.length; - for (int i = 0; i < size; i++) { - bindObjectToProgram(prog, i + 1, selectionArgs[i]); - } - } - long value = prog.simpleQueryForLong(); - return value; - } - - /** - * Utility method to run the query on the db and return the value in the - * first column of the first row. - */ - public static String stringForQuery(SQLiteDatabase db, String query, String[] selectionArgs) { - SQLiteStatement prog = db.compileStatement(query); - try { - return stringForQuery(prog, selectionArgs); - } finally { - prog.close(); - } - } - - /** - * Utility method to run the pre-compiled query and return the value in the - * first column of the first row. - */ - public static String stringForQuery(SQLiteStatement prog, String[] selectionArgs) { - if (selectionArgs != null) { - int size = selectionArgs.length; - for (int i = 0; i < size; i++) { - bindObjectToProgram(prog, i + 1, selectionArgs[i]); - } - } - String value = prog.simpleQueryForString(); - return value; - } - - /** - * This class allows users to do multiple inserts into a table but - * compile the SQL insert statement only once, which may increase - * performance. - */ - public static class InsertHelper { - private final SQLiteDatabase mDb; - private final String mTableName; - private HashMap<String, Integer> mColumns; - private String mInsertSQL = null; - private SQLiteStatement mInsertStatement = null; - private SQLiteStatement mReplaceStatement = null; - private SQLiteStatement mPreparedStatement = null; - - /** - * {@hide} - * - * These are the columns returned by sqlite's "PRAGMA - * table_info(...)" command that we depend on. - */ - public static final int TABLE_INFO_PRAGMA_COLUMNNAME_INDEX = 1; - public static final int TABLE_INFO_PRAGMA_DEFAULT_INDEX = 4; - - /** - * @param db the SQLiteDatabase to insert into - * @param tableName the name of the table to insert into - */ - public InsertHelper(SQLiteDatabase db, String tableName) { - mDb = db; - mTableName = tableName; - } - - private void buildSQL() throws SQLException { - StringBuilder sb = new StringBuilder(128); - sb.append("INSERT INTO "); - sb.append(mTableName); - sb.append(" ("); - - StringBuilder sbv = new StringBuilder(128); - sbv.append("VALUES ("); - - int i = 1; - Cursor cur = null; - try { - cur = mDb.rawQuery("PRAGMA table_info(" + mTableName + ")", null); - mColumns = new HashMap<String, Integer>(cur.getCount()); - while (cur.moveToNext()) { - String columnName = cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX); - String defaultValue = cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX); - - mColumns.put(columnName, i); - sb.append("'"); - sb.append(columnName); - sb.append("'"); - - if (defaultValue == null) { - sbv.append("?"); - } else { - sbv.append("COALESCE(?, "); - sbv.append(defaultValue); - sbv.append(")"); - } - - sb.append(i == cur.getCount() ? ") " : ", "); - sbv.append(i == cur.getCount() ? ");" : ", "); - ++i; - } - } finally { - if (cur != null) cur.close(); - } - - sb.append(sbv); - - mInsertSQL = sb.toString(); - if (LOCAL_LOGV) Log.v(TAG, "insert statement is " + mInsertSQL); - } - - private SQLiteStatement getStatement(boolean allowReplace) throws SQLException { - if (allowReplace) { - if (mReplaceStatement == null) { - if (mInsertSQL == null) buildSQL(); - // chop "INSERT" off the front and prepend "INSERT OR REPLACE" instead. - String replaceSQL = "INSERT OR REPLACE" + mInsertSQL.substring(6); - mReplaceStatement = mDb.compileStatement(replaceSQL); - } - return mReplaceStatement; - } else { - if (mInsertStatement == null) { - if (mInsertSQL == null) buildSQL(); - mInsertStatement = mDb.compileStatement(mInsertSQL); - } - return mInsertStatement; - } - } - - /** - * Performs an insert, adding a new row with the given values. - * - * @param values the set of values with which to populate the - * new row - * @param allowReplace if true, the statement does "INSERT OR - * REPLACE" instead of "INSERT", silently deleting any - * previously existing rows that would cause a conflict - * - * @return the row ID of the newly inserted row, or -1 if an - * error occurred - */ - private synchronized long insertInternal(ContentValues values, boolean allowReplace) { - try { - SQLiteStatement stmt = getStatement(allowReplace); - stmt.clearBindings(); - if (LOCAL_LOGV) Log.v(TAG, "--- inserting in table " + mTableName); - for (Map.Entry<String, Object> e: values.valueSet()) { - final String key = e.getKey(); - int i = getColumnIndex(key); - DatabaseUtils.bindObjectToProgram(stmt, i, e.getValue()); - if (LOCAL_LOGV) { - Log.v(TAG, "binding " + e.getValue() + " to column " + - i + " (" + key + ")"); - } - } - return stmt.executeInsert(); - } catch (SQLException e) { - Log.e(TAG, "Error inserting " + values + " into table " + mTableName, e); - return -1; - } - } - - /** - * Returns the index of the specified column. This is index is suitagble for use - * in calls to bind(). - * @param key the column name - * @return the index of the column - */ - public int getColumnIndex(String key) { - getStatement(false); - final Integer index = mColumns.get(key); - if (index == null) { - throw new IllegalArgumentException("column '" + key + "' is invalid"); - } - return index; - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, double value) { - mPreparedStatement.bindDouble(index, value); - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, float value) { - mPreparedStatement.bindDouble(index, value); - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, long value) { - mPreparedStatement.bindLong(index, value); - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, int value) { - mPreparedStatement.bindLong(index, value); - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, boolean value) { - mPreparedStatement.bindLong(index, value ? 1 : 0); - } - - /** - * Bind null to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - */ - public void bindNull(int index) { - mPreparedStatement.bindNull(index); - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, byte[] value) { - if (value == null) { - mPreparedStatement.bindNull(index); - } else { - mPreparedStatement.bindBlob(index, value); - } - } - - /** - * Bind the value to an index. A prepareForInsert() or prepareForReplace() - * without a matching execute() must have already have been called. - * @param index the index of the slot to which to bind - * @param value the value to bind - */ - public void bind(int index, String value) { - if (value == null) { - mPreparedStatement.bindNull(index); - } else { - mPreparedStatement.bindString(index, value); - } - } - - /** - * Performs an insert, adding a new row with the given values. - * If the table contains conflicting rows, an error is - * returned. - * - * @param values the set of values with which to populate the - * new row - * - * @return the row ID of the newly inserted row, or -1 if an - * error occurred - */ - public long insert(ContentValues values) { - return insertInternal(values, false); - } - - /** - * Execute the previously prepared insert or replace using the bound values - * since the last call to prepareForInsert or prepareForReplace. - * - * <p>Note that calling bind() and then execute() is not thread-safe. The only thread-safe - * way to use this class is to call insert() or replace(). - * - * @return the row ID of the newly inserted row, or -1 if an - * error occurred - */ - public long execute() { - if (mPreparedStatement == null) { - throw new IllegalStateException("you must prepare this inserter before calling " - + "execute"); - } - try { - if (LOCAL_LOGV) Log.v(TAG, "--- doing insert or replace in table " + mTableName); - return mPreparedStatement.executeInsert(); - } catch (SQLException e) { - Log.e(TAG, "Error executing InsertHelper with table " + mTableName, e); - return -1; - } finally { - // you can only call this once per prepare - mPreparedStatement = null; - } - } - - /** - * Prepare the InsertHelper for an insert. The pattern for this is: - * <ul> - * <li>prepareForInsert() - * <li>bind(index, value); - * <li>bind(index, value); - * <li>... - * <li>bind(index, value); - * <li>execute(); - * </ul> - */ - public void prepareForInsert() { - mPreparedStatement = getStatement(false); - mPreparedStatement.clearBindings(); - } - - /** - * Prepare the InsertHelper for a replace. The pattern for this is: - * <ul> - * <li>prepareForReplace() - * <li>bind(index, value); - * <li>bind(index, value); - * <li>... - * <li>bind(index, value); - * <li>execute(); - * </ul> - */ - public void prepareForReplace() { - mPreparedStatement = getStatement(true); - mPreparedStatement.clearBindings(); - } - - /** - * Performs an insert, adding a new row with the given values. - * If the table contains conflicting rows, they are deleted - * and replaced with the new row. - * - * @param values the set of values with which to populate the - * new row - * - * @return the row ID of the newly inserted row, or -1 if an - * error occurred - */ - public long replace(ContentValues values) { - return insertInternal(values, true); - } - - /** - * Close this object and release any resources associated with - * it. The behavior of calling <code>insert()</code> after - * calling this method is undefined. - */ - public void close() { - if (mInsertStatement != null) { - mInsertStatement.close(); - mInsertStatement = null; - } - if (mReplaceStatement != null) { - mReplaceStatement.close(); - mReplaceStatement = null; - } - mInsertSQL = null; - mColumns = null; - } - } - - /** - * Creates a db and populates it with the sql statements in sqlStatements. - * - * @param context the context to use to create the db - * @param dbName the name of the db to create - * @param dbVersion the version to set on the db - * @param sqlStatements the statements to use to populate the db. This should be a single string - * of the form returned by sqlite3's <tt>.dump</tt> command (statements separated by - * semicolons) - */ - static public void createDbFromSqlStatements( - Context context, String dbName, int dbVersion, String sqlStatements) { - SQLiteDatabase db = context.openOrCreateDatabase(dbName, 0, null); - // TODO: this is not quite safe since it assumes that all semicolons at the end of a line - // terminate statements. It is possible that a text field contains ;\n. We will have to fix - // this if that turns out to be a problem. - String[] statements = TextUtils.split(sqlStatements, ";\n"); - for (String statement : statements) { - if (TextUtils.isEmpty(statement)) continue; - db.execSQL(statement); - } - db.setVersion(dbVersion); - db.close(); - } -} diff --git a/core/java/android/database/IBulkCursor.java b/core/java/android/database/IBulkCursor.java deleted file mode 100644 index 24354fd..0000000 --- a/core/java/android/database/IBulkCursor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import android.os.RemoteException; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Bundle; - -import java.util.Map; - -/** - * This interface provides a low-level way to pass bulk cursor data across - * both process and language boundries. Application code should use the Cursor - * interface directly. - * - * {@hide} - */ -public interface IBulkCursor extends IInterface -{ - /** - * Returns a BulkCursorWindow, which either has a reference to a shared - * memory segment with the rows, or an array of JSON strings. - */ - public CursorWindow getWindow(int startPos) throws RemoteException; - - public void onMove(int position) throws RemoteException; - - /** - * Returns the number of rows in the cursor. - * - * @return the number of rows in the cursor. - */ - public int count() throws RemoteException; - - /** - * Returns a string array holding the names of all of the columns in the - * cursor in the order in which they were listed in the result. - * - * @return the names of the columns returned in this query. - */ - public String[] getColumnNames() throws RemoteException; - - public boolean updateRows(Map<? extends Long, ? extends Map<String, Object>> values) throws RemoteException; - - public boolean deleteRow(int position) throws RemoteException; - - public void deactivate() throws RemoteException; - - public void close() throws RemoteException; - - public int requery(IContentObserver observer, CursorWindow window) throws RemoteException; - - boolean getWantsAllOnMoveCalls() throws RemoteException; - - Bundle getExtras() throws RemoteException; - - Bundle respond(Bundle extras) throws RemoteException; - - /* IPC constants */ - static final String descriptor = "android.content.IBulkCursor"; - - static final int GET_CURSOR_WINDOW_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; - static final int COUNT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1; - static final int GET_COLUMN_NAMES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2; - static final int UPDATE_ROWS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3; - static final int DELETE_ROW_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 4; - static final int DEACTIVATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 5; - static final int REQUERY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 6; - static final int ON_MOVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 7; - static final int WANTS_ON_MOVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 8; - static final int GET_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 9; - static final int RESPOND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10; - static final int CLOSE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 11; -} - diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl deleted file mode 100755 index ac2f975..0000000 --- a/core/java/android/database/IContentObserver.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* -** -** Copyright 2007, 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 -** -** 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 -** limitations under the License. -*/ - -package android.database; - -/** - * @hide - */ -interface IContentObserver -{ - /** - * This method is called when an update occurs to the cursor that is being - * observed. selfUpdate is true if the update was caused by a call to - * commit on the cursor that is being observed. - */ - oneway void onChange(boolean selfUpdate); -} diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java deleted file mode 100644 index cf5a573..0000000 --- a/core/java/android/database/MatrixCursor.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import java.util.ArrayList; - -/** - * A mutable cursor implementation backed by an array of {@code Object}s. Use - * {@link #newRow()} to add rows. Automatically expands internal capacity - * as needed. - */ -public class MatrixCursor extends AbstractCursor { - - private final String[] columnNames; - private Object[] data; - private int rowCount = 0; - private final int columnCount; - - /** - * Constructs a new cursor with the given initial capacity. - * - * @param columnNames names of the columns, the ordering of which - * determines column ordering elsewhere in this cursor - * @param initialCapacity in rows - */ - public MatrixCursor(String[] columnNames, int initialCapacity) { - this.columnNames = columnNames; - this.columnCount = columnNames.length; - - if (initialCapacity < 1) { - initialCapacity = 1; - } - - this.data = new Object[columnCount * initialCapacity]; - } - - /** - * Constructs a new cursor. - * - * @param columnNames names of the columns, the ordering of which - * determines column ordering elsewhere in this cursor - */ - public MatrixCursor(String[] columnNames) { - this(columnNames, 16); - } - - /** - * Gets value at the given column for the current row. - */ - private Object get(int column) { - if (column < 0 || column >= columnCount) { - throw new CursorIndexOutOfBoundsException("Requested column: " - + column + ", # of columns: " + columnCount); - } - if (mPos < 0) { - throw new CursorIndexOutOfBoundsException("Before first row."); - } - if (mPos >= rowCount) { - throw new CursorIndexOutOfBoundsException("After last row."); - } - return data[mPos * columnCount + column]; - } - - /** - * Adds a new row to the end and returns a builder for that row. Not safe - * for concurrent use. - * - * @return builder which can be used to set the column values for the new - * row - */ - public RowBuilder newRow() { - rowCount++; - int endIndex = rowCount * columnCount; - ensureCapacity(endIndex); - int start = endIndex - columnCount; - return new RowBuilder(start, endIndex); - } - - /** - * Adds a new row to the end with the given column values. Not safe - * for concurrent use. - * - * @throws IllegalArgumentException if {@code columnValues.length != - * columnNames.length} - * @param columnValues in the same order as the the column names specified - * at cursor construction time - */ - public void addRow(Object[] columnValues) { - if (columnValues.length != columnCount) { - throw new IllegalArgumentException("columnNames.length = " - + columnCount + ", columnValues.length = " - + columnValues.length); - } - - int start = rowCount++ * columnCount; - ensureCapacity(start + columnCount); - System.arraycopy(columnValues, 0, data, start, columnCount); - } - - /** - * Adds a new row to the end with the given column values. Not safe - * for concurrent use. - * - * @throws IllegalArgumentException if {@code columnValues.size() != - * columnNames.length} - * @param columnValues in the same order as the the column names specified - * at cursor construction time - */ - public void addRow(Iterable<?> columnValues) { - int start = rowCount * columnCount; - int end = start + columnCount; - ensureCapacity(end); - - if (columnValues instanceof ArrayList<?>) { - addRow((ArrayList<?>) columnValues, start); - return; - } - - int current = start; - Object[] localData = data; - for (Object columnValue : columnValues) { - if (current == end) { - // TODO: null out row? - throw new IllegalArgumentException( - "columnValues.size() > columnNames.length"); - } - localData[current++] = columnValue; - } - - if (current != end) { - // TODO: null out row? - throw new IllegalArgumentException( - "columnValues.size() < columnNames.length"); - } - - // Increase row count here in case we encounter an exception. - rowCount++; - } - - /** Optimization for {@link ArrayList}. */ - private void addRow(ArrayList<?> columnValues, int start) { - int size = columnValues.size(); - if (size != columnCount) { - throw new IllegalArgumentException("columnNames.length = " - + columnCount + ", columnValues.size() = " + size); - } - - rowCount++; - Object[] localData = data; - for (int i = 0; i < size; i++) { - localData[start + i] = columnValues.get(i); - } - } - - /** Ensures that this cursor has enough capacity. */ - private void ensureCapacity(int size) { - if (size > data.length) { - Object[] oldData = this.data; - int newSize = data.length * 2; - if (newSize < size) { - newSize = size; - } - this.data = new Object[newSize]; - System.arraycopy(oldData, 0, this.data, 0, oldData.length); - } - } - - /** - * Builds a row, starting from the left-most column and adding one column - * value at a time. Follows the same ordering as the column names specified - * at cursor construction time. - */ - public class RowBuilder { - - private int index; - private final int endIndex; - - RowBuilder(int index, int endIndex) { - this.index = index; - this.endIndex = endIndex; - } - - /** - * Sets the next column value in this row. - * - * @throws CursorIndexOutOfBoundsException if you try to add too many - * values - * @return this builder to support chaining - */ - public RowBuilder add(Object columnValue) { - if (index == endIndex) { - throw new CursorIndexOutOfBoundsException( - "No more columns left."); - } - - data[index++] = columnValue; - return this; - } - } - - // AbstractCursor implementation. - - public int getCount() { - return rowCount; - } - - public String[] getColumnNames() { - return columnNames; - } - - public String getString(int column) { - return String.valueOf(get(column)); - } - - public short getShort(int column) { - Object value = get(column); - return (value instanceof String) - ? Short.valueOf((String) value) - : ((Number) value).shortValue(); - } - - public int getInt(int column) { - Object value = get(column); - return (value instanceof String) - ? Integer.valueOf((String) value) - : ((Number) value).intValue(); - } - - public long getLong(int column) { - Object value = get(column); - return (value instanceof String) - ? Long.valueOf((String) value) - : ((Number) value).longValue(); - } - - public float getFloat(int column) { - Object value = get(column); - return (value instanceof String) - ? Float.valueOf((String) value) - : ((Number) value).floatValue(); - } - - public double getDouble(int column) { - Object value = get(column); - return (value instanceof String) - ? Double.valueOf((String) value) - : ((Number) value).doubleValue(); - } - - public boolean isNull(int column) { - return get(column) == null; - } -} diff --git a/core/java/android/database/MergeCursor.java b/core/java/android/database/MergeCursor.java deleted file mode 100644 index 7e91159..0000000 --- a/core/java/android/database/MergeCursor.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * A convience class that lets you present an array of Cursors as a single linear Cursor. - * The schema of the cursors presented is entirely up to the creator of the MergeCursor, and - * may be different if that is desired. Calls to getColumns, getColumnIndex, etc will return the - * value for the row that the MergeCursor is currently pointing at. - */ -public class MergeCursor extends AbstractCursor -{ - private DataSetObserver mObserver = new DataSetObserver() { - - @Override - public void onChanged() { - // Reset our position so the optimizations in move-related code - // don't screw us over - mPos = -1; - } - - @Override - public void onInvalidated() { - mPos = -1; - } - }; - - public MergeCursor(Cursor[] cursors) - { - mCursors = cursors; - mCursor = cursors[0]; - - for (int i = 0; i < mCursors.length; i++) { - if (mCursors[i] == null) continue; - - mCursors[i].registerDataSetObserver(mObserver); - } - } - - @Override - public int getCount() - { - int count = 0; - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - count += mCursors[i].getCount(); - } - } - return count; - } - - @Override - public boolean onMove(int oldPosition, int newPosition) - { - /* Find the right cursor */ - mCursor = null; - int cursorStartPos = 0; - int length = mCursors.length; - for (int i = 0 ; i < length; i++) { - if (mCursors[i] == null) { - continue; - } - - if (newPosition < (cursorStartPos + mCursors[i].getCount())) { - mCursor = mCursors[i]; - break; - } - - cursorStartPos += mCursors[i].getCount(); - } - - /* Move it to the right position */ - if (mCursor != null) { - boolean ret = mCursor.moveToPosition(newPosition - cursorStartPos); - return ret; - } - return false; - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean deleteRow() - { - return mCursor.deleteRow(); - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean commitUpdates() { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].commitUpdates(); - } - } - onChange(true); - return true; - } - - @Override - public String getString(int column) - { - return mCursor.getString(column); - } - - @Override - public short getShort(int column) - { - return mCursor.getShort(column); - } - - @Override - public int getInt(int column) - { - return mCursor.getInt(column); - } - - @Override - public long getLong(int column) - { - return mCursor.getLong(column); - } - - @Override - public float getFloat(int column) - { - return mCursor.getFloat(column); - } - - @Override - public double getDouble(int column) - { - return mCursor.getDouble(column); - } - - @Override - public boolean isNull(int column) - { - return mCursor.isNull(column); - } - - @Override - public byte[] getBlob(int column) - { - return mCursor.getBlob(column); - } - - @Override - public String[] getColumnNames() - { - if (mCursor != null) { - return mCursor.getColumnNames(); - } else { - return new String[0]; - } - } - - @Override - public void deactivate() - { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].deactivate(); - } - } - } - - @Override - public void close() { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] == null) continue; - mCursors[i].close(); - } - } - - @Override - public void registerContentObserver(ContentObserver observer) { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].registerContentObserver(observer); - } - } - } - @Override - public void unregisterContentObserver(ContentObserver observer) { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].unregisterContentObserver(observer); - } - } - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].registerDataSetObserver(observer); - } - } - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] != null) { - mCursors[i].unregisterDataSetObserver(observer); - } - } - } - - @Override - public boolean requery() - { - int length = mCursors.length; - for (int i = 0 ; i < length ; i++) { - if (mCursors[i] == null) { - continue; - } - - if (mCursors[i].requery() == false) { - return false; - } - } - - return true; - } - - private Cursor mCursor; // updated in onMove - private Cursor[] mCursors; -} diff --git a/core/java/android/database/Observable.java b/core/java/android/database/Observable.java deleted file mode 100644 index b6fecab..0000000 --- a/core/java/android/database/Observable.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -import java.util.ArrayList; - -/** - * Provides methods for (un)registering arbitrary observers in an ArrayList. - */ -public abstract class Observable<T> { - /** - * The list of observers. An observer can be in the list at most - * once and will never be null. - */ - protected final ArrayList<T> mObservers = new ArrayList<T>(); - - /** - * Adds an observer to the list. The observer cannot be null and it must not already - * be registered. - * @param observer the observer to register - * @throws IllegalArgumentException the observer is null - * @throws IllegalStateException the observer is already registered - */ - public void registerObserver(T observer) { - if (observer == null) { - throw new IllegalArgumentException("The observer is null."); - } - synchronized(mObservers) { - if (mObservers.contains(observer)) { - throw new IllegalStateException("Observer " + observer + " is already registered."); - } - mObservers.add(observer); - } - } - - /** - * Removes a previously registered observer. The observer must not be null and it - * must already have been registered. - * @param observer the observer to unregister - * @throws IllegalArgumentException the observer is null - * @throws IllegalStateException the observer is not yet registered - */ - public void unregisterObserver(T observer) { - if (observer == null) { - throw new IllegalArgumentException("The observer is null."); - } - synchronized(mObservers) { - int index = mObservers.indexOf(observer); - if (index == -1) { - throw new IllegalStateException("Observer " + observer + " was not registered."); - } - mObservers.remove(index); - } - } - - /** - * Remove all registered observer - */ - public void unregisterAll() { - synchronized(mObservers) { - mObservers.clear(); - } - } -} diff --git a/core/java/android/database/SQLException.java b/core/java/android/database/SQLException.java deleted file mode 100644 index 0386af0..0000000 --- a/core/java/android/database/SQLException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * An exception that indicates there was an error with SQL parsing or execution. - */ -public class SQLException extends RuntimeException -{ - public SQLException() {} - - public SQLException(String error) - { - super(error); - } -} diff --git a/core/java/android/database/StaleDataException.java b/core/java/android/database/StaleDataException.java deleted file mode 100644 index ee70beb..0000000 --- a/core/java/android/database/StaleDataException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database; - -/** - * This exception is thrown when a Cursor contains stale data and must be - * requeried before being used again. - */ -public class StaleDataException extends java.lang.RuntimeException -{ - public StaleDataException() - { - super(); - } - - public StaleDataException(String description) - { - super(description); - } -} diff --git a/core/java/android/database/package.html b/core/java/android/database/package.html deleted file mode 100644 index 1f76d9f..0000000 --- a/core/java/android/database/package.html +++ /dev/null @@ -1,14 +0,0 @@ -<HTML> -<BODY> -Contains classes to explore data returned through a content provider. -<p> -If you need to manage data in a private database, use the {@link -android.database.sqlite} classes. These classes are used to manage the {@link -android.database.Cursor} object returned from a content provider query. Databases -are usually created and opened with {@link android.content.Context#openOrCreateDatabase} -To make requests through -content providers, you can use the {@link android.content.ContentResolver -content.ContentResolver} class. -<p>All databases are stored on the device in <code>/data/data/<package_name>/databases</code> -</BODY> -</HTML> diff --git a/core/java/android/database/sqlite/SQLiteAbortException.java b/core/java/android/database/sqlite/SQLiteAbortException.java deleted file mode 100644 index 64dc4b7..0000000 --- a/core/java/android/database/sqlite/SQLiteAbortException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that the SQLite program was aborted. - * This can happen either through a call to ABORT in a trigger, - * or as the result of using the ABORT conflict clause. - */ -public class SQLiteAbortException extends SQLiteException { - public SQLiteAbortException() {} - - public SQLiteAbortException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java deleted file mode 100644 index f64261c..0000000 --- a/core/java/android/database/sqlite/SQLiteClosable.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An object create from a SQLiteDatabase that can be closed. - */ -public abstract class SQLiteClosable { - private int mReferenceCount = 1; - private Object mLock = new Object(); - protected abstract void onAllReferencesReleased(); - protected void onAllReferencesReleasedFromContainer(){} - - public void acquireReference() { - synchronized(mLock) { - if (mReferenceCount <= 0) { - throw new IllegalStateException( - "attempt to acquire a reference on a close SQLiteClosable"); - } - mReferenceCount++; - } - } - - public void releaseReference() { - synchronized(mLock) { - mReferenceCount--; - if (mReferenceCount == 0) { - onAllReferencesReleased(); - } - } - } - - public void releaseReferenceFromContainer() { - synchronized(mLock) { - mReferenceCount--; - if (mReferenceCount == 0) { - onAllReferencesReleasedFromContainer(); - } - } - } -} diff --git a/core/java/android/database/sqlite/SQLiteConstraintException.java b/core/java/android/database/sqlite/SQLiteConstraintException.java deleted file mode 100644 index e3119eb..0000000 --- a/core/java/android/database/sqlite/SQLiteConstraintException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that an integrity constraint was violated. - */ -public class SQLiteConstraintException extends SQLiteException { - public SQLiteConstraintException() {} - - public SQLiteConstraintException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java deleted file mode 100644 index 70b9b83..0000000 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ /dev/null @@ -1,606 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.AbstractWindowedCursor; -import android.database.CursorWindow; -import android.database.DataSetObserver; -import android.database.SQLException; - -import android.os.Handler; -import android.os.Message; -import android.os.Process; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; - -/** - * A Cursor implementation that exposes results from a query on a - * {@link SQLiteDatabase}. - */ -public class SQLiteCursor extends AbstractWindowedCursor { - static final String TAG = "Cursor"; - static final int NO_COUNT = -1; - - /** The name of the table to edit */ - private String mEditTable; - - /** The names of the columns in the rows */ - private String[] mColumns; - - /** The query object for the cursor */ - private SQLiteQuery mQuery; - - /** The database the cursor was created from */ - private SQLiteDatabase mDatabase; - - /** The compiled query this cursor came from */ - private SQLiteCursorDriver mDriver; - - /** The number of rows in the cursor */ - private int mCount = NO_COUNT; - - /** A mapping of column names to column indices, to speed up lookups */ - private Map<String, Integer> mColumnNameMap; - - /** Used to find out where a cursor was allocated in case it never got - * released. */ - private StackTraceElement[] mStackTraceElements; - - /** - * mMaxRead is the max items that each cursor window reads - * default to a very high value - */ - private int mMaxRead = Integer.MAX_VALUE; - private int mInitialRead = Integer.MAX_VALUE; - private int mCursorState = 0; - private ReentrantLock mLock = null; - private boolean mPendingData = false; - - /** - * support for a cursor variant that doesn't always read all results - * initialRead is the initial number of items that cursor window reads - * if query contains more than this number of items, a thread will be - * created and handle the left over items so that caller can show - * results as soon as possible - * @param initialRead initial number of items that cursor read - * @param maxRead leftover items read at maxRead items per time - * @hide - */ - public void setLoadStyle(int initialRead, int maxRead) { - mMaxRead = maxRead; - mInitialRead = initialRead; - mLock = new ReentrantLock(true); - } - - private void queryThreadLock() { - if (mLock != null) { - mLock.lock(); - } - } - - private void queryThreadUnlock() { - if (mLock != null) { - mLock.unlock(); - } - } - - - /** - * @hide - */ - final private class QueryThread implements Runnable { - private final int mThreadState; - QueryThread(int version) { - mThreadState = version; - } - private void sendMessage() { - if (mNotificationHandler != null) { - mNotificationHandler.sendEmptyMessage(1); - mPendingData = false; - } else { - mPendingData = true; - } - - } - public void run() { - // use cached mWindow, to avoid get null mWindow - CursorWindow cw = mWindow; - Process.setThreadPriority(Process.myTid(), Process.THREAD_PRIORITY_BACKGROUND); - // the cursor's state doesn't change - while (true) { - mLock.lock(); - if (mCursorState != mThreadState) { - mLock.unlock(); - break; - } - try { - int count = mQuery.fillWindow(cw, mMaxRead, mCount); - // return -1 means not finished - if (count != 0) { - if (count == NO_COUNT){ - mCount += mMaxRead; - sendMessage(); - } else { - mCount = count; - sendMessage(); - break; - } - } else { - break; - } - } catch (Exception e) { - // end the tread when the cursor is close - break; - } finally { - mLock.unlock(); - } - } - } - } - - /** - * @hide - */ - protected class MainThreadNotificationHandler extends Handler { - public void handleMessage(Message msg) { - notifyDataSetChange(); - } - } - - /** - * @hide - */ - protected MainThreadNotificationHandler mNotificationHandler; - - public void registerDataSetObserver(DataSetObserver observer) { - super.registerDataSetObserver(observer); - if ((Integer.MAX_VALUE != mMaxRead || Integer.MAX_VALUE != mInitialRead) && - mNotificationHandler == null) { - queryThreadLock(); - try { - mNotificationHandler = new MainThreadNotificationHandler(); - if (mPendingData) { - notifyDataSetChange(); - mPendingData = false; - } - } finally { - queryThreadUnlock(); - } - } - - } - - /** - * Execute a query and provide access to its result set through a Cursor - * interface. For a query such as: {@code SELECT name, birth, phone FROM - * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth, - * phone) would be in the projection argument and everything from - * {@code FROM} onward would be in the params argument. This constructor - * has package scope. - * - * @param db a reference to a Database object that is already constructed - * and opened - * @param editTable the name of the table used for this query - * @param query the rest of the query terms - * cursor is finalized - */ - public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, - String editTable, SQLiteQuery query) { - // The AbstractCursor constructor needs to do some setup. - super(); - - if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) { - mStackTraceElements = new Exception().getStackTrace(); - } - - mDatabase = db; - mDriver = driver; - mEditTable = editTable; - mColumnNameMap = null; - mQuery = query; - - try { - db.lock(); - - // Setup the list of columns - int columnCount = mQuery.columnCountLocked(); - mColumns = new String[columnCount]; - - // Read in all column names - for (int i = 0; i < columnCount; i++) { - String columnName = mQuery.columnNameLocked(i); - mColumns[i] = columnName; - if (Config.LOGV) { - Log.v("DatabaseWindow", "mColumns[" + i + "] is " - + mColumns[i]); - } - - // Make note of the row ID column index for quick access to it - if ("_id".equals(columnName)) { - mRowIdColumnIndex = i; - } - } - } finally { - db.unlock(); - } - } - - /** - * @return the SQLiteDatabase that this cursor is associated with. - */ - public SQLiteDatabase getDatabase() { - return mDatabase; - } - - @Override - public boolean onMove(int oldPosition, int newPosition) { - // Make sure the row at newPosition is present in the window - if (mWindow == null || newPosition < mWindow.getStartPosition() || - newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) { - fillWindow(newPosition); - } - - return true; - } - - @Override - public int getCount() { - if (mCount == NO_COUNT) { - fillWindow(0); - } - return mCount; - } - - private void fillWindow (int startPos) { - if (mWindow == null) { - // If there isn't a window set already it will only be accessed locally - mWindow = new CursorWindow(true /* the window is local only */); - } else { - mCursorState++; - queryThreadLock(); - try { - mWindow.clear(); - } finally { - queryThreadUnlock(); - } - } - mWindow.setStartPosition(startPos); - mCount = mQuery.fillWindow(mWindow, mInitialRead, 0); - // return -1 means not finished - if (mCount == NO_COUNT){ - mCount = startPos + mInitialRead; - Thread t = new Thread(new QueryThread(mCursorState), "query thread"); - t.start(); - } - } - - @Override - public int getColumnIndex(String columnName) { - // Create mColumnNameMap on demand - if (mColumnNameMap == null) { - String[] columns = mColumns; - int columnCount = columns.length; - HashMap<String, Integer> map = new HashMap<String, Integer>(columnCount, 1); - for (int i = 0; i < columnCount; i++) { - map.put(columns[i], i); - } - mColumnNameMap = map; - } - - // Hack according to bug 903852 - final int periodIndex = columnName.lastIndexOf('.'); - if (periodIndex != -1) { - Exception e = new Exception(); - Log.e(TAG, "requesting column name with table name -- " + columnName, e); - columnName = columnName.substring(periodIndex + 1); - } - - Integer i = mColumnNameMap.get(columnName); - if (i != null) { - return i.intValue(); - } else { - return -1; - } - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean deleteRow() { - checkPosition(); - - // Only allow deletes if there is an ID column, and the ID has been read from it - if (mRowIdColumnIndex == -1 || mCurrentRowID == null) { - Log.e(TAG, - "Could not delete row because either the row ID column is not available or it" + - "has not been read."); - return false; - } - - boolean success; - - /* - * Ensure we don't change the state of the database when another - * thread is holding the database lock. requery() and moveTo() are also - * synchronized here to make sure they get the state of the database - * immediately following the DELETE. - */ - mDatabase.lock(); - try { - try { - mDatabase.delete(mEditTable, mColumns[mRowIdColumnIndex] + "=?", - new String[] {mCurrentRowID.toString()}); - success = true; - } catch (SQLException e) { - success = false; - } - - int pos = mPos; - requery(); - - /* - * Ensure proper cursor state. Note that mCurrentRowID changes - * in this call. - */ - moveToPosition(pos); - } finally { - mDatabase.unlock(); - } - - if (success) { - onChange(true); - return true; - } else { - return false; - } - } - - @Override - public String[] getColumnNames() { - return mColumns; - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean supportsUpdates() { - return super.supportsUpdates() && !TextUtils.isEmpty(mEditTable); - } - - /** - * @hide - * @deprecated - */ - @Override - public boolean commitUpdates(Map<? extends Long, - ? extends Map<String, Object>> additionalValues) { - if (!supportsUpdates()) { - Log.e(TAG, "commitUpdates not supported on this cursor, did you " - + "include the _id column?"); - return false; - } - - /* - * Prevent other threads from changing the updated rows while they're - * being processed here. - */ - synchronized (mUpdatedRows) { - if (additionalValues != null) { - mUpdatedRows.putAll(additionalValues); - } - - if (mUpdatedRows.size() == 0) { - return true; - } - - /* - * Prevent other threads from changing the database state while - * we process the updated rows, and prevents us from changing the - * database behind the back of another thread. - */ - mDatabase.beginTransaction(); - try { - StringBuilder sql = new StringBuilder(128); - - // For each row that has been updated - for (Map.Entry<Long, Map<String, Object>> rowEntry : - mUpdatedRows.entrySet()) { - Map<String, Object> values = rowEntry.getValue(); - Long rowIdObj = rowEntry.getKey(); - - if (rowIdObj == null || values == null) { - throw new IllegalStateException("null rowId or values found! rowId = " - + rowIdObj + ", values = " + values); - } - - if (values.size() == 0) { - continue; - } - - long rowId = rowIdObj.longValue(); - - Iterator<Map.Entry<String, Object>> valuesIter = - values.entrySet().iterator(); - - sql.setLength(0); - sql.append("UPDATE " + mEditTable + " SET "); - - // For each column value that has been updated - Object[] bindings = new Object[values.size()]; - int i = 0; - while (valuesIter.hasNext()) { - Map.Entry<String, Object> entry = valuesIter.next(); - sql.append(entry.getKey()); - sql.append("=?"); - bindings[i] = entry.getValue(); - if (valuesIter.hasNext()) { - sql.append(", "); - } - i++; - } - - sql.append(" WHERE " + mColumns[mRowIdColumnIndex] - + '=' + rowId); - sql.append(';'); - mDatabase.execSQL(sql.toString(), bindings); - mDatabase.rowUpdated(mEditTable, rowId); - } - mDatabase.setTransactionSuccessful(); - } finally { - mDatabase.endTransaction(); - } - - mUpdatedRows.clear(); - } - - // Let any change observers know about the update - onChange(true); - - return true; - } - - private void deactivateCommon() { - if (Config.LOGV) Log.v(TAG, "<<< Releasing cursor " + this); - mCursorState = 0; - if (mWindow != null) { - mWindow.close(); - mWindow = null; - } - if (Config.LOGV) Log.v("DatabaseWindow", "closing window in release()"); - } - - @Override - public void deactivate() { - super.deactivate(); - deactivateCommon(); - mDriver.cursorDeactivated(); - } - - @Override - public void close() { - super.close(); - deactivateCommon(); - mQuery.close(); - mDriver.cursorClosed(); - } - - @Override - public boolean requery() { - if (isClosed()) { - return false; - } - long timeStart = 0; - if (Config.LOGV) { - timeStart = System.currentTimeMillis(); - } - /* - * Synchronize on the database lock to ensure that mCount matches the - * results of mQuery.requery(). - */ - mDatabase.lock(); - try { - if (mWindow != null) { - mWindow.clear(); - } - mPos = -1; - // This one will recreate the temp table, and get its count - mDriver.cursorRequeried(this); - mCount = NO_COUNT; - mCursorState++; - queryThreadLock(); - try { - mQuery.requery(); - } finally { - queryThreadUnlock(); - } - } finally { - mDatabase.unlock(); - } - - if (Config.LOGV) { - Log.v("DatabaseWindow", "closing window in requery()"); - Log.v(TAG, "--- Requery()ed cursor " + this + ": " + mQuery); - } - - boolean result = super.requery(); - if (Config.LOGV) { - long timeEnd = System.currentTimeMillis(); - Log.v(TAG, "requery (" + (timeEnd - timeStart) + " ms): " + mDriver.toString()); - } - return result; - } - - @Override - public void setWindow(CursorWindow window) { - if (mWindow != null) { - mCursorState++; - queryThreadLock(); - try { - mWindow.close(); - } finally { - queryThreadUnlock(); - } - mCount = NO_COUNT; - } - mWindow = window; - } - - /** - * Changes the selection arguments. The new values take effect after a call to requery(). - */ - public void setSelectionArguments(String[] selectionArgs) { - mDriver.setBindArguments(selectionArgs); - } - - /** - * Release the native resources, if they haven't been released yet. - */ - @Override - protected void finalize() { - try { - if (mWindow != null) { - close(); - String message = "Finalizing cursor " + this + " on " + mEditTable - + " that has not been deactivated or closed"; - if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) { - Log.d(TAG, message + "\nThis cursor was created in:"); - for (StackTraceElement ste : mStackTraceElements) { - Log.d(TAG, " " + ste); - } - } - SQLiteDebug.notifyActiveCursorFinalized(); - throw new IllegalStateException(message); - } else { - if (Config.LOGV) { - Log.v(TAG, "Finalizing cursor " + this + " on " + mEditTable); - } - } - } finally { - super.finalize(); - } - } -} diff --git a/core/java/android/database/sqlite/SQLiteCursorDriver.java b/core/java/android/database/sqlite/SQLiteCursorDriver.java deleted file mode 100644 index eda1b78..0000000 --- a/core/java/android/database/sqlite/SQLiteCursorDriver.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase.CursorFactory; - -/** - * A driver for SQLiteCursors that is used to create them and gets notified - * by the cursors it creates on significant events in their lifetimes. - */ -public interface SQLiteCursorDriver { - /** - * Executes the query returning a Cursor over the result set. - * - * @param factory The CursorFactory to use when creating the Cursors, or - * null if standard SQLiteCursors should be returned. - * @return a Cursor over the result set - */ - Cursor query(CursorFactory factory, String[] bindArgs); - - /** - * Called by a SQLiteCursor when it is released. - */ - void cursorDeactivated(); - - /** - * Called by a SQLiteCursor when it is requeryed. - * - * @return The new count value. - */ - void cursorRequeried(Cursor cursor); - - /** - * Called by a SQLiteCursor when it it closed to destroy this object as well. - */ - void cursorClosed(); - - /** - * Set new bind arguments. These will take effect in cursorRequeried(). - * @param bindArgs the new arguments - */ - public void setBindArguments(String[] bindArgs); -} diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java deleted file mode 100644 index 87bb277..0000000 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ /dev/null @@ -1,1675 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.SQLException; -import android.os.Debug; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; -import android.util.EventLog; - -import java.io.File; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Exposes methods to manage a SQLite database. - * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and - * perform other common database management tasks. - * <p>See the Notepad sample application in the SDK for an example of creating - * and managing a database. - * <p> Database names must be unique within an application, not across all - * applications. - * - * <h3>Localized Collation - ORDER BY</h3> - * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies - * two more, <code>LOCALIZED</code>, which changes with the system's current locale - * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which - * is the Unicode Collation Algorithm and not tailored to the current locale. - */ -public class SQLiteDatabase extends SQLiteClosable { - private static final String TAG = "Database"; - private static final int DB_OPERATION_EVENT = 52000; - - /** - * Algorithms used in ON CONFLICT clause - * http://www.sqlite.org/lang_conflict.html - * @hide - */ - public enum ConflictAlgorithm { - /** - * When a constraint violation occurs, an immediate ROLLBACK occurs, - * thus ending the current transaction, and the command aborts with a - * return code of SQLITE_CONSTRAINT. If no transaction is active - * (other than the implied transaction that is created on every command) - * then this algorithm works the same as ABORT. - */ - ROLLBACK("ROLLBACK"), - - /** - * When a constraint violation occurs,no ROLLBACK is executed - * so changes from prior commands within the same transaction - * are preserved. This is the default behavior. - */ - ABORT("ABORT"), - - /** - * When a constraint violation occurs, the command aborts with a return - * code SQLITE_CONSTRAINT. But any changes to the database that - * the command made prior to encountering the constraint violation - * are preserved and are not backed out. - */ - FAIL("FAIL"), - - /** - * When a constraint violation occurs, the one row that contains - * the constraint violation is not inserted or changed. - * But the command continues executing normally. Other rows before and - * after the row that contained the constraint violation continue to be - * inserted or updated normally. No error is returned. - */ - IGNORE("IGNORE"), - - /** - * When a UNIQUE constraint violation occurs, the pre-existing rows that - * are causing the constraint violation are removed prior to inserting - * or updating the current row. Thus the insert or update always occurs. - * The command continues executing normally. No error is returned. - * If a NOT NULL constraint violation occurs, the NULL value is replaced - * by the default value for that column. If the column has no default - * value, then the ABORT algorithm is used. If a CHECK constraint - * violation occurs then the IGNORE algorithm is used. When this conflict - * resolution strategy deletes rows in order to satisfy a constraint, - * it does not invoke delete triggers on those rows. - * This behavior might change in a future release. - */ - REPLACE("REPLACE"); - - private final String mValue; - ConflictAlgorithm(String value) { - mValue = value; - } - public String value() { - return mValue; - } - } - - /** - * Maximum Length Of A LIKE Or GLOB Pattern - * The pattern matching algorithm used in the default LIKE and GLOB implementation - * of SQLite can exhibit O(N^2) performance (where N is the number of characters in - * the pattern) for certain pathological cases. To avoid denial-of-service attacks - * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes. - * The default value of this limit is 50000. A modern workstation can evaluate - * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly. - * The denial of service problem only comes into play when the pattern length gets - * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns - * are at most a few dozen bytes in length, paranoid application developers may - * want to reduce this parameter to something in the range of a few hundred - * if they know that external users are able to generate arbitrary patterns. - */ - public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000; - - /** - * Flag for {@link #openDatabase} to open the database for reading and writing. - * If the disk is full, this may fail even before you actually write anything. - * - * {@more} Note that the value of this flag is 0, so it is the default. - */ - public static final int OPEN_READWRITE = 0x00000000; // update native code if changing - - /** - * Flag for {@link #openDatabase} to open the database for reading only. - * This is the only reliable way to open a database if the disk may be full. - */ - public static final int OPEN_READONLY = 0x00000001; // update native code if changing - - private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing - - /** - * Flag for {@link #openDatabase} to open the database without support for localized collators. - * - * {@more} This causes the collator <code>LOCALIZED</code> not to be created. - * You must be consistent when using this flag to use the setting the database was - * created with. If this is set, {@link #setLocale} will do nothing. - */ - public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing - - /** - * Flag for {@link #openDatabase} to create the database file if it does not already exist. - */ - public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing - - /** - * Indicates whether the most-recently started transaction has been marked as successful. - */ - private boolean mInnerTransactionIsSuccessful; - - /** - * Valid during the life of a transaction, and indicates whether the entire transaction (the - * outer one and all of the inner ones) so far has been successful. - */ - private boolean mTransactionIsSuccessful; - - /** Synchronize on this when accessing the database */ - private final ReentrantLock mLock = new ReentrantLock(true); - - private long mLockAcquiredWallTime = 0L; - private long mLockAcquiredThreadTime = 0L; - - // limit the frequency of complaints about each database to one within 20 sec - // unless run command adb shell setprop log.tag.Database VERBOSE - private static final int LOCK_WARNING_WINDOW_IN_MS = 20000; - /** If the lock is held this long then a warning will be printed when it is released. */ - private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300; - private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100; - private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000; - - private long mLastLockMessageTime = 0L; - - /** Used by native code, do not rename */ - /* package */ int mNativeHandle = 0; - - /** Used to make temp table names unique */ - /* package */ int mTempTableSequence = 0; - - /** The path for the database file */ - private String mPath; - - /** The flags passed to open/create */ - private int mFlags; - - /** The optional factory to use when creating new Cursors */ - private CursorFactory mFactory; - - private WeakHashMap<SQLiteClosable, Object> mPrograms; - - private final RuntimeException mLeakedException; - - // package visible, since callers will access directly to minimize overhead in the case - // that logging is not enabled. - /* package */ final boolean mLogStats; - - /** - * @param closable - */ - void addSQLiteClosable(SQLiteClosable closable) { - lock(); - try { - mPrograms.put(closable, null); - } finally { - unlock(); - } - } - - void removeSQLiteClosable(SQLiteClosable closable) { - lock(); - try { - mPrograms.remove(closable); - } finally { - unlock(); - } - } - - @Override - protected void onAllReferencesReleased() { - if (isOpen()) { - dbclose(); - } - } - - /** - * Attempts to release memory that SQLite holds but does not require to - * operate properly. Typically this memory will come from the page cache. - * - * @return the number of bytes actually released - */ - static public native int releaseMemory(); - - /** - * Control whether or not the SQLiteDatabase is made thread-safe by using locks - * around critical sections. This is pretty expensive, so if you know that your - * DB will only be used by a single thread then you should set this to false. - * The default is true. - * @param lockingEnabled set to true to enable locks, false otherwise - */ - public void setLockingEnabled(boolean lockingEnabled) { - mLockingEnabled = lockingEnabled; - } - - /** - * If set then the SQLiteDatabase is made thread-safe by using locks - * around critical sections - */ - private boolean mLockingEnabled = true; - - /* package */ void onCorruption() { - try { - // Close the database (if we can), which will cause subsequent operations to fail. - close(); - } finally { - Log.e(TAG, "Removing corrupt database: " + mPath); - // Delete the corrupt file. Don't re-create it now -- that would just confuse people - // -- but the next time someone tries to open it, they can set it up from scratch. - new File(mPath).delete(); - } - } - - /** - * Locks the database for exclusive access. The database lock must be held when - * touch the native sqlite3* object since it is single threaded and uses - * a polling lock contention algorithm. The lock is recursive, and may be acquired - * multiple times by the same thread. This is a no-op if mLockingEnabled is false. - * - * @see #unlock() - */ - /* package */ void lock() { - if (!mLockingEnabled) return; - mLock.lock(); - if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { - if (mLock.getHoldCount() == 1) { - // Use elapsed real-time since the CPU may sleep when waiting for IO - mLockAcquiredWallTime = SystemClock.elapsedRealtime(); - mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); - } - } - } - - /** - * Locks the database for exclusive access. The database lock must be held when - * touch the native sqlite3* object since it is single threaded and uses - * a polling lock contention algorithm. The lock is recursive, and may be acquired - * multiple times by the same thread. - * - * @see #unlockForced() - */ - private void lockForced() { - mLock.lock(); - if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { - if (mLock.getHoldCount() == 1) { - // Use elapsed real-time since the CPU may sleep when waiting for IO - mLockAcquiredWallTime = SystemClock.elapsedRealtime(); - mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); - } - } - } - - /** - * Releases the database lock. This is a no-op if mLockingEnabled is false. - * - * @see #unlock() - */ - /* package */ void unlock() { - if (!mLockingEnabled) return; - if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { - if (mLock.getHoldCount() == 1) { - checkLockHoldTime(); - } - } - mLock.unlock(); - } - - /** - * Releases the database lock. - * - * @see #unlockForced() - */ - private void unlockForced() { - if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) { - if (mLock.getHoldCount() == 1) { - checkLockHoldTime(); - } - } - mLock.unlock(); - } - - private void checkLockHoldTime() { - // Use elapsed real-time since the CPU may sleep when waiting for IO - long elapsedTime = SystemClock.elapsedRealtime(); - long lockedTime = elapsedTime - mLockAcquiredWallTime; - if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT && - !Log.isLoggable(TAG, Log.VERBOSE) && - (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) { - return; - } - if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) { - int threadTime = (int) - ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000); - if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS || - lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) { - mLastLockMessageTime = elapsedTime; - String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was " - + threadTime + "ms"; - if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) { - Log.d(TAG, msg, new Exception()); - } else { - Log.d(TAG, msg); - } - } - } - } - - /** - * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of - * the work done in that transaction and all of the nested transactions will be committed or - * rolled back. The changes will be rolled back if any transaction is ended without being - * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. - * - * <p>Here is the standard idiom for transactions: - * - * <pre> - * db.beginTransaction(); - * try { - * ... - * db.setTransactionSuccessful(); - * } finally { - * db.endTransaction(); - * } - * </pre> - */ - public void beginTransaction() { - lockForced(); - boolean ok = false; - try { - // If this thread already had the lock then get out - if (mLock.getHoldCount() > 1) { - if (mInnerTransactionIsSuccessful) { - String msg = "Cannot call beginTransaction between " - + "calling setTransactionSuccessful and endTransaction"; - IllegalStateException e = new IllegalStateException(msg); - Log.e(TAG, "beginTransaction() failed", e); - throw e; - } - ok = true; - return; - } - - // This thread didn't already have the lock, so begin a database - // transaction now. - execSQL("BEGIN EXCLUSIVE;"); - mTransactionIsSuccessful = true; - mInnerTransactionIsSuccessful = false; - ok = true; - } finally { - if (!ok) { - // beginTransaction is called before the try block so we must release the lock in - // the case of failure. - unlockForced(); - } - } - } - - /** - * End a transaction. See beginTransaction for notes about how to use this and when transactions - * are committed and rolled back. - */ - public void endTransaction() { - if (!mLock.isHeldByCurrentThread()) { - throw new IllegalStateException("no transaction pending"); - } - try { - if (mInnerTransactionIsSuccessful) { - mInnerTransactionIsSuccessful = false; - } else { - mTransactionIsSuccessful = false; - } - if (mLock.getHoldCount() != 1) { - return; - } - if (mTransactionIsSuccessful) { - execSQL("COMMIT;"); - } else { - try { - execSQL("ROLLBACK;"); - } catch (SQLException e) { - if (Config.LOGD) { - Log.d(TAG, "exception during rollback, maybe the DB previously " - + "performed an auto-rollback"); - } - } - } - } finally { - unlockForced(); - if (Config.LOGV) { - Log.v(TAG, "unlocked " + Thread.currentThread() - + ", holdCount is " + mLock.getHoldCount()); - } - } - } - - /** - * Marks the current transaction as successful. Do not do any more database work between - * calling this and calling endTransaction. Do as little non-database work as possible in that - * situation too. If any errors are encountered between this and endTransaction the transaction - * will still be committed. - * - * @throws IllegalStateException if the current thread is not in a transaction or the - * transaction is already marked as successful. - */ - public void setTransactionSuccessful() { - if (!mLock.isHeldByCurrentThread()) { - throw new IllegalStateException("no transaction pending"); - } - if (mInnerTransactionIsSuccessful) { - throw new IllegalStateException( - "setTransactionSuccessful may only be called once per call to beginTransaction"); - } - mInnerTransactionIsSuccessful = true; - } - - /** - * return true if there is a transaction pending - */ - public boolean inTransaction() { - return mLock.getHoldCount() > 0; - } - - /** - * Checks if the database lock is held by this thread. - * - * @return true, if this thread is holding the database lock. - */ - public boolean isDbLockedByCurrentThread() { - return mLock.isHeldByCurrentThread(); - } - - /** - * Checks if the database is locked by another thread. This is - * just an estimate, since this status can change at any time, - * including after the call is made but before the result has - * been acted upon. - * - * @return true, if the database is locked by another thread - */ - public boolean isDbLockedByOtherThreads() { - return !mLock.isHeldByCurrentThread() && mLock.isLocked(); - } - - /** - * Temporarily end the transaction to let other threads run. The transaction is assumed to be - * successful so far. Do not call setTransactionSuccessful before calling this. When this - * returns a new transaction will have been created but not marked as successful. - * @return true if the transaction was yielded - * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock - * will not be yielded. Use yieldIfContendedSafely instead. - */ - public boolean yieldIfContended() { - return yieldIfContendedHelper(false /* do not check yielding */); - } - - /** - * Temporarily end the transaction to let other threads run. The transaction is assumed to be - * successful so far. Do not call setTransactionSuccessful before calling this. When this - * returns a new transaction will have been created but not marked as successful. This assumes - * that there are no nested transactions (beginTransaction has only been called once) and will - * through an exception if that is not the case. - * @return true if the transaction was yielded - */ - public boolean yieldIfContendedSafely() { - return yieldIfContendedHelper(true /* check yielding */); - } - - private boolean yieldIfContendedHelper(boolean checkFullyYielded) { - if (mLock.getQueueLength() == 0) { - // Reset the lock acquire time since we know that the thread was willing to yield - // the lock at this time. - mLockAcquiredWallTime = SystemClock.elapsedRealtime(); - mLockAcquiredThreadTime = Debug.threadCpuTimeNanos(); - return false; - } - setTransactionSuccessful(); - endTransaction(); - if (checkFullyYielded) { - if (this.isDbLockedByCurrentThread()) { - throw new IllegalStateException( - "Db locked more than once. yielfIfContended cannot yield"); - } - } - beginTransaction(); - return true; - } - - /** Maps table names to info about what to which _sync_time column to set - * to NULL on an update. This is used to support syncing. */ - private final Map<String, SyncUpdateInfo> mSyncUpdateInfo = - new HashMap<String, SyncUpdateInfo>(); - - public Map<String, String> getSyncedTables() { - synchronized(mSyncUpdateInfo) { - HashMap<String, String> tables = new HashMap<String, String>(); - for (String table : mSyncUpdateInfo.keySet()) { - SyncUpdateInfo info = mSyncUpdateInfo.get(table); - if (info.deletedTable != null) { - tables.put(table, info.deletedTable); - } - } - return tables; - } - } - - /** - * Internal class used to keep track what needs to be marked as changed - * when an update occurs. This is used for syncing, so the sync engine - * knows what data has been updated locally. - */ - static private class SyncUpdateInfo { - /** - * Creates the SyncUpdateInfo class. - * - * @param masterTable The table to set _sync_time to NULL in - * @param deletedTable The deleted table that corresponds to the - * master table - * @param foreignKey The key that refers to the primary key in table - */ - SyncUpdateInfo(String masterTable, String deletedTable, - String foreignKey) { - this.masterTable = masterTable; - this.deletedTable = deletedTable; - this.foreignKey = foreignKey; - } - - /** The table containing the _sync_time column */ - String masterTable; - - /** The deleted table that corresponds to the master table */ - String deletedTable; - - /** The key in the local table the row in table. It may be _id, if table - * is the local table. */ - String foreignKey; - } - - /** - * Used to allow returning sub-classes of {@link Cursor} when calling query. - */ - public interface CursorFactory { - /** - * See - * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver, - * String, SQLiteQuery)}. - */ - public Cursor newCursor(SQLiteDatabase db, - SQLiteCursorDriver masterQuery, String editTable, - SQLiteQuery query); - } - - /** - * Open the database according to the flags {@link #OPEN_READWRITE} - * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}. - * - * <p>Sets the locale of the database to the the system's current locale. - * Call {@link #setLocale} if you would like something else.</p> - * - * @param path to database file to open and/or create - * @param factory an optional factory class that is called to instantiate a - * cursor when query is called, or null for default - * @param flags to control database access mode - * @return the newly opened database - * @throws SQLiteException if the database cannot be opened - */ - public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) { - SQLiteDatabase db = null; - try { - // Open the database. - return new SQLiteDatabase(path, factory, flags); - } catch (SQLiteDatabaseCorruptException e) { - // Try to recover from this, if we can. - // TODO: should we do this for other open failures? - Log.e(TAG, "Deleting and re-creating corrupt database " + path, e); - new File(path).delete(); - return new SQLiteDatabase(path, factory, flags); - } - } - - /** - * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY). - */ - public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) { - return openOrCreateDatabase(file.getPath(), factory); - } - - /** - * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY). - */ - public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) { - return openDatabase(path, factory, CREATE_IF_NECESSARY); - } - - /** - * Create a memory backed SQLite database. Its contents will be destroyed - * when the database is closed. - * - * <p>Sets the locale of the database to the the system's current locale. - * Call {@link #setLocale} if you would like something else.</p> - * - * @param factory an optional factory class that is called to instantiate a - * cursor when query is called - * @return a SQLiteDatabase object, or null if the database can't be created - */ - public static SQLiteDatabase create(CursorFactory factory) { - // This is a magic string with special meaning for SQLite. - return openDatabase(":memory:", factory, CREATE_IF_NECESSARY); - } - - /** - * Close the database. - */ - public void close() { - lock(); - try { - closeClosable(); - releaseReference(); - } finally { - unlock(); - } - } - - private void closeClosable() { - Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry<SQLiteClosable, Object> entry = iter.next(); - SQLiteClosable program = entry.getKey(); - if (program != null) { - program.onAllReferencesReleasedFromContainer(); - } - } - } - - /** - * Native call to close the database. - */ - private native void dbclose(); - - /** - * Gets the database version. - * - * @return the database version - */ - public int getVersion() { - SQLiteStatement prog = null; - lock(); - try { - prog = new SQLiteStatement(this, "PRAGMA user_version;"); - long version = prog.simpleQueryForLong(); - return (int) version; - } finally { - if (prog != null) prog.close(); - unlock(); - } - } - - /** - * Sets the database version. - * - * @param version the new database version - */ - public void setVersion(int version) { - execSQL("PRAGMA user_version = " + version); - } - - /** - * Returns the maximum size the database may grow to. - * - * @return the new maximum database size - */ - public long getMaximumSize() { - SQLiteStatement prog = null; - lock(); - try { - prog = new SQLiteStatement(this, - "PRAGMA max_page_count;"); - long pageCount = prog.simpleQueryForLong(); - return pageCount * getPageSize(); - } finally { - if (prog != null) prog.close(); - unlock(); - } - } - - /** - * Sets the maximum size the database will grow to. The maximum size cannot - * be set below the current size. - * - * @param numBytes the maximum database size, in bytes - * @return the new maximum database size - */ - public long setMaximumSize(long numBytes) { - SQLiteStatement prog = null; - lock(); - try { - long pageSize = getPageSize(); - long numPages = numBytes / pageSize; - // If numBytes isn't a multiple of pageSize, bump up a page - if ((numBytes % pageSize) != 0) { - numPages++; - } - prog = new SQLiteStatement(this, - "PRAGMA max_page_count = " + numPages); - long newPageCount = prog.simpleQueryForLong(); - return newPageCount * pageSize; - } finally { - if (prog != null) prog.close(); - unlock(); - } - } - - /** - * Returns the maximum size the database may grow to. - * - * @return the new maximum database size - */ - public long getPageSize() { - SQLiteStatement prog = null; - lock(); - try { - prog = new SQLiteStatement(this, - "PRAGMA page_size;"); - long size = prog.simpleQueryForLong(); - return size; - } finally { - if (prog != null) prog.close(); - unlock(); - } - } - - /** - * Sets the database page size. The page size must be a power of two. This - * method does not work if any data has been written to the database file, - * and must be called right after the database has been created. - * - * @param numBytes the database page size, in bytes - */ - public void setPageSize(long numBytes) { - execSQL("PRAGMA page_size = " + numBytes); - } - - /** - * Mark this table as syncable. When an update occurs in this table the - * _sync_dirty field will be set to ensure proper syncing operation. - * - * @param table the table to mark as syncable - * @param deletedTable The deleted table that corresponds to the - * syncable table - */ - public void markTableSyncable(String table, String deletedTable) { - markTableSyncable(table, "_id", table, deletedTable); - } - - /** - * Mark this table as syncable, with the _sync_dirty residing in another - * table. When an update occurs in this table the _sync_dirty field of the - * row in updateTable with the _id in foreignKey will be set to - * ensure proper syncing operation. - * - * @param table an update on this table will trigger a sync time removal - * @param foreignKey this is the column in table whose value is an _id in - * updateTable - * @param updateTable this is the table that will have its _sync_dirty - */ - public void markTableSyncable(String table, String foreignKey, - String updateTable) { - markTableSyncable(table, foreignKey, updateTable, null); - } - - /** - * Mark this table as syncable, with the _sync_dirty residing in another - * table. When an update occurs in this table the _sync_dirty field of the - * row in updateTable with the _id in foreignKey will be set to - * ensure proper syncing operation. - * - * @param table an update on this table will trigger a sync time removal - * @param foreignKey this is the column in table whose value is an _id in - * updateTable - * @param updateTable this is the table that will have its _sync_dirty - * @param deletedTable The deleted table that corresponds to the - * updateTable - */ - private void markTableSyncable(String table, String foreignKey, - String updateTable, String deletedTable) { - lock(); - try { - native_execSQL("SELECT _sync_dirty FROM " + updateTable - + " LIMIT 0"); - native_execSQL("SELECT " + foreignKey + " FROM " + table - + " LIMIT 0"); - } finally { - unlock(); - } - - SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable, - foreignKey); - synchronized (mSyncUpdateInfo) { - mSyncUpdateInfo.put(table, info); - } - } - - /** - * Call for each row that is updated in a cursor. - * - * @param table the table the row is in - * @param rowId the row ID of the updated row - */ - /* package */ void rowUpdated(String table, long rowId) { - SyncUpdateInfo info; - synchronized (mSyncUpdateInfo) { - info = mSyncUpdateInfo.get(table); - } - if (info != null) { - execSQL("UPDATE " + info.masterTable - + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey - + " FROM " + table + " WHERE _id=" + rowId + ")"); - } - } - - /** - * Finds the name of the first table, which is editable. - * - * @param tables a list of tables - * @return the first table listed - */ - public static String findEditTable(String tables) { - if (!TextUtils.isEmpty(tables)) { - // find the first word terminated by either a space or a comma - int spacepos = tables.indexOf(' '); - int commapos = tables.indexOf(','); - - if (spacepos > 0 && (spacepos < commapos || commapos < 0)) { - return tables.substring(0, spacepos); - } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) { - return tables.substring(0, commapos); - } - return tables; - } else { - throw new IllegalStateException("Invalid tables"); - } - } - - /** - * Compiles an SQL statement into a reusable pre-compiled statement object. - * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the - * statement and fill in those values with {@link SQLiteProgram#bindString} - * and {@link SQLiteProgram#bindLong} each time you want to run the - * statement. Statements may not return result sets larger than 1x1. - * - * @param sql The raw SQL statement, may contain ? for unknown values to be - * bound later. - * @return a pre-compiled statement object. - */ - public SQLiteStatement compileStatement(String sql) throws SQLException { - lock(); - try { - return new SQLiteStatement(this, sql); - } finally { - unlock(); - } - } - - /** - * Query the given URL, returning a {@link Cursor} over the result set. - * - * @param distinct true if you want each row to be unique, false otherwise. - * @param table The table name to compile the query against. - * @param columns A list of which columns to return. Passing null will - * return all columns, which is discouraged to prevent reading - * data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, formatted as an - * SQL WHERE clause (excluding the WHERE itself). Passing null - * will return all rows for the given table. - * @param selectionArgs You may include ?s in selection, which will be - * replaced by the values from selectionArgs, in order that they - * appear in the selection. The values will be bound as Strings. - * @param groupBy A filter declaring how to group rows, formatted as an SQL - * GROUP BY clause (excluding the GROUP BY itself). Passing null - * will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in the cursor, - * if row grouping is being used, formatted as an SQL HAVING - * clause (excluding the HAVING itself). Passing null will cause - * all row groups to be included, and is required when row - * grouping is not being used. - * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause - * (excluding the ORDER BY itself). Passing null will use the - * default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return A Cursor object, which is positioned before the first entry - * @see Cursor - */ - public Cursor query(boolean distinct, String table, String[] columns, - String selection, String[] selectionArgs, String groupBy, - String having, String orderBy, String limit) { - return queryWithFactory(null, distinct, table, columns, selection, selectionArgs, - groupBy, having, orderBy, limit); - } - - /** - * Query the given URL, returning a {@link Cursor} over the result set. - * - * @param cursorFactory the cursor factory to use, or null for the default factory - * @param distinct true if you want each row to be unique, false otherwise. - * @param table The table name to compile the query against. - * @param columns A list of which columns to return. Passing null will - * return all columns, which is discouraged to prevent reading - * data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, formatted as an - * SQL WHERE clause (excluding the WHERE itself). Passing null - * will return all rows for the given table. - * @param selectionArgs You may include ?s in selection, which will be - * replaced by the values from selectionArgs, in order that they - * appear in the selection. The values will be bound as Strings. - * @param groupBy A filter declaring how to group rows, formatted as an SQL - * GROUP BY clause (excluding the GROUP BY itself). Passing null - * will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in the cursor, - * if row grouping is being used, formatted as an SQL HAVING - * clause (excluding the HAVING itself). Passing null will cause - * all row groups to be included, and is required when row - * grouping is not being used. - * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause - * (excluding the ORDER BY itself). Passing null will use the - * default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return A Cursor object, which is positioned before the first entry - * @see Cursor - */ - public Cursor queryWithFactory(CursorFactory cursorFactory, - boolean distinct, String table, String[] columns, - String selection, String[] selectionArgs, String groupBy, - String having, String orderBy, String limit) { - String sql = SQLiteQueryBuilder.buildQueryString( - distinct, table, columns, selection, groupBy, having, orderBy, limit); - - return rawQueryWithFactory( - cursorFactory, sql, selectionArgs, findEditTable(table)); - } - - /** - * Query the given table, returning a {@link Cursor} over the result set. - * - * @param table The table name to compile the query against. - * @param columns A list of which columns to return. Passing null will - * return all columns, which is discouraged to prevent reading - * data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, formatted as an - * SQL WHERE clause (excluding the WHERE itself). Passing null - * will return all rows for the given table. - * @param selectionArgs You may include ?s in selection, which will be - * replaced by the values from selectionArgs, in order that they - * appear in the selection. The values will be bound as Strings. - * @param groupBy A filter declaring how to group rows, formatted as an SQL - * GROUP BY clause (excluding the GROUP BY itself). Passing null - * will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in the cursor, - * if row grouping is being used, formatted as an SQL HAVING - * clause (excluding the HAVING itself). Passing null will cause - * all row groups to be included, and is required when row - * grouping is not being used. - * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause - * (excluding the ORDER BY itself). Passing null will use the - * default sort order, which may be unordered. - * @return A {@link Cursor} object, which is positioned before the first entry - * @see Cursor - */ - public Cursor query(String table, String[] columns, String selection, - String[] selectionArgs, String groupBy, String having, - String orderBy) { - - return query(false, table, columns, selection, selectionArgs, groupBy, - having, orderBy, null /* limit */); - } - - /** - * Query the given table, returning a {@link Cursor} over the result set. - * - * @param table The table name to compile the query against. - * @param columns A list of which columns to return. Passing null will - * return all columns, which is discouraged to prevent reading - * data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, formatted as an - * SQL WHERE clause (excluding the WHERE itself). Passing null - * will return all rows for the given table. - * @param selectionArgs You may include ?s in selection, which will be - * replaced by the values from selectionArgs, in order that they - * appear in the selection. The values will be bound as Strings. - * @param groupBy A filter declaring how to group rows, formatted as an SQL - * GROUP BY clause (excluding the GROUP BY itself). Passing null - * will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in the cursor, - * if row grouping is being used, formatted as an SQL HAVING - * clause (excluding the HAVING itself). Passing null will cause - * all row groups to be included, and is required when row - * grouping is not being used. - * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause - * (excluding the ORDER BY itself). Passing null will use the - * default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return A {@link Cursor} object, which is positioned before the first entry - * @see Cursor - */ - public Cursor query(String table, String[] columns, String selection, - String[] selectionArgs, String groupBy, String having, - String orderBy, String limit) { - - return query(false, table, columns, selection, selectionArgs, groupBy, - having, orderBy, limit); - } - - /** - * Runs the provided SQL and returns a {@link Cursor} over the result set. - * - * @param sql the SQL query. The SQL string must not be ; terminated - * @param selectionArgs You may include ?s in where clause in the query, - * which will be replaced by the values from selectionArgs. The - * values will be bound as Strings. - * @return A {@link Cursor} object, which is positioned before the first entry - */ - public Cursor rawQuery(String sql, String[] selectionArgs) { - return rawQueryWithFactory(null, sql, selectionArgs, null); - } - - /** - * Runs the provided SQL and returns a cursor over the result set. - * - * @param cursorFactory the cursor factory to use, or null for the default factory - * @param sql the SQL query. The SQL string must not be ; terminated - * @param selectionArgs You may include ?s in where clause in the query, - * which will be replaced by the values from selectionArgs. The - * values will be bound as Strings. - * @param editTable the name of the first table, which is editable - * @return A {@link Cursor} object, which is positioned before the first entry - */ - public Cursor rawQueryWithFactory( - CursorFactory cursorFactory, String sql, String[] selectionArgs, - String editTable) { - long timeStart = 0; - - if (Config.LOGV) { - timeStart = System.currentTimeMillis(); - } - - SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable); - - try { - return driver.query( - cursorFactory != null ? cursorFactory : mFactory, - selectionArgs); - } finally { - if (Config.LOGV) { - long duration = System.currentTimeMillis() - timeStart; - - Log.v(SQLiteCursor.TAG, - "query (" + duration + " ms): " + driver.toString() + ", args are " - + (selectionArgs != null - ? TextUtils.join(",", selectionArgs) - : "<null>")); - } - } - } - - /** - * Runs the provided SQL and returns a cursor over the result set. - * The cursor will read an initial set of rows and the return to the caller. - * It will continue to read in batches and send data changed notifications - * when the later batches are ready. - * @param sql the SQL query. The SQL string must not be ; terminated - * @param selectionArgs You may include ?s in where clause in the query, - * which will be replaced by the values from selectionArgs. The - * values will be bound as Strings. - * @param initialRead set the initial count of items to read from the cursor - * @param maxRead set the count of items to read on each iteration after the first - * @return A {@link Cursor} object, which is positioned before the first entry - * @hide pending API council approval - */ - public Cursor rawQuery(String sql, String[] selectionArgs, - int initialRead, int maxRead) { - SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory( - null, sql, selectionArgs, null); - c.setLoadStyle(initialRead, maxRead); - return c; - } - - /** - * Convenience method for inserting a row into the database. - * - * @param table the table to insert the row into - * @param nullColumnHack SQL doesn't allow inserting a completely empty row, - * so if initialValues is empty this column will explicitly be - * assigned a NULL value - * @param values this map contains the initial column values for the - * row. The keys should be the column names and the values the - * column values - * @return the row ID of the newly inserted row, or -1 if an error occurred - */ - public long insert(String table, String nullColumnHack, ContentValues values) { - try { - return insertWithOnConflict(table, nullColumnHack, values, null); - } catch (SQLException e) { - Log.e(TAG, "Error inserting " + values, e); - return -1; - } - } - - /** - * Convenience method for inserting a row into the database. - * - * @param table the table to insert the row into - * @param nullColumnHack SQL doesn't allow inserting a completely empty row, - * so if initialValues is empty this column will explicitly be - * assigned a NULL value - * @param values this map contains the initial column values for the - * row. The keys should be the column names and the values the - * column values - * @throws SQLException - * @return the row ID of the newly inserted row, or -1 if an error occurred - */ - public long insertOrThrow(String table, String nullColumnHack, ContentValues values) - throws SQLException { - return insertWithOnConflict(table, nullColumnHack, values, null); - } - - /** - * Convenience method for replacing a row in the database. - * - * @param table the table in which to replace the row - * @param nullColumnHack SQL doesn't allow inserting a completely empty row, - * so if initialValues is empty this row will explicitly be - * assigned a NULL value - * @param initialValues this map contains the initial column values for - * the row. The key - * @return the row ID of the newly inserted row, or -1 if an error occurred - */ - public long replace(String table, String nullColumnHack, ContentValues initialValues) { - try { - return insertWithOnConflict(table, nullColumnHack, initialValues, - ConflictAlgorithm.REPLACE); - } catch (SQLException e) { - Log.e(TAG, "Error inserting " + initialValues, e); - return -1; - } - } - - /** - * Convenience method for replacing a row in the database. - * - * @param table the table in which to replace the row - * @param nullColumnHack SQL doesn't allow inserting a completely empty row, - * so if initialValues is empty this row will explicitly be - * assigned a NULL value - * @param initialValues this map contains the initial column values for - * the row. The key - * @throws SQLException - * @return the row ID of the newly inserted row, or -1 if an error occurred - */ - public long replaceOrThrow(String table, String nullColumnHack, - ContentValues initialValues) throws SQLException { - return insertWithOnConflict(table, nullColumnHack, initialValues, - ConflictAlgorithm.REPLACE); - } - - /** - * General method for inserting a row into the database. - * - * @param table the table to insert the row into - * @param nullColumnHack SQL doesn't allow inserting a completely empty row, - * so if initialValues is empty this column will explicitly be - * assigned a NULL value - * @param initialValues this map contains the initial column values for the - * row. The keys should be the column names and the values the - * column values - * @param algorithm {@link ConflictAlgorithm} for insert conflict resolver - * @return the row ID of the newly inserted row, or -1 if an error occurred - * @hide - */ - public long insertWithOnConflict(String table, String nullColumnHack, - ContentValues initialValues, ConflictAlgorithm algorithm) { - if (!isOpen()) { - throw new IllegalStateException("database not open"); - } - - // Measurements show most sql lengths <= 152 - StringBuilder sql = new StringBuilder(152); - sql.append("INSERT"); - if (algorithm != null) { - sql.append(" OR "); - sql.append(algorithm.value()); - } - sql.append(" INTO "); - sql.append(table); - // Measurements show most values lengths < 40 - StringBuilder values = new StringBuilder(40); - - Set<Map.Entry<String, Object>> entrySet = null; - if (initialValues != null && initialValues.size() > 0) { - entrySet = initialValues.valueSet(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - sql.append('('); - - boolean needSeparator = false; - while (entriesIter.hasNext()) { - if (needSeparator) { - sql.append(", "); - values.append(", "); - } - needSeparator = true; - Map.Entry<String, Object> entry = entriesIter.next(); - sql.append(entry.getKey()); - values.append('?'); - } - - sql.append(')'); - } else { - sql.append("(" + nullColumnHack + ") "); - values.append("NULL"); - } - - sql.append(" VALUES("); - sql.append(values); - sql.append(");"); - - lock(); - SQLiteStatement statement = null; - try { - statement = compileStatement(sql.toString()); - - // Bind the values - if (entrySet != null) { - int size = entrySet.size(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - for (int i = 0; i < size; i++) { - Map.Entry<String, Object> entry = entriesIter.next(); - DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue()); - } - } - - // Run the program and then cleanup - statement.execute(); - - long insertedRowId = lastInsertRow(); - if (insertedRowId == -1) { - Log.e(TAG, "Error inserting " + initialValues + " using " + sql); - } else { - if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Inserting row " + insertedRowId + " from " - + initialValues + " using " + sql); - } - } - return insertedRowId; - } catch (SQLiteDatabaseCorruptException e) { - onCorruption(); - throw e; - } finally { - if (statement != null) { - statement.close(); - } - unlock(); - } - } - - /** - * Convenience method for deleting rows in the database. - * - * @param table the table to delete from - * @param whereClause the optional WHERE clause to apply when deleting. - * Passing null will delete all rows. - * @return the number of rows affected if a whereClause is passed in, 0 - * otherwise. To remove all rows and get a count pass "1" as the - * whereClause. - */ - public int delete(String table, String whereClause, String[] whereArgs) { - if (!isOpen()) { - throw new IllegalStateException("database not open"); - } - lock(); - SQLiteStatement statement = null; - try { - statement = compileStatement("DELETE FROM " + table - + (!TextUtils.isEmpty(whereClause) - ? " WHERE " + whereClause : "")); - if (whereArgs != null) { - int numArgs = whereArgs.length; - for (int i = 0; i < numArgs; i++) { - DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]); - } - } - statement.execute(); - statement.close(); - return lastChangeCount(); - } catch (SQLiteDatabaseCorruptException e) { - onCorruption(); - throw e; - } finally { - if (statement != null) { - statement.close(); - } - unlock(); - } - } - - /** - * Convenience method for updating rows in the database. - * - * @param table the table to update in - * @param values a map from column names to new column values. null is a - * valid value that will be translated to NULL. - * @param whereClause the optional WHERE clause to apply when updating. - * Passing null will update all rows. - * @return the number of rows affected - */ - public int update(String table, ContentValues values, String whereClause, String[] whereArgs) { - return updateWithOnConflict(table, values, whereClause, whereArgs, null); - } - - /** - * Convenience method for updating rows in the database. - * - * @param table the table to update in - * @param values a map from column names to new column values. null is a - * valid value that will be translated to NULL. - * @param whereClause the optional WHERE clause to apply when updating. - * Passing null will update all rows. - * @param algorithm {@link ConflictAlgorithm} for update conflict resolver - * @return the number of rows affected - * @hide - */ - public int updateWithOnConflict(String table, ContentValues values, - String whereClause, String[] whereArgs, ConflictAlgorithm algorithm) { - if (!isOpen()) { - throw new IllegalStateException("database not open"); - } - - if (values == null || values.size() == 0) { - throw new IllegalArgumentException("Empty values"); - } - - StringBuilder sql = new StringBuilder(120); - sql.append("UPDATE "); - if (algorithm != null) { - sql.append(" OR "); - sql.append(algorithm.value()); - } - - sql.append(table); - sql.append(" SET "); - - Set<Map.Entry<String, Object>> entrySet = values.valueSet(); - Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator(); - - while (entriesIter.hasNext()) { - Map.Entry<String, Object> entry = entriesIter.next(); - sql.append(entry.getKey()); - sql.append("=?"); - if (entriesIter.hasNext()) { - sql.append(", "); - } - } - - if (!TextUtils.isEmpty(whereClause)) { - sql.append(" WHERE "); - sql.append(whereClause); - } - - lock(); - SQLiteStatement statement = null; - try { - statement = compileStatement(sql.toString()); - - // Bind the values - int size = entrySet.size(); - entriesIter = entrySet.iterator(); - int bindArg = 1; - for (int i = 0; i < size; i++) { - Map.Entry<String, Object> entry = entriesIter.next(); - DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue()); - bindArg++; - } - - if (whereArgs != null) { - size = whereArgs.length; - for (int i = 0; i < size; i++) { - statement.bindString(bindArg, whereArgs[i]); - bindArg++; - } - } - - // Run the program and then cleanup - statement.execute(); - statement.close(); - int numChangedRows = lastChangeCount(); - if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql); - } - return numChangedRows; - } catch (SQLiteDatabaseCorruptException e) { - onCorruption(); - throw e; - } catch (SQLException e) { - Log.e(TAG, "Error updating " + values + " using " + sql); - throw e; - } finally { - if (statement != null) { - statement.close(); - } - unlock(); - } - } - - /** - * Execute a single SQL statement that is not a query. For example, CREATE - * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not - * supported. it takes a write lock - * - * @throws SQLException If the SQL string is invalid for some reason - */ - public void execSQL(String sql) throws SQLException { - boolean logStats = mLogStats; - long timeStart = logStats ? SystemClock.elapsedRealtime() : 0; - lock(); - try { - native_execSQL(sql); - } catch (SQLiteDatabaseCorruptException e) { - onCorruption(); - throw e; - } finally { - unlock(); - } - if (logStats) { - logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime()); - } - } - - /** - * Execute a single SQL statement that is not a query. For example, CREATE - * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not - * supported. it takes a write lock, - * - * @param sql - * @param bindArgs only byte[], String, Long and Double are supported in bindArgs. - * @throws SQLException If the SQL string is invalid for some reason - */ - public void execSQL(String sql, Object[] bindArgs) throws SQLException { - if (bindArgs == null) { - throw new IllegalArgumentException("Empty bindArgs"); - } - - boolean logStats = mLogStats; - long timeStart = logStats ? SystemClock.elapsedRealtime() : 0; - lock(); - SQLiteStatement statement = null; - try { - statement = compileStatement(sql); - if (bindArgs != null) { - int numArgs = bindArgs.length; - for (int i = 0; i < numArgs; i++) { - DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]); - } - } - statement.execute(); - } catch (SQLiteDatabaseCorruptException e) { - onCorruption(); - throw e; - } finally { - if (statement != null) { - statement.close(); - } - unlock(); - } - if (logStats) { - logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime()); - } - } - - @Override - protected void finalize() { - if (isOpen()) { - if (mPrograms.isEmpty()) { - Log.e(TAG, "Leak found", mLeakedException); - } else { - IllegalStateException leakProgram = new IllegalStateException( - "mPrograms size " + mPrograms.size(), mLeakedException); - Log.e(TAG, "Leak found", leakProgram); - } - closeClosable(); - onAllReferencesReleased(); - } - } - - /** - * Private constructor. See {@link #create} and {@link #openDatabase}. - * - * @param path The full path to the database - * @param factory The factory to use when creating cursors, may be NULL. - * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already - * exists, mFlags will be updated appropriately. - */ - private SQLiteDatabase(String path, CursorFactory factory, int flags) { - if (path == null) { - throw new IllegalArgumentException("path should not be null"); - } - mFlags = flags; - mPath = path; - mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats")); - - mLeakedException = new IllegalStateException(path + - " SQLiteDatabase created and never closed"); - mFactory = factory; - dbopen(mPath, mFlags); - mPrograms = new WeakHashMap<SQLiteClosable,Object>(); - try { - setLocale(Locale.getDefault()); - } catch (RuntimeException e) { - Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e); - dbclose(); - throw e; - } - } - - /** - * return whether the DB is opened as read only. - * @return true if DB is opened as read only - */ - public boolean isReadOnly() { - return (mFlags & OPEN_READ_MASK) == OPEN_READONLY; - } - - /** - * @return true if the DB is currently open (has not been closed) - */ - public boolean isOpen() { - return mNativeHandle != 0; - } - - public boolean needUpgrade(int newVersion) { - return newVersion > getVersion(); - } - - /** - * Getter for the path to the database file. - * - * @return the path to our database file. - */ - public final String getPath() { - return mPath; - } - - /* package */ void logTimeStat(boolean read, long begin, long end) { - EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin); - } - - /** - * Sets the locale for this database. Does nothing if this database has - * the NO_LOCALIZED_COLLATORS flag set or was opened read only. - * @throws SQLException if the locale could not be set. The most common reason - * for this is that there is no collator available for the locale you requested. - * In this case the database remains unchanged. - */ - public void setLocale(Locale locale) { - lock(); - try { - native_setLocale(locale.toString(), mFlags); - } finally { - unlock(); - } - } - - /** - * Native call to open the database. - * - * @param path The full path to the database - */ - private native void dbopen(String path, int flags); - - /** - * Native call to execute a raw SQL statement. {@link #lock} must be held - * when calling this method. - * - * @param sql The raw SQL string - * @throws SQLException - */ - /* package */ native void native_execSQL(String sql) throws SQLException; - - /** - * Native call to set the locale. {@link #lock} must be held when calling - * this method. - * @throws SQLException - */ - /* package */ native void native_setLocale(String loc, int flags); - - /** - * Returns the row ID of the last row inserted into the database. - * - * @return the row ID of the last row inserted into the database. - */ - /* package */ native long lastInsertRow(); - - /** - * Returns the number of changes made in the last statement executed. - * - * @return the number of changes made in the last statement executed. - */ - /* package */ native int lastChangeCount(); -} diff --git a/core/java/android/database/sqlite/SQLiteDatabaseCorruptException.java b/core/java/android/database/sqlite/SQLiteDatabaseCorruptException.java deleted file mode 100644 index 73b6c0c..0000000 --- a/core/java/android/database/sqlite/SQLiteDatabaseCorruptException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that the SQLite database file is corrupt. - */ -public class SQLiteDatabaseCorruptException extends SQLiteException { - public SQLiteDatabaseCorruptException() {} - - public SQLiteDatabaseCorruptException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java deleted file mode 100644 index d04afb0..0000000 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.util.Config; - -/** - * Provides debugging info about all SQLite databases running in the current process. - * - * {@hide} - */ -public final class SQLiteDebug { - /** - * Controls the printing of SQL statements as they are executed. - */ - public static final boolean DEBUG_SQL_STATEMENTS = Config.LOGV; - - /** - * Controls the stack trace reporting of active cursors being - * finalized. - */ - public static final boolean DEBUG_ACTIVE_CURSOR_FINALIZATION = Config.LOGV; - - /** - * Controls the tracking of time spent holding the database lock. - */ - public static final boolean DEBUG_LOCK_TIME_TRACKING = false; - - /** - * Controls the printing of stack traces when tracking the time spent holding the database lock. - */ - public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE = false; - - /** - * Contains statistics about the active pagers in the current process. - * - * @see #getPagerStats(PagerStats) - */ - public static class PagerStats { - /** The total number of bytes in all pagers in the current process */ - public long totalBytes; - /** The number of bytes in referenced pages in all pagers in the current process */ - public long referencedBytes; - /** The number of bytes in all database files opened in the current process */ - public long databaseBytes; - /** The number of pagers opened in the current process */ - public int numPagers; - } - - /** - * Gathers statistics about all pagers in the current process. - */ - public static native void getPagerStats(PagerStats stats); - - /** - * Returns the size of the SQLite heap. - * @return The size of the SQLite heap in bytes. - */ - public static native long getHeapSize(); - - /** - * Returns the amount of allocated memory in the SQLite heap. - * @return The allocated size in bytes. - */ - public static native long getHeapAllocatedSize(); - - /** - * Returns the amount of free memory in the SQLite heap. - * @return The freed size in bytes. - */ - public static native long getHeapFreeSize(); - - /** - * Determines the number of dirty belonging to the SQLite - * heap segments of this process. pages[0] returns the number of - * shared pages, pages[1] returns the number of private pages - */ - public static native void getHeapDirtyPages(int[] pages); - - private static int sNumActiveCursorsFinalized = 0; - - /** - * Returns the number of active cursors that have been finalized. This depends on the GC having - * run but is still useful for tests. - */ - public static int getNumActiveCursorsFinalized() { - return sNumActiveCursorsFinalized; - } - - static synchronized void notifyActiveCursorFinalized() { - sNumActiveCursorsFinalized++; - } -} diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java deleted file mode 100644 index ca64aca..0000000 --- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase.CursorFactory; -import android.util.Log; - -/** - * A cursor driver that uses the given query directly. - * - * @hide - */ -public class SQLiteDirectCursorDriver implements SQLiteCursorDriver { - private static String TAG = "SQLiteDirectCursorDriver"; - private String mEditTable; - private SQLiteDatabase mDatabase; - private Cursor mCursor; - private String mSql; - private SQLiteQuery mQuery; - - public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable) { - mDatabase = db; - mEditTable = editTable; - //TODO remove all callers that end in ; and remove this check - if (sql.charAt(sql.length() - 1) == ';') { - Log.w(TAG, "Found SQL string that ends in ; -- " + sql); - sql = sql.substring(0, sql.length() - 1); - } - mSql = sql; - } - - public Cursor query(CursorFactory factory, String[] selectionArgs) { - // Compile the query - SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs); - - try { - // Arg binding - int numArgs = selectionArgs == null ? 0 : selectionArgs.length; - for (int i = 0; i < numArgs; i++) { - query.bindString(i + 1, selectionArgs[i]); - } - - // Create the cursor - if (factory == null) { - mCursor = new SQLiteCursor(mDatabase, this, mEditTable, query); - } else { - mCursor = factory.newCursor(mDatabase, this, mEditTable, query); - } - - mQuery = query; - query = null; - return mCursor; - } finally { - // Make sure this object is cleaned up if something happens - if (query != null) query.close(); - } - } - - public void cursorClosed() { - mCursor = null; - } - - public void setBindArguments(String[] bindArgs) { - final int numArgs = bindArgs.length; - for (int i = 0; i < numArgs; i++) { - mQuery.bindString(i + 1, bindArgs[i]); - } - } - - public void cursorDeactivated() { - // Do nothing - } - - public void cursorRequeried(Cursor cursor) { - // Do nothing - } - - @Override - public String toString() { - return "SQLiteDirectCursorDriver: " + mSql; - } -} diff --git a/core/java/android/database/sqlite/SQLiteDiskIOException.java b/core/java/android/database/sqlite/SQLiteDiskIOException.java deleted file mode 100644 index 01b2069..0000000 --- a/core/java/android/database/sqlite/SQLiteDiskIOException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that an IO error occured while accessing the - * SQLite database file. - */ -public class SQLiteDiskIOException extends SQLiteException { - public SQLiteDiskIOException() {} - - public SQLiteDiskIOException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteDoneException.java b/core/java/android/database/sqlite/SQLiteDoneException.java deleted file mode 100644 index d6d3f66..0000000 --- a/core/java/android/database/sqlite/SQLiteDoneException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that the SQLite program is done. - * Thrown when an operation that expects a row (such as {@link - * SQLiteStatement#simpleQueryForString} or {@link - * SQLiteStatement#simpleQueryForLong}) does not get one. - */ -public class SQLiteDoneException extends SQLiteException { - public SQLiteDoneException() {} - - public SQLiteDoneException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteException.java b/core/java/android/database/sqlite/SQLiteException.java deleted file mode 100644 index 3a97bfb..0000000 --- a/core/java/android/database/sqlite/SQLiteException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.SQLException; - -/** - * A SQLite exception that indicates there was an error with SQL parsing or execution. - */ -public class SQLiteException extends SQLException { - public SQLiteException() {} - - public SQLiteException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteFullException.java b/core/java/android/database/sqlite/SQLiteFullException.java deleted file mode 100644 index 582d930..0000000 --- a/core/java/android/database/sqlite/SQLiteFullException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -/** - * An exception that indicates that the SQLite database is full. - */ -public class SQLiteFullException extends SQLiteException { - public SQLiteFullException() {} - - public SQLiteFullException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteMisuseException.java b/core/java/android/database/sqlite/SQLiteMisuseException.java deleted file mode 100644 index 685f3ea..0000000 --- a/core/java/android/database/sqlite/SQLiteMisuseException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2008 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -public class SQLiteMisuseException extends SQLiteException { - public SQLiteMisuseException() {} - - public SQLiteMisuseException(String error) { - super(error); - } -} diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java deleted file mode 100644 index 52aac3a..0000000 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2007 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase.CursorFactory; -import android.util.Log; - -/** - * A helper class to manage database creation and version management. - * You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and - * optionally {@link #onOpen}, and this class takes care of opening the database - * if it exists, creating it if it does not, and upgrading it as necessary. - * Transactions are used to make sure the database is always in a sensible state. - * <p>For an example, see the NotePadProvider class in the NotePad sample application, - * in the <em>samples/</em> directory of the SDK.</p> - */ -public abstract class SQLiteOpenHelper { - private static final String TAG = SQLiteOpenHelper.class.getSimpleName(); - - private final Context mContext; - private final String mName; - private final CursorFactory mFactory; - private final int mNewVersion; - - private SQLiteDatabase mDatabase = null; - private boolean mIsInitializing = false; - - /** - * Create a helper object to create, open, and/or manage a database. - * The database is not actually created or opened until one of - * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called. - * - * @param context to use to open or create the database - * @param name of the database file, or null for an in-memory database - * @param factory to use for creating cursor objects, or null for the default - * @param version number of the database (starting at 1); if the database is older, - * {@link #onUpgrade} will be used to upgrade the database - */ - public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) { - if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version); - - mContext = context; - mName = name; - mFactory = factory; - mNewVersion = version; - } - - /** - * Create and/or open a database that will be used for reading and writing. - * Once opened successfully, the database is cached, so you can call this - * method every time you need to write to the database. Make sure to call - * {@link #close} when you no longer need it. - * - * <p>Errors such as bad permissions or a full disk may cause this operation - * to fail, but future attempts may succeed if the problem is fixed.</p> - * - * @throws SQLiteException if the database cannot be opened for writing - * @return a read/write database object valid until {@link #close} is called - */ - public synchronized SQLiteDatabase getWritableDatabase() { - if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { - return mDatabase; // The database is already open for business - } - - if (mIsInitializing) { - throw new IllegalStateException("getWritableDatabase called recursively"); - } - - // If we have a read-only database open, someone could be using it - // (though they shouldn't), which would cause a lock to be held on - // the file, and our attempts to open the database read-write would - // fail waiting for the file lock. To prevent that, we acquire the - // lock on the read-only database, which shuts out other users. - - boolean success = false; - SQLiteDatabase db = null; - if (mDatabase != null) mDatabase.lock(); - try { - mIsInitializing = true; - if (mName == null) { - db = SQLiteDatabase.create(null); - } else { - db = mContext.openOrCreateDatabase(mName, 0, mFactory); - } - - int version = db.getVersion(); - if (version != mNewVersion) { - db.beginTransaction(); - try { - if (version == 0) { - onCreate(db); - } else { - onUpgrade(db, version, mNewVersion); - } - db.setVersion(mNewVersion); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - } - - onOpen(db); - success = true; - return db; - } finally { - mIsInitializing = false; - if (success) { - if (mDatabase != null) { - try { mDatabase.close(); } catch (Exception e) { } - mDatabase.unlock(); - } - mDatabase = db; - } else { - if (mDatabase != null) mDatabase.unlock(); - if (db != null) db.close(); - } - } - } - - /** - * Create and/or open a database. This will be the same object returned by - * {@link #getWritableDatabase} unless some problem, such as a full disk, - * requires the database to be opened read-only. In that case, a read-only - * database object will be returned. If the problem is fixed, a future call - * to {@link #getWritableDatabase} may succeed, in which case the read-only - * database object will be closed and the read/write object will be returned - * in the future. - * - * @throws SQLiteException if the database cannot be opened - * @return a database object valid until {@link #getWritableDatabase} - * or {@link #close} is called. - */ - public synchronized SQLiteDatabase getReadableDatabase() { - if (mDatabase != null && mDatabase.isOpen()) { - return mDatabase; // The database is already open for business - } - - if (mIsInitializing) { - throw new IllegalStateException("getReadableDatabase called recursively"); - } - - try { - return getWritableDatabase(); - } catch (SQLiteException e) { - if (mName == null) throw e; // Can't open a temp database read-only! - Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); - } - - SQLiteDatabase db = null; - try { - mIsInitializing = true; - String path = mContext.getDatabasePath(mName).getPath(); - db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY); - if (db.getVersion() != mNewVersion) { - throw new SQLiteException("Can't upgrade read-only database from version " + - db.getVersion() + " to " + mNewVersion + ": " + path); - } - - onOpen(db); - Log.w(TAG, "Opened " + mName + " in read-only mode"); - mDatabase = db; - return mDatabase; - } finally { - mIsInitializing = false; - if (db != null && db != mDatabase) db.close(); - } - } - - /** - * Close any open database object. - */ - public synchronized void close() { - if (mIsInitializing) throw new IllegalStateException("Closed during initialization"); - - if (mDatabase != null && mDatabase.isOpen()) { - mDatabase.close(); - mDatabase = null; - } - } - - /** - * Called when the database is created for the first time. This is where the - * creation of tables and the initial population of the tables should happen. - * - * @param db The database. - */ - public abstract void onCreate(SQLiteDatabase db); - - /** - * Called when the database needs to be upgraded. The implementation - * should use this method to drop tables, add tables, or do anything else it - * needs to upgrade to the new schema version. - * - * <p>The SQLite ALTER TABLE documentation can be found - * <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns - * you can use ALTER TABLE to insert them into a live table. If you rename or remove columns - * you can use ALTER TABLE to rename the old table, then create the new table and then - * populate the new table with the contents of the old table. - * - * @param db The database. - * @param oldVersion The old database version. - * @param newVersion The new database version. - */ - public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); - - /** - * Called when the database has been opened. - * Override method should check {@link SQLiteDatabase#isReadOnly} before - * updating the database. - * - * @param db The database. - */ - public void onOpen(SQLiteDatabase db) {} -} diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java deleted file mode 100644 index f89c87d..0000000 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.util.Log; - -/** - * A base class for compiled SQLite programs. - */ -public abstract class SQLiteProgram extends SQLiteClosable { - static final String TAG = "SQLiteProgram"; - - /** The database this program is compiled against. */ - protected SQLiteDatabase mDatabase; - - /** - * Native linkage, do not modify. This comes from the database and should not be modified - * in here or in the native code. - */ - protected int nHandle = 0; - - /** - * Native linkage, do not modify. When non-0 this holds a reference to a valid - * sqlite3_statement object. It is only updated by the native code, but may be - * checked in this class when the database lock is held to determine if there - * is a valid native-side program or not. - */ - protected int nStatement = 0; - - /** - * Used to find out where a cursor was allocated in case it never got - * released. - */ - private StackTraceElement[] mStackTraceElements; - - /* package */ SQLiteProgram(SQLiteDatabase db, String sql) { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - mStackTraceElements = new Exception().getStackTrace(); - } - - mDatabase = db; - db.acquireReference(); - db.addSQLiteClosable(this); - this.nHandle = db.mNativeHandle; - compile(sql, false); - } - - @Override - protected void onAllReferencesReleased() { - // Note that native_finalize() checks to make sure that nStatement is - // non-null before destroying it. - native_finalize(); - mDatabase.releaseReference(); - mDatabase.removeSQLiteClosable(this); - } - - @Override - protected void onAllReferencesReleasedFromContainer(){ - // Note that native_finalize() checks to make sure that nStatement is - // non-null before destroying it. - native_finalize(); - mDatabase.releaseReference(); - } - - /** - * Returns a unique identifier for this program. - * - * @return a unique identifier for this program - */ - public final int getUniqueId() { - return nStatement; - } - - /** - * Compiles the given SQL into a SQLite byte code program using sqlite3_prepare_v2(). If - * this method has been called previously without a call to close and forCompilation is set - * to false the previous compilation will be used. Setting forceCompilation to true will - * always re-compile the program and should be done if you pass differing SQL strings to this - * method. - * - * <P>Note: this method acquires the database lock.</P> - * - * @param sql the SQL string to compile - * @param forceCompilation forces the SQL to be recompiled in the event that there is an - * existing compiled SQL program already around - */ - protected void compile(String sql, boolean forceCompilation) { - // Only compile if we don't have a valid statement already or the caller has - // explicitly requested a recompile. - if (nStatement == 0 || forceCompilation) { - mDatabase.lock(); - try { - // Note that the native_compile() takes care of destroying any previously - // existing programs before it compiles. - acquireReference(); - native_compile(sql); - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - } - - /** - * Bind a NULL value to this statement. The value remains bound until - * {@link #clearBindings} is called. - * - * @param index The 1-based index to the parameter to bind null to - */ - public void bindNull(int index) { - acquireReference(); - try { - native_bind_null(index); - } finally { - releaseReference(); - } - } - - /** - * Bind a long value to this statement. The value remains bound until - * {@link #clearBindings} is called. - * - * @param index The 1-based index to the parameter to bind - * @param value The value to bind - */ - public void bindLong(int index, long value) { - acquireReference(); - try { - native_bind_long(index, value); - } finally { - releaseReference(); - } - } - - /** - * Bind a double value to this statement. The value remains bound until - * {@link #clearBindings} is called. - * - * @param index The 1-based index to the parameter to bind - * @param value The value to bind - */ - public void bindDouble(int index, double value) { - acquireReference(); - try { - native_bind_double(index, value); - } finally { - releaseReference(); - } - } - - /** - * Bind a String value to this statement. The value remains bound until - * {@link #clearBindings} is called. - * - * @param index The 1-based index to the parameter to bind - * @param value The value to bind - */ - public void bindString(int index, String value) { - if (value == null) { - throw new IllegalArgumentException("the bind value at index " + index + " is null"); - } - acquireReference(); - try { - native_bind_string(index, value); - } finally { - releaseReference(); - } - } - - /** - * Bind a byte array value to this statement. The value remains bound until - * {@link #clearBindings} is called. - * - * @param index The 1-based index to the parameter to bind - * @param value The value to bind - */ - public void bindBlob(int index, byte[] value) { - if (value == null) { - throw new IllegalArgumentException("the bind value at index " + index + " is null"); - } - acquireReference(); - try { - native_bind_blob(index, value); - } finally { - releaseReference(); - } - } - - /** - * Clears all existing bindings. Unset bindings are treated as NULL. - */ - public void clearBindings() { - acquireReference(); - try { - native_clear_bindings(); - } finally { - releaseReference(); - } - } - - /** - * Release this program's resources, making it invalid. - */ - public void close() { - mDatabase.lock(); - try { - releaseReference(); - } finally { - mDatabase.unlock(); - } - } - - /** - * Make sure that the native resource is cleaned up. - */ - @Override - protected void finalize() { - if (nStatement != 0) { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - String message = "Finalizing " + this + - " that has not been closed"; - - Log.d(TAG, message + "\nThis cursor was created in:"); - for (StackTraceElement ste : mStackTraceElements) { - Log.d(TAG, " " + ste); - } - } - // when in finalize() it is already removed from weakhashmap - // so it is safe to not removed itself from db - onAllReferencesReleasedFromContainer(); - } - } - - /** - * Compiles SQL into a SQLite program. - * - * <P>The database lock must be held when calling this method. - * @param sql The SQL to compile. - */ - protected final native void native_compile(String sql); - protected final native void native_finalize(); - - protected final native void native_bind_null(int index); - protected final native void native_bind_long(int index, long value); - protected final native void native_bind_double(int index, double value); - protected final native void native_bind_string(int index, String value); - protected final native void native_bind_blob(int index, byte[] value); - private final native void native_clear_bindings(); -} - diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java deleted file mode 100644 index 5bfa0e8..0000000 --- a/core/java/android/database/sqlite/SQLiteQuery.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.CursorWindow; -import android.os.SystemClock; - -/** - * A SQLite program that represents a query that reads the resulting rows into a CursorWindow. - * This class is used by SQLiteCursor and isn't useful itself. - */ -public class SQLiteQuery extends SQLiteProgram { - //private static final String TAG = "Cursor"; - - /** The index of the unbound OFFSET parameter */ - private int mOffsetIndex; - - /** The SQL used to create this query */ - private String mQuery; - - /** Args to bind on requery */ - private String[] mBindArgs; - - private boolean mClosed = false; - - /** - * Create a persistent query object. - * - * @param db The database that this query object is associated with - * @param query The SQL string for this query. - * @param offsetIndex The 1-based index to the OFFSET parameter, - */ - /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) { - super(db, query); - - mOffsetIndex = offsetIndex; - mQuery = query; - mBindArgs = bindArgs; - } - - /** - * Reads rows into a buffer. This method acquires the database lock. - * - * @param window The window to fill into - * @return number of total rows in the query - */ - /* package */ int fillWindow(CursorWindow window, - int maxRead, int lastPos) { - mDatabase.lock(); - - boolean logStats = mDatabase.mLogStats; - long startTime = logStats ? SystemClock.elapsedRealtime() : 0; - try { - acquireReference(); - try { - window.acquireReference(); - // if the start pos is not equal to 0, then most likely window is - // too small for the data set, loading by another thread - // is not safe in this situation. the native code will ignore maxRead - int numRows = native_fill_window(window, window.getStartPosition(), mOffsetIndex, - maxRead, lastPos); - if (logStats) { - mDatabase.logTimeStat(true /* read */, startTime, - SystemClock.elapsedRealtime()); - } - return numRows; - } catch (IllegalStateException e){ - // simply ignore it - return 0; - } catch (SQLiteDatabaseCorruptException e) { - mDatabase.onCorruption(); - throw e; - } finally { - window.releaseReference(); - } - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - - /** - * Get the column count for the statement. Only valid on query based - * statements. The database must be locked - * when calling this method. - * - * @return The number of column in the statement's result set. - */ - /* package */ int columnCountLocked() { - acquireReference(); - try { - return native_column_count(); - } finally { - releaseReference(); - } - } - - /** - * Retrieves the column name for the given column index. The database must be locked - * when calling this method. - * - * @param columnIndex the index of the column to get the name for - * @return The requested column's name - */ - /* package */ String columnNameLocked(int columnIndex) { - acquireReference(); - try { - return native_column_name(columnIndex); - } finally { - releaseReference(); - } - } - - /** {@hide pending API Council approval} */ - @Override - public String toString() { - return "SQLiteQuery: " + mQuery; - } - - @Override - public void close() { - super.close(); - mClosed = true; - } - - /** - * Called by SQLiteCursor when it is requeried. - */ - /* package */ void requery() { - if (mBindArgs != null) { - int len = mBindArgs.length; - try { - for (int i = 0; i < len; i++) { - super.bindString(i + 1, mBindArgs[i]); - } - } catch (SQLiteMisuseException e) { - StringBuilder errMsg = new StringBuilder("mQuery " + mQuery); - for (int i = 0; i < len; i++) { - errMsg.append(" "); - errMsg.append(mBindArgs[i]); - } - errMsg.append(" "); - IllegalStateException leakProgram = new IllegalStateException( - errMsg.toString(), e); - throw leakProgram; - } - } - } - - @Override - public void bindNull(int index) { - mBindArgs[index - 1] = null; - if (!mClosed) super.bindNull(index); - } - - @Override - public void bindLong(int index, long value) { - mBindArgs[index - 1] = Long.toString(value); - if (!mClosed) super.bindLong(index, value); - } - - @Override - public void bindDouble(int index, double value) { - mBindArgs[index - 1] = Double.toString(value); - if (!mClosed) super.bindDouble(index, value); - } - - @Override - public void bindString(int index, String value) { - mBindArgs[index - 1] = value; - if (!mClosed) super.bindString(index, value); - } - - private final native int native_fill_window(CursorWindow window, - int startPos, int offsetParam, int maxRead, int lastPos); - - private final native int native_column_count(); - - private final native String native_column_name(int columnIndex); -} diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java deleted file mode 100644 index 519a81c..0000000 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteDatabase; -import android.provider.BaseColumns; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -/** - * This is a convience class that helps build SQL queries to be sent to - * {@link SQLiteDatabase} objects. - */ -public class SQLiteQueryBuilder -{ - private static final String TAG = "SQLiteQueryBuilder"; - - private Map<String, String> mProjectionMap = null; - private String mTables = ""; - private StringBuilder mWhereClause = new StringBuilder(64); - private boolean mDistinct; - private SQLiteDatabase.CursorFactory mFactory; - - public SQLiteQueryBuilder() { - mDistinct = false; - mFactory = null; - } - - /** - * Mark the query as DISTINCT. - * - * @param distinct if true the query is DISTINCT, otherwise it isn't - */ - public void setDistinct(boolean distinct) { - mDistinct = distinct; - } - - /** - * Returns the list of tables being queried - * - * @return the list of tables being queried - */ - public String getTables() { - return mTables; - } - - /** - * Sets the list of tables to query. Multiple tables can be specified to perform a join. - * For example: - * setTables("foo, bar") - * setTables("foo LEFT OUTER JOIN bar ON (foo.id = bar.foo_id)") - * - * @param inTables the list of tables to query on - */ - public void setTables(String inTables) { - mTables = inTables; - } - - /** - * Append a chunk to the WHERE clause of the query. All chunks appended are surrounded - * by parenthesis and ANDed with the selection passed to {@link #query}. The final - * WHERE clause looks like: - * - * WHERE (<append chunk 1><append chunk2>) AND (<query() selection parameter>) - * - * @param inWhere the chunk of text to append to the WHERE clause. - */ - public void appendWhere(CharSequence inWhere) { - if (mWhereClause.length() == 0) { - mWhereClause.append('('); - } - mWhereClause.append(inWhere); - } - - /** - * Append a chunk to the WHERE clause of the query. All chunks appended are surrounded - * by parenthesis and ANDed with the selection passed to {@link #query}. The final - * WHERE clause looks like: - * - * WHERE (<append chunk 1><append chunk2>) AND (<query() selection parameter>) - * - * @param inWhere the chunk of text to append to the WHERE clause. it will be escaped - * to avoid SQL injection attacks - */ - public void appendWhereEscapeString(String inWhere) { - if (mWhereClause.length() == 0) { - mWhereClause.append('('); - } - DatabaseUtils.appendEscapedSQLString(mWhereClause, inWhere); - } - - /** - * Sets the projection map for the query. The projection map maps - * from column names that the caller passes into query to database - * column names. This is useful for renaming columns as well as - * disambiguating column names when doing joins. For example you - * could map "name" to "people.name". If a projection map is set - * it must contain all column names the user may request, even if - * the key and value are the same. - * - * @param columnMap maps from the user column names to the database column names - */ - public void setProjectionMap(Map<String, String> columnMap) { - mProjectionMap = columnMap; - } - - /** - * Sets the cursor factory to be used for the query. You can use - * one factory for all queries on a database but it is normally - * easier to specify the factory when doing this query. @param - * factory the factor to use - */ - public void setCursorFactory(SQLiteDatabase.CursorFactory factory) { - mFactory = factory; - } - - /** - * Build an SQL query string from the given clauses. - * - * @param distinct true if you want each row to be unique, false otherwise. - * @param tables The table names to compile the query against. - * @param columns A list of which columns to return. Passing null will - * return all columns, which is discouraged to prevent reading - * data from storage that isn't going to be used. - * @param where A filter declaring which rows to return, formatted as an SQL - * WHERE clause (excluding the WHERE itself). Passing null will - * return all rows for the given URL. - * @param groupBy A filter declaring how to group rows, formatted as an SQL - * GROUP BY clause (excluding the GROUP BY itself). Passing null - * will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in the cursor, - * if row grouping is being used, formatted as an SQL HAVING - * clause (excluding the HAVING itself). Passing null will cause - * all row groups to be included, and is required when row - * grouping is not being used. - * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause - * (excluding the ORDER BY itself). Passing null will use the - * default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return the SQL query string - */ - public static String buildQueryString( - boolean distinct, String tables, String[] columns, String where, - String groupBy, String having, String orderBy, String limit) { - if (TextUtils.isEmpty(groupBy) && !TextUtils.isEmpty(having)) { - throw new IllegalArgumentException( - "HAVING clauses are only permitted when using a groupBy clause"); - } - - StringBuilder query = new StringBuilder(120); - - query.append("SELECT "); - if (distinct) { - query.append("DISTINCT "); - } - if (columns != null && columns.length != 0) { - appendColumns(query, columns); - } else { - query.append("* "); - } - query.append("FROM "); - query.append(tables); - appendClause(query, " WHERE ", where); - appendClause(query, " GROUP BY ", groupBy); - appendClause(query, " HAVING ", having); - appendClause(query, " ORDER BY ", orderBy); - appendClauseEscapeClause(query, " LIMIT ", limit); - - return query.toString(); - } - - private static void appendClause(StringBuilder s, String name, String clause) { - if (!TextUtils.isEmpty(clause)) { - s.append(name); - s.append(clause); - } - } - - private static void appendClauseEscapeClause(StringBuilder s, String name, String clause) { - if (!TextUtils.isEmpty(clause)) { - s.append(name); - DatabaseUtils.appendEscapedSQLString(s, clause); - } - } - - /** - * Add the names that are non-null in columns to s, separating - * them with commas. - */ - public static void appendColumns(StringBuilder s, String[] columns) { - int n = columns.length; - - for (int i = 0; i < n; i++) { - String column = columns[i]; - - if (column != null) { - if (i > 0) { - s.append(", "); - } - s.append(column); - } - } - s.append(' '); - } - - /** - * Perform a query by combining all current settings and the - * information passed into this method. - * - * @param db the database to query on - * @param projectionIn A list of which columns to return. Passing - * null will return all columns, which is discouraged to prevent - * reading data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, - * formatted as an SQL WHERE clause (excluding the WHERE - * itself). Passing null will return all rows for the given URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. - * @param groupBy A filter declaring how to group rows, formatted - * as an SQL GROUP BY clause (excluding the GROUP BY - * itself). Passing null will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in - * the cursor, if row grouping is being used, formatted as an - * SQL HAVING clause (excluding the HAVING itself). Passing - * null will cause all row groups to be included, and is - * required when row grouping is not being used. - * @param sortOrder How to order the rows, formatted as an SQL - * ORDER BY clause (excluding the ORDER BY itself). Passing null - * will use the default sort order, which may be unordered. - * @return a cursor over the result set - * @see android.content.ContentResolver#query(android.net.Uri, String[], - * String, String[], String) - */ - public Cursor query(SQLiteDatabase db, String[] projectionIn, - String selection, String[] selectionArgs, String groupBy, - String having, String sortOrder) { - return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder, - null /* limit */); - } - - /** - * Perform a query by combining all current settings and the - * information passed into this method. - * - * @param db the database to query on - * @param projectionIn A list of which columns to return. Passing - * null will return all columns, which is discouraged to prevent - * reading data from storage that isn't going to be used. - * @param selection A filter declaring which rows to return, - * formatted as an SQL WHERE clause (excluding the WHERE - * itself). Passing null will return all rows for the given URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. - * @param groupBy A filter declaring how to group rows, formatted - * as an SQL GROUP BY clause (excluding the GROUP BY - * itself). Passing null will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in - * the cursor, if row grouping is being used, formatted as an - * SQL HAVING clause (excluding the HAVING itself). Passing - * null will cause all row groups to be included, and is - * required when row grouping is not being used. - * @param sortOrder How to order the rows, formatted as an SQL - * ORDER BY clause (excluding the ORDER BY itself). Passing null - * will use the default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return a cursor over the result set - * @see android.content.ContentResolver#query(android.net.Uri, String[], - * String, String[], String) - */ - public Cursor query(SQLiteDatabase db, String[] projectionIn, - String selection, String[] selectionArgs, String groupBy, - String having, String sortOrder, String limit) { - if (mTables == null) { - return null; - } - - String sql = buildQuery( - projectionIn, selection, selectionArgs, groupBy, having, - sortOrder, limit); - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Performing query: " + sql); - } - return db.rawQueryWithFactory( - mFactory, sql, selectionArgs, - SQLiteDatabase.findEditTable(mTables)); - } - - /** - * Construct a SELECT statement suitable for use in a group of - * SELECT statements that will be joined through UNION operators - * in buildUnionQuery. - * - * @param projectionIn A list of which columns to return. Passing - * null will return all columns, which is discouraged to - * prevent reading data from storage that isn't going to be - * used. - * @param selection A filter declaring which rows to return, - * formatted as an SQL WHERE clause (excluding the WHERE - * itself). Passing null will return all rows for the given - * URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. - * @param groupBy A filter declaring how to group rows, formatted - * as an SQL GROUP BY clause (excluding the GROUP BY itself). - * Passing null will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in - * the cursor, if row grouping is being used, formatted as an - * SQL HAVING clause (excluding the HAVING itself). Passing - * null will cause all row groups to be included, and is - * required when row grouping is not being used. - * @param sortOrder How to order the rows, formatted as an SQL - * ORDER BY clause (excluding the ORDER BY itself). Passing null - * will use the default sort order, which may be unordered. - * @param limit Limits the number of rows returned by the query, - * formatted as LIMIT clause. Passing null denotes no LIMIT clause. - * @return the resulting SQL SELECT statement - */ - public String buildQuery( - String[] projectionIn, String selection, String[] selectionArgs, - String groupBy, String having, String sortOrder, String limit) { - String[] projection = computeProjection(projectionIn); - - if (mWhereClause.length() > 0) { - mWhereClause.append(')'); - } - - // Tack on the user's selection, if present. - if (selection != null && selection.length() > 0) { - if (mWhereClause.length() > 0) { - mWhereClause.append(" AND "); - } - - mWhereClause.append('('); - mWhereClause.append(selection); - mWhereClause.append(')'); - } - - return buildQueryString( - mDistinct, mTables, projection, mWhereClause.toString(), - groupBy, having, sortOrder, limit); - } - - /** - * Construct a SELECT statement suitable for use in a group of - * SELECT statements that will be joined through UNION operators - * in buildUnionQuery. - * - * @param typeDiscriminatorColumn the name of the result column - * whose cells will contain the name of the table from which - * each row was drawn. - * @param unionColumns the names of the columns to appear in the - * result. This may include columns that do not appear in the - * table this SELECT is querying (i.e. mTables), but that do - * appear in one of the other tables in the UNION query that we - * are constructing. - * @param columnsPresentInTable a Set of the names of the columns - * that appear in this table (i.e. in the table whose name is - * mTables). Since columns in unionColumns include columns that - * appear only in other tables, we use this array to distinguish - * which ones actually are present. Other columns will have - * NULL values for results from this subquery. - * @param computedColumnsOffset all columns in unionColumns before - * this index are included under the assumption that they're - * computed and therefore won't appear in columnsPresentInTable, - * e.g. "date * 1000 as normalized_date" - * @param typeDiscriminatorValue the value used for the - * type-discriminator column in this subquery - * @param selection A filter declaring which rows to return, - * formatted as an SQL WHERE clause (excluding the WHERE - * itself). Passing null will return all rows for the given - * URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. - * @param groupBy A filter declaring how to group rows, formatted - * as an SQL GROUP BY clause (excluding the GROUP BY itself). - * Passing null will cause the rows to not be grouped. - * @param having A filter declare which row groups to include in - * the cursor, if row grouping is being used, formatted as an - * SQL HAVING clause (excluding the HAVING itself). Passing - * null will cause all row groups to be included, and is - * required when row grouping is not being used. - * @return the resulting SQL SELECT statement - */ - public String buildUnionSubQuery( - String typeDiscriminatorColumn, - String[] unionColumns, - Set<String> columnsPresentInTable, - int computedColumnsOffset, - String typeDiscriminatorValue, - String selection, - String[] selectionArgs, - String groupBy, - String having) { - int unionColumnsCount = unionColumns.length; - String[] projectionIn = new String[unionColumnsCount]; - - for (int i = 0; i < unionColumnsCount; i++) { - String unionColumn = unionColumns[i]; - - if (unionColumn.equals(typeDiscriminatorColumn)) { - projectionIn[i] = "'" + typeDiscriminatorValue + "' AS " - + typeDiscriminatorColumn; - } else if (i <= computedColumnsOffset - || columnsPresentInTable.contains(unionColumn)) { - projectionIn[i] = unionColumn; - } else { - projectionIn[i] = "NULL AS " + unionColumn; - } - } - return buildQuery( - projectionIn, selection, selectionArgs, groupBy, having, - null /* sortOrder */, - null /* limit */); - } - - /** - * Given a set of subqueries, all of which are SELECT statements, - * construct a query that returns the union of what those - * subqueries return. - * @param subQueries an array of SQL SELECT statements, all of - * which must have the same columns as the same positions in - * their results - * @param sortOrder How to order the rows, formatted as an SQL - * ORDER BY clause (excluding the ORDER BY itself). Passing - * null will use the default sort order, which may be unordered. - * @param limit The limit clause, which applies to the entire union result set - * - * @return the resulting SQL SELECT statement - */ - public String buildUnionQuery(String[] subQueries, String sortOrder, String limit) { - StringBuilder query = new StringBuilder(128); - int subQueryCount = subQueries.length; - String unionOperator = mDistinct ? " UNION " : " UNION ALL "; - - for (int i = 0; i < subQueryCount; i++) { - if (i > 0) { - query.append(unionOperator); - } - query.append(subQueries[i]); - } - appendClause(query, " ORDER BY ", sortOrder); - appendClause(query, " LIMIT ", limit); - return query.toString(); - } - - private String[] computeProjection(String[] projectionIn) { - if (projectionIn != null && projectionIn.length > 0) { - if (mProjectionMap != null) { - String[] projection = new String[projectionIn.length]; - int length = projectionIn.length; - - for (int i = 0; i < length; i++) { - String userColumn = projectionIn[i]; - String column = mProjectionMap.get(userColumn); - - if (column == null) { - throw new IllegalArgumentException( - "Invalid column " + projectionIn[i]); - } else { - projection[i] = column; - } - } - return projection; - } else { - return projectionIn; - } - } else if (mProjectionMap != null) { - // Return all columns in projection map. - Set<Entry<String, String>> entrySet = mProjectionMap.entrySet(); - String[] projection = new String[entrySet.size()]; - Iterator<Entry<String, String>> entryIter = entrySet.iterator(); - int i = 0; - - while (entryIter.hasNext()) { - Entry<String, String> entry = entryIter.next(); - - // Don't include the _count column when people ask for no projection. - if (entry.getKey().equals(BaseColumns._COUNT)) { - continue; - } - projection[i++] = entry.getValue(); - } - return projection; - } - return null; - } -} diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java deleted file mode 100644 index d169259..0000000 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 - * - * 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 - * limitations under the License. - */ - -package android.database.sqlite; - -import android.os.SystemClock; - -/** - * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused. - * The statement cannot return multiple rows, but 1x1 result sets are allowed. - * Don't use SQLiteStatement constructor directly, please use - * {@link SQLiteDatabase#compileStatement(String)} - */ -public class SQLiteStatement extends SQLiteProgram -{ - /** - * Don't use SQLiteStatement constructor directly, please use - * {@link SQLiteDatabase#compileStatement(String)} - * @param db - * @param sql - */ - /* package */ SQLiteStatement(SQLiteDatabase db, String sql) { - super(db, sql); - } - - /** - * Execute this SQL statement, if it is not a query. For example, - * CREATE TABLE, DELTE, INSERT, etc. - * - * @throws android.database.SQLException If the SQL string is invalid for - * some reason - */ - public void execute() { - mDatabase.lock(); - boolean logStats = mDatabase.mLogStats; - long startTime = logStats ? SystemClock.elapsedRealtime() : 0; - - acquireReference(); - try { - native_execute(); - if (logStats) { - mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); - } - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - - /** - * Execute this SQL statement and return the ID of the most - * recently inserted row. The SQL statement should probably be an - * INSERT for this to be a useful call. - * - * @return the row ID of the last row inserted. - * - * @throws android.database.SQLException If the SQL string is invalid for - * some reason - */ - public long executeInsert() { - mDatabase.lock(); - boolean logStats = mDatabase.mLogStats; - long startTime = logStats ? SystemClock.elapsedRealtime() : 0; - - acquireReference(); - try { - native_execute(); - if (logStats) { - mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); - } - return mDatabase.lastInsertRow(); - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - - /** - * Execute a statement that returns a 1 by 1 table with a numeric value. - * For example, SELECT COUNT(*) FROM table; - * - * @return The result of the query. - * - * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows - */ - public long simpleQueryForLong() { - mDatabase.lock(); - boolean logStats = mDatabase.mLogStats; - long startTime = logStats ? SystemClock.elapsedRealtime() : 0; - - acquireReference(); - try { - long retValue = native_1x1_long(); - if (logStats) { - mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); - } - return retValue; - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - - /** - * Execute a statement that returns a 1 by 1 table with a text value. - * For example, SELECT COUNT(*) FROM table; - * - * @return The result of the query. - * - * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows - */ - public String simpleQueryForString() { - mDatabase.lock(); - boolean logStats = mDatabase.mLogStats; - long startTime = logStats ? SystemClock.elapsedRealtime() : 0; - - acquireReference(); - try { - String retValue = native_1x1_string(); - if (logStats) { - mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); - } - return retValue; - } finally { - releaseReference(); - mDatabase.unlock(); - } - } - - private final native void native_execute(); - private final native long native_1x1_long(); - private final native String native_1x1_string(); -} diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html deleted file mode 100644 index ff0f9f5..0000000 --- a/core/java/android/database/sqlite/package.html +++ /dev/null @@ -1,20 +0,0 @@ -<HTML> -<BODY> -Contains the SQLite database management -classes that an application would use to manage its own private database. -<p> -Applications use these classes to maange private databases. If creating a -content provider, you will probably have to use these classes to create and -manage your own database to store content. See <a -href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> to learn -the conventions for implementing a content provider. See the -NotePadProvider class in the NotePad sample application in the SDK for an -example of a content provider. Android ships with SQLite version 3.4.0 -<p>If you are working with data sent to you by a provider, you will not use -these SQLite classes, but instead use the generic {@link android.database} -classes. -<p>Android ships with the sqlite3 database tool in the <code>tools/</code> -folder. You can use this tool to browse or run SQL commands on the device. Run by -typing <code>sqlite3</code> in a shell window. -</BODY> -</HTML> |