summaryrefslogtreecommitdiff
path: root/data/patches/disable/0002-update-mobile-sqlite-to-v35.patch
blob: 9a99ea2302de91667630aacfb1d292b5e91cacd3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
diff -ru mobile/android/base/sqlite/ByteBufferInputStream.java /tmp/mozilla-release/mobile/android/base/sqlite/ByteBufferInputStream.java
--- a/mobile/android/base/sqlite/ByteBufferInputStream.java	2015-02-23 22:40:38.708934982 +0100
+++ b/mobile/android/base/sqlite/ByteBufferInputStream.java	2015-01-23 07:00:04.000000000 +0100
@@ -14,7 +14,7 @@
  * easier to use.
  */
 public class ByteBufferInputStream extends InputStream {
-    private ByteBuffer mByteBuffer;
+    private final ByteBuffer mByteBuffer;
 
     public ByteBufferInputStream(ByteBuffer aByteBuffer) {
         mByteBuffer = aByteBuffer;
diff -ru mobile/android/base/sqlite/MatrixBlobCursor.java /tmp/mozilla-release/mobile/android/base/sqlite/MatrixBlobCursor.java
--- a/mobile/android/base/sqlite/MatrixBlobCursor.java	2015-02-23 22:40:38.720934982 +0100
+++ b/mobile/android/base/sqlite/MatrixBlobCursor.java	2015-01-23 07:00:04.000000000 +0100
@@ -17,34 +17,37 @@
 
 package org.mozilla.gecko.sqlite;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 
 import android.database.AbstractCursor;
 import android.database.CursorIndexOutOfBoundsException;
+import android.util.Log;
 
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
-/*
- * Android's AbstractCursor throws on getBlob()
- * and MatrixCursor forgot to override it. This was fixed
- * at some point but old devices are still SOL.
- * Oh, and everything in MatrixCursor is private instead of
- * protected, so we need to entirely duplicate it here,
- * instad of just being able to add the missing method.
- */
 /**
  * A mutable cursor implementation backed by an array of {@code Object}s. Use
  * {@link #newRow()} to add rows. Automatically expands internal capacity
  * as needed.
+ *
+ * This class provides one missing feature from Android's MatrixCursor:
+ * the implementation of getBlob that was inadvertently omitted from API 9 (and
+ * perhaps later; it's present in 14).
+ *
+ * MatrixCursor is all private, so we entirely duplicate it here.
  */
 public class MatrixBlobCursor extends AbstractCursor {
+    private static final String LOGTAG = "GeckoMatrixCursor";
 
     private final String[] columnNames;
-    private Object[] data;
-    private int rowCount = 0;
     private final int columnCount;
 
+    private int rowCount;
+
+    Object[] data;
+
     /**
      * Constructs a new cursor with the given initial capacity.
      *
@@ -140,17 +143,18 @@
      */
     @WrapElementForJNI
     public void addRow(Iterable<?> columnValues) {
-        int start = rowCount * columnCount;
-        int end = start + columnCount;
-        ensureCapacity(end);
+        final int start = rowCount * columnCount;
 
         if (columnValues instanceof ArrayList<?>) {
             addRow((ArrayList<?>) columnValues, start);
             return;
         }
 
+        final int end = start + columnCount;
         int current = start;
-        Object[] localData = data;
+
+        ensureCapacity(end);
+        final Object[] localData = data;
         for (Object columnValue : columnValues) {
             if (current == end) {
                 // TODO: null out row?
@@ -173,39 +177,47 @@
     /** Optimization for {@link ArrayList}. */
     @WrapElementForJNI
     private void addRow(ArrayList<?> columnValues, int start) {
-        int size = columnValues.size();
+        final int size = columnValues.size();
         if (size != columnCount) {
             throw new IllegalArgumentException("columnNames.length = "
                     + columnCount + ", columnValues.size() = " + size);
         }
 
-        rowCount++;
-        Object[] localData = data;
+        final int end = start + columnCount;
+        ensureCapacity(end);
+
+        // Take a reference just in case someone calls ensureCapacity
+        // and `data` gets replaced by a new array!
+        final Object[] localData = data;
         for (int i = 0; i < size; i++) {
             localData[start + i] = columnValues.get(i);
         }
+
+        rowCount++;
     }
 
-    /** 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);
+    /**
+     * Ensures that this cursor has enough capacity. If it needs to allocate
+     * a new array, the existing capacity will be at least doubled.
+     */
+    private void ensureCapacity(final int size) {
+        if (size <= data.length) {
+            return;
         }
+
+        final Object[] oldData = this.data;
+        this.data = new Object[Math.max(size, data.length * 2)];
+        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.
+     *
+     * Not thread-safe.
      */
     public class RowBuilder {
-
         private int index;
         private final int endIndex;
 
@@ -221,10 +233,9 @@
          *  values
          * @return this builder to support chaining
          */
-        public RowBuilder add(Object columnValue) {
+        public RowBuilder add(final Object columnValue) {
             if (index == endIndex) {
-                throw new CursorIndexOutOfBoundsException(
-                        "No more columns left.");
+                throw new CursorIndexOutOfBoundsException("No more columns left.");
             }
 
             data[index++] = columnValue;
@@ -232,6 +243,9 @@
         }
     }
 
+    /**
+     * Not thread safe.
+     */
     public void set(int column, Object value) {
         if (column < 0 || column >= columnCount) {
             throw new CursorIndexOutOfBoundsException("Requested column: "
@@ -266,7 +280,7 @@
 
     @Override
     public short getShort(int column) {
-        Object value = get(column);
+        final Object value = get(column);
         if (value == null) return 0;
         if (value instanceof Number) return ((Number) value).shortValue();
         return Short.parseShort(value.toString());
@@ -311,10 +325,11 @@
         if (value instanceof byte[]) {
             return (byte[]) value;
         }
+
         if (value instanceof ByteBuffer) {
-            ByteBuffer data = (ByteBuffer)value;
-            byte[] byteArray = new byte[data.remaining()];
-            data.get(byteArray);
+            final ByteBuffer bytes = (ByteBuffer) value;
+            byte[] byteArray = new byte[bytes.remaining()];
+            bytes.get(byteArray);
             return byteArray;
         }
         throw new UnsupportedOperationException("BLOB Object not of known type");
@@ -324,4 +339,15 @@
     public boolean isNull(int column) {
         return get(column) == null;
     }
+
+    @Override
+    protected void finalize() {
+        if (AppConstants.DEBUG_BUILD) {
+            if (!isClosed()) {
+                Log.e(LOGTAG, "Cursor finalized without being closed", new RuntimeException("stack"));
+            }
+        }
+
+        super.finalize();
+    }
 }
diff -ru mobile/android/base/sqlite/SQLiteBridge.java /tmp/mozilla-release/mobile/android/base/sqlite/SQLiteBridge.java
--- a/mobile/android/base/sqlite/SQLiteBridge.java	2015-02-23 22:40:38.716934982 +0100
+++ b/mobile/android/base/sqlite/SQLiteBridge.java	2015-01-23 07:00:04.000000000 +0100
@@ -26,16 +26,16 @@
     private static final String LOGTAG = "SQLiteBridge";
 
     // Path to the database. If this database was not opened with openDatabase, we reopen it every query.
-    private String mDb;
+    private final String mDb;
 
     // Pointer to the database if it was opened with openDatabase. 0 implies closed.
-    protected volatile long mDbPointer = 0L;
+    protected volatile long mDbPointer;
 
     // Values remembered after a query.
     private long[] mQueryResults;
 
-    private boolean mTransactionSuccess = false;
-    private boolean mInTransaction = false;
+    private boolean mTransactionSuccess;
+    private boolean mInTransaction;
 
     private static final int RESULT_INSERT_ROW_ID = 0;
     private static final int RESULT_ROWS_CHANGED = 1;
@@ -227,6 +227,7 @@
             cursor.moveToFirst();
             String version = cursor.getString(0);
             ret = Integer.parseInt(version);
+            cursor.close();
         }
         return ret;
     }