Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / android / java / src / org / chromium / chrome / browser / database / SQLiteCursor.java
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5
6 package org.chromium.chrome.browser.database;
7
8 import android.database.AbstractCursor;
9 import android.database.CursorWindow;
10 import android.util.Log;
11
12 import org.chromium.base.CalledByNative;
13
14 import java.sql.Types;
15
16 /**
17  * This class exposes the query result from native side.
18  */
19 public class SQLiteCursor extends AbstractCursor {
20     private static final String TAG = "SQLiteCursor";
21     // Used by JNI.
22     private long mNativeSQLiteCursor;
23
24     // The count of result rows.
25     private int mCount = -1;
26
27     private int[] mColumnTypes;
28
29     private final Object mColumnTypeLock = new Object();
30     private final Object mDestoryNativeLock = new Object();
31
32     // The belows are the locks for those methods that need wait for
33     // the callback result in native side.
34     private final Object mMoveLock = new Object();
35     private final Object mGetBlobLock = new Object();
36
37     private SQLiteCursor(long nativeSQLiteCursor) {
38         mNativeSQLiteCursor = nativeSQLiteCursor;
39     }
40
41     @CalledByNative
42     private static SQLiteCursor create(long nativeSQLiteCursor) {
43         return new SQLiteCursor(nativeSQLiteCursor);
44     }
45
46     @Override
47     public int getCount() {
48         synchronized (mMoveLock) {
49             if (mCount == -1)
50                 mCount = nativeGetCount(mNativeSQLiteCursor);
51         }
52         return mCount;
53     }
54
55     @Override
56     public String[] getColumnNames() {
57         return nativeGetColumnNames(mNativeSQLiteCursor);
58     }
59
60     @Override
61     public String getString(int column) {
62         return nativeGetString(mNativeSQLiteCursor, column);
63     }
64
65     @Override
66     public short getShort(int column) {
67         return (short) nativeGetInt(mNativeSQLiteCursor, column);
68     }
69
70     @Override
71     public int getInt(int column) {
72         return nativeGetInt(mNativeSQLiteCursor, column);
73     }
74
75     @Override
76     public long getLong(int column) {
77         return nativeGetLong(mNativeSQLiteCursor, column);
78     }
79
80     @Override
81     public float getFloat(int column) {
82         return (float) nativeGetDouble(mNativeSQLiteCursor, column);
83     }
84
85     @Override
86     public double getDouble(int column) {
87         return nativeGetDouble(mNativeSQLiteCursor, column);
88     }
89
90     @Override
91     public boolean isNull(int column) {
92         return nativeIsNull(mNativeSQLiteCursor, column);
93     }
94
95     @Override
96     public void close() {
97         super.close();
98         synchronized (mDestoryNativeLock) {
99             if (mNativeSQLiteCursor != 0) {
100                 nativeDestroy(mNativeSQLiteCursor);
101                 mNativeSQLiteCursor = 0;
102             }
103         }
104     }
105
106     @Override
107     public boolean onMove(int oldPosition, int newPosition) {
108         synchronized (mMoveLock) {
109             nativeMoveTo(mNativeSQLiteCursor, newPosition);
110         }
111         return super.onMove(oldPosition, newPosition);
112     }
113
114     @Override
115     public byte[] getBlob(int column) {
116         synchronized (mGetBlobLock) {
117             return nativeGetBlob(mNativeSQLiteCursor, column);
118         }
119     }
120
121     @Deprecated
122     public boolean supportsUpdates() {
123         return false;
124     }
125
126     @Override
127     protected void finalize() {
128         super.finalize();
129         if (!isClosed()) {
130             Log.w(TAG, "Cursor hasn't been closed");
131             close();
132         }
133     }
134
135     @Override
136     public void fillWindow(int position, CursorWindow window) {
137         if (position < 0 || position > getCount()) {
138             return;
139         }
140         window.acquireReference();
141         try {
142             int oldpos = mPos;
143             mPos = position - 1;
144             window.clear();
145             window.setStartPosition(position);
146             int columnNum = getColumnCount();
147             window.setNumColumns(columnNum);
148             while (moveToNext() && window.allocRow()) {
149                 for (int i = 0; i < columnNum; i++) {
150                     boolean hasRoom = true;
151                     switch (getColumnType(i)) {
152                         case Types.DOUBLE:
153                             hasRoom = fillRow(window, Double.valueOf(getDouble(i)), mPos, i);
154                             break;
155                         case Types.NUMERIC:
156                             hasRoom = fillRow(window, Long.valueOf(getLong(i)), mPos, i);
157                             break;
158                         case Types.BLOB:
159                             hasRoom = fillRow(window, getBlob(i), mPos, i);
160                             break;
161                         case Types.LONGVARCHAR:
162                             hasRoom = fillRow(window, getString(i), mPos, i);
163                             break;
164                         case Types.NULL:
165                             hasRoom = fillRow(window, null, mPos, i);
166                             break;
167                         default:
168                             // Ignore an unknown type.
169                     }
170                     if (!hasRoom) {
171                         break;
172                     }
173                 }
174             }
175             mPos = oldpos;
176         } catch (IllegalStateException e) {
177             // simply ignore it
178         } finally {
179             window.releaseReference();
180         }
181     }
182
183     /**
184      * Fill row with the given value. If the value type is other than Long,
185      * String, byte[] or Double, the NULL will be filled.
186      *
187      * @return true if succeeded, false if window is full.
188      */
189     private boolean fillRow(CursorWindow window, Object value, int pos, int column) {
190         if (putValue(window, value, pos, column)) {
191             return true;
192         } else {
193             window.freeLastRow();
194             return false;
195         }
196     }
197
198     /**
199      * Put the value in given window. If the value type is other than Long,
200      * String, byte[] or Double, the NULL will be filled.
201      *
202      * @return true if succeeded.
203      */
204     private boolean putValue(CursorWindow window, Object value, int pos, int column) {
205         if (value == null) {
206             return window.putNull(pos, column);
207         } else if (value instanceof Long) {
208             return window.putLong((Long) value, pos, column);
209         } else if (value instanceof String) {
210             return window.putString((String) value, pos, column);
211         } else if (value instanceof byte[] && ((byte[]) value).length > 0) {
212             return window.putBlob((byte[]) value, pos, column);
213         } else if (value instanceof Double) {
214             return window.putDouble((Double) value, pos, column);
215         } else {
216             return window.putNull(pos, column);
217         }
218     }
219
220     /**
221      * @param index the column index.
222      * @return the column type from cache or native side.
223      */
224     private int getColumnType(int index) {
225         synchronized (mColumnTypeLock) {
226             if (mColumnTypes == null) {
227                 int columnCount = getColumnCount();
228                 mColumnTypes = new int[columnCount];
229                 for (int i = 0; i < columnCount; i++) {
230                     mColumnTypes[i] = nativeGetColumnType(mNativeSQLiteCursor, i);
231                 }
232             }
233         }
234         return mColumnTypes[index];
235     }
236
237     private native void nativeDestroy(long nativeSQLiteCursor);
238     private native int nativeGetCount(long nativeSQLiteCursor);
239     private native String[] nativeGetColumnNames(long nativeSQLiteCursor);
240     private native int nativeGetColumnType(long nativeSQLiteCursor, int column);
241     private native String nativeGetString(long nativeSQLiteCursor, int column);
242     private native byte[] nativeGetBlob(long nativeSQLiteCursor, int column);
243     private native boolean nativeIsNull(long nativeSQLiteCursor, int column);
244     private native long nativeGetLong(long nativeSQLiteCursor, int column);
245     private native int nativeGetInt(long nativeSQLiteCursor, int column);
246     private native double nativeGetDouble(long nativeSQLiteCursor, int column);
247     private native int nativeMoveTo(long nativeSQLiteCursor, int newPosition);
248 }