· 7 years ago · Feb 22, 2019, 09:12 AM
1CREATE TABLE "user" (
2 "_id" INTEGER NOT NULL,
3 "user" TEXT,
4 "password" TEXT,
5 PRIMARY KEY ("_id")
6)
7
8CREATE TABLE "user" (
9 "_id" INTEGER NOT NULL,
10 "user" TEXT,
11 "password" TEXT,
12 "email" TEXT,
13 PRIMARY KEY ("_id"),
14 CONSTRAINT "user" UNIQUE ("user")
15);
16
17public class DBAssetHandler {
18
19 static final String[] tempfiles = new String[]{"-journal","-wal","-shm"}; // temporary files to rename
20 public static final String backup = "-backup"; //value to be appended to file name when renaming (psuedo delete)
21 public static final int OUCH = -666666666;
22
23 /**
24 * Check if the database already exists. NOTE will create the databases folder is it doesn't exist
25 * @return true if it exists, false if it doesn't
26 */
27 public static boolean checkDataBase(Context context, String dbname) {
28
29 File db = new File(context.getDatabasePath(dbname).getPath()); //Get the file name of the database
30 Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove if publish App
31 if (db.exists()) return true; // If it exists then return doing nothing
32
33 // Get the parent (directory in which the database file would be)
34 File dbdir = db.getParentFile();
35 // If the directory does not exits then make the directory (and higher level directories)
36 if (!dbdir.exists()) {
37 db.getParentFile().mkdirs();
38 dbdir.mkdirs();
39 }
40 return false;
41 }
42
43
44 /**
45 * Copy database file from the assets folder
46 * (long version caters for asset file name being different to the database name)
47 * @param context Context is needed to get the applicable package
48 * @param dbname name of the database file
49 * @param assetfilename name of the asset file
50 * @param deleteExistingDB true if an existing database file should be deleted
51 * note will delete journal and wal files
52 * note doen't actually delete the files rater it renames
53 * the files by appended -backup to the file name
54 * SEE/USE clearForceBackups below to delete the renamed files
55 */
56 public static void copyDataBase(Context context, String dbname, String assetfilename, boolean deleteExistingDB) {
57
58 final String TAG = "COPYDATABASE";
59 int stage = 0, buffer_size = 4096, blocks_copied = 0, bytes_copied = 0;
60 File f = new File(context.getDatabasePath(dbname).toString());
61 InputStream is;
62 OutputStream os;
63
64 /**
65 * If forcing then effectively delete (rename) current database files
66 */
67 if (deleteExistingDB) {
68 //String[] tempfiles = new String[]{"-journal","-wal","-shm"};
69 //String backup = "-backup";
70 f.renameTo(context.getDatabasePath(dbname + "-backup"));
71 for (String s: tempfiles) {
72 File tmpf = new File(context.getDatabasePath(dbname + s).toString());
73 if (tmpf.exists()) {
74 tmpf.renameTo(context.getDatabasePath(dbname + s + backup));
75 }
76 }
77 }
78
79
80 //Open your local db as the input stream
81 Log.d(TAG,"Initiated Copy of the database file " + assetfilename + " from the assets folder."); //TODO remove if publishing
82 try {
83 is = context.getAssets().open(assetfilename); // Open the Asset file
84 stage++;
85 Log.d(TAG, "Asset file " + assetfilename + " found so attmepting to copy to " + f.getPath()); //TODO remove if publishing
86
87 os = new FileOutputStream(f);
88 stage++;
89 //transfer bytes from the inputfile to the outputfile
90 byte[] buffer = new byte[buffer_size];
91 int length;
92 while ((length = is.read(buffer)) > 0) {
93 blocks_copied++;
94 Log.d(TAG, "Attempting copy of block " + String.valueOf(blocks_copied) + " which has " + String.valueOf(length) + " bytes."); //TODO remove if publishing
95 os.write(buffer, 0, length);
96 bytes_copied += length;
97 }
98 stage++;
99 Log.d(TAG,
100 "Finished copying Database " + dbname +
101 " from the assets folder, to " + f.getPath() +
102 String.valueOf(bytes_copied) + "were copied, in " +
103 String.valueOf(blocks_copied) + " blocks of size " +
104 String.valueOf(buffer_size) + "."
105 ); //TODO remove if publishing
106 //Close the streams
107 os.flush();
108 stage++;
109 os.close();
110 stage++;
111 is.close();
112 Log.d(TAG, "All Streams have been flushed and closed.");
113 } catch (IOException e) {
114 String exception_message = "";
115 e.printStackTrace();
116 switch (stage) {
117 case 0:
118 exception_message = "Error trying to open the asset " + dbname;
119 break;
120 case 1:
121 exception_message = "Error opening Database file for output, path is " + f.getPath();
122 break;
123 case 2:
124 exception_message = "Error flushing written database file " + f.getPath();
125 break;
126 case 3:
127 exception_message = "Error closing written database file " + f.getPath();
128 break;
129 case 4:
130 exception_message = "Error closing asset file " + f.getPath();
131
132 }
133 throw new RuntimeException("Unable to copy the database from the asset folder." + exception_message + " see starck-trace above.");
134 }
135 }
136
137 /**
138 * Copy the databsse from the assets folder where asset name and dbname are the same
139 * @param context
140 * @param dbname
141 * @param deleteExistingDB
142 */
143 public static void copyDataBase(Context context, String dbname, boolean deleteExistingDB) {
144 copyDataBase(context, dbname,dbname,deleteExistingDB);
145 }
146
147 /**
148 * Get the SQLite_user_vesrion from the DB in the asset folder
149 *
150 * @param context needed to get the appropriate package assets
151 * @param assetfilename the name of the asset file (assumes/requires name matches database)
152 * @return the version number as stored in the asset DB
153 */
154 public static int getVersionFromDBInAssetFolder(Context context, String assetfilename) {
155 InputStream is;
156 try {
157 is = context.getAssets().open(assetfilename);
158 } catch (IOException e) {
159 return OUCH;
160 }
161 return getDBVersionFromInputStream(is);
162 }
163
164 /**
165 * Get the version from the database itself without opening the database as an SQliteDatabase
166 * @param context Needed to ascertain package
167 * @param dbname the name of the dataabase
168 * @return the version number extracted
169 */
170 public static int getVersionFromDBFile(Context context, String dbname) {
171 InputStream is;
172 try {
173 is = new FileInputStream(new File(context.getDatabasePath(dbname).toString()));
174 } catch (IOException e) {
175 return OUCH;
176 }
177 return getDBVersionFromInputStream(is);
178 }
179
180 /**
181 * Get the Database Version (user_version) from an inputstream
182 * Note the inputstream is closed
183 * @param is The Inputstream
184 * @return The extracted version number
185 */
186 private static int getDBVersionFromInputStream(InputStream is) {
187 int rv = -1, dbversion_offset = 60, dbversion_length = 4 ;
188 byte[] dbfileheader = new byte[64];
189 byte[] dbversion = new byte[4];
190 try {
191 is.read(dbfileheader);
192 is.close();
193 } catch (IOException e) {
194 e.printStackTrace();
195 return rv;
196 }
197
198 for (int i = 0; i < dbversion_length; i++ ) {
199 dbversion[i] = dbfileheader[dbversion_offset + i];
200 }
201 return ByteBuffer.wrap(dbversion).getInt();
202 }
203
204 /**
205 * Check to see if the asset file exists
206 *
207 * @param context needed to get the appropriate package
208 * @param assetfilename the name of the asset file to check
209 * @return true if the asset file exists, else false
210 */
211 public static boolean ifAssetFileExists(Context context, String assetfilename) {
212 try {
213 context.getAssets().open(assetfilename);
214 } catch (IOException e) {
215 return false;
216 }
217 return true;
218 }
219
220
221 /**
222 * Delete the backup
223 * @param context
224 * @param dbname
225 */
226 public static void clearForceBackups(Context context, String dbname) {
227 String[] fulllist = new String[tempfiles.length + 1];
228
229 for (int i = 0;i < tempfiles.length; i++) {
230 fulllist[i] = tempfiles[i];
231 }
232 fulllist[tempfiles.length] = ""; // Add "" so database file backup is also deleted
233 for (String s: fulllist) {
234 File tmpf = new File(context.getDatabasePath(dbname + s + backup).toString());
235 if (tmpf.exists()) {
236 tmpf.delete();
237 }
238 }
239 }
240}
241
242/**
243 * MORE COMPLEX EXAMPLE RETAINING USER DATA
244 */
245public class PEV2DBHelper extends SQLiteOpenHelper {
246
247 public static final String DBNAME = "pev1.db";
248 public static final String ASSETTOCOPY_DBV2 = "pev1mod.db"; //<<<<<<<<<< changed DB
249 public static final int DBVERSION = 2; //<<<<<<<<<< increase and db file from assets will copied keeping existing data
250 Context mContext;
251
252 public PEV2DBHelper(Context context) {
253 super(context, DBNAME, null, DBVERSION);
254
255
256 int dbversion = DBAssetHandler.getVersionFromDBFile(context,DBNAME);
257 Log.d("DBFILEVERSION","Database File Version = " + String.valueOf(dbversion));
258 int af1version = DBAssetHandler.getVersionFromDBInAssetFolder(context,DBNAME);
259 Log.d("DBFILEVERSION","Asset Database File Version = " + String.valueOf(af1version));
260 int af2version = DBAssetHandler.getVersionFromDBInAssetFolder(context,ASSETTOCOPY_DBV2);
261 Log.d("DBFILEVERSION","Asset Database File Version = " + String.valueOf(af2version));
262
263 // cater for different DBVERSIONS (for testing )
264 if (!DBAssetHandler.checkDataBase(context,DBNAME)) {
265
266 //If new installation of the APP then copy the appropriate asset file for the DB
267 switch (DBVERSION) {
268 case 1:
269 DBAssetHandler.copyDataBase(context,DBNAME,DBNAME,false);
270 break;
271 case 2:
272 DBAssetHandler.copyDataBase(context,DBNAME,ASSETTOCOPY_DBV2,false);
273 break;
274 }
275 }
276
277 // If DBVERSION upgraded to 2 with modified DB but wanting to preserve used data
278 if (DBAssetHandler.checkDataBase(context,DBNAME) & (DBVERSION > DBAssetHandler.getVersionFromDBFile(context, DBNAME)) & (DBVERSION == 2) ) {
279
280 String[] oldcolumns = new String[]{"user","password"};
281
282 // Copy in the new DB noting that delete option renames old (truue flag important)
283 DBAssetHandler.copyDataBase(context,DBNAME,ASSETTOCOPY_DBV2,true);
284
285 //Get the newly copied database
286 SQLiteDatabase newdb = SQLiteDatabase.openDatabase(context.getDatabasePath(DBNAME).toString(),null,SQLiteDatabase.OPEN_READWRITE);
287 //Get the old database (backup copy)
288 SQLiteDatabase olddb = SQLiteDatabase.openDatabase(context.getDatabasePath(DBNAME + DBAssetHandler.backup).toString(),null,SQLiteDatabase.OPEN_READWRITE);
289
290 //Prepare to insert old rows (note user column is UNIQUE so pretty simple scenario just try inserting all and duplicates will be rejected)
291 ContentValues cv = new ContentValues();
292 Cursor oldcsr = olddb.query("user",null,null,null,null,null,null);
293 newdb.beginTransaction();
294 while (oldcsr.moveToNext()) {
295 cv.clear();
296 for (String columnname: oldcolumns) {
297 cv.put(columnname,oldcsr.getString(oldcsr.getColumnIndex(columnname)));
298 }
299 newdb.insert("user",null,cv);
300 }
301 newdb.setTransactionSuccessful();
302 newdb.endTransaction();
303 newdb.close();
304 olddb.close();
305
306 // Finally delete the renamed old database
307 DBAssetHandler.clearForceBackups(context,DBNAME);
308 }
309 }
310
311 @Override
312 public void onCreate(SQLiteDatabase db) {
313
314 }
315
316 @Override
317 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
318
319 }
320}
321
322public class MainActivity extends AppCompatActivity {
323
324 PEV2DBHelper mDBHlpr2; //DBHelper for example that retains user data
325
326 @Override
327 protected void onCreate(Bundle savedInstanceState) {
328 super.onCreate(savedInstanceState);
329 setContentView(R.layout.activity_main);
330
331 doPEV2(); // Test simple more complex scenario
332 }
333
334
335 private void doPEV2() {
336
337 mDBHlpr2 = new PEV2DBHelper(this);
338 SQLiteDatabase db = mDBHlpr2.getWritableDatabase();
339 Cursor csr = db.query("sqlite_master",null,null,null,null,null,null);
340 DatabaseUtils.dumpCursor(csr);
341 csr = db.query("user",null,null,null,null,null,null);
342 DatabaseUtils.dumpCursor(csr);
343 if (PEV2DBHelper.DBVERSION == 1) {
344 addUserData(db);
345 csr = db.query("user",null,null,null,null,null,null);
346 DatabaseUtils.dumpCursor(csr);
347 }
348 csr.close();
349 db.close();
350 }
351
352 /**
353 * Add some user data for testing presevation of that data
354 * @param db the SQLitedatabase
355 */
356 private void addUserData(SQLiteDatabase db) {
357 ContentValues cv = new ContentValues();
358 cv.put("user","mr new user");
359 cv.put("password","a password");
360 db.insert("user",null,cv);
361 }
362}
363
3642019-02-22 19:07:54.676 28670-28670/? D/DBFILEVERSION: Database File Version = -666666666
3652019-02-22 19:07:54.677 28670-28670/? D/DBFILEVERSION: Asset Database File Version = 0
3662019-02-22 19:07:54.677 28670-28670/? D/DBFILEVERSION: Asset Database File Version = 0
3672019-02-22 19:07:54.677 28670-28670/? D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
3682019-02-22 19:07:54.677 28670-28670/? D/COPYDATABASE: Initiated Copy of the database file pev1.db from the assets folder.
3692019-02-22 19:07:54.677 28670-28670/? D/COPYDATABASE: Asset file pev1.db found so attmepting to copy to /data/user/0/mjt.so54807516/databases/pev1.db
3702019-02-22 19:07:54.677 28670-28670/? D/COPYDATABASE: Attempting copy of block 1 which has 4096 bytes.
3712019-02-22 19:07:54.677 28670-28670/? D/COPYDATABASE: Attempting copy of block 2 which has 4096 bytes.
3722019-02-22 19:07:54.677 28670-28670/? D/COPYDATABASE: Finished copying Database pev1.db from the assets folder, to /data/user/0/mjt.so54807516/databases/pev1.db8192were copied, in 2 blocks of size 4096.
3732019-02-22 19:07:54.678 28670-28670/? D/COPYDATABASE: All Streams have been flushed and closed.
3742019-02-22 19:07:54.678 28670-28670/? D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
3752019-02-22 19:07:54.701 28670-28670/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@71528f1
3762019-02-22 19:07:54.701 28670-28670/? I/System.out: 0 {
3772019-02-22 19:07:54.701 28670-28670/? I/System.out: type=table
3782019-02-22 19:07:54.701 28670-28670/? I/System.out: name=user
3792019-02-22 19:07:54.701 28670-28670/? I/System.out: tbl_name=user
3802019-02-22 19:07:54.702 28670-28670/? I/System.out: rootpage=2
3812019-02-22 19:07:54.702 28670-28670/? I/System.out: sql=CREATE TABLE "user" (
3822019-02-22 19:07:54.702 28670-28670/? I/System.out: "_id" INTEGER NOT NULL,
3832019-02-22 19:07:54.702 28670-28670/? I/System.out: "user" TEXT,
3842019-02-22 19:07:54.702 28670-28670/? I/System.out: "password" TEXT,
3852019-02-22 19:07:54.702 28670-28670/? I/System.out: PRIMARY KEY ("_id")
3862019-02-22 19:07:54.702 28670-28670/? I/System.out: )
3872019-02-22 19:07:54.702 28670-28670/? I/System.out: }
3882019-02-22 19:07:54.702 28670-28670/? I/System.out: 1 {
3892019-02-22 19:07:54.702 28670-28670/? I/System.out: type=table
3902019-02-22 19:07:54.702 28670-28670/? I/System.out: name=android_metadata
3912019-02-22 19:07:54.702 28670-28670/? I/System.out: tbl_name=android_metadata
3922019-02-22 19:07:54.702 28670-28670/? I/System.out: rootpage=3
3932019-02-22 19:07:54.702 28670-28670/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
3942019-02-22 19:07:54.702 28670-28670/? I/System.out: }
3952019-02-22 19:07:54.702 28670-28670/? I/System.out: <<<<<
3962019-02-22 19:07:54.703 28670-28670/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@1e20cd6
3972019-02-22 19:07:54.703 28670-28670/? I/System.out: 0 {
3982019-02-22 19:07:54.703 28670-28670/? I/System.out: _id=1
3992019-02-22 19:07:54.703 28670-28670/? I/System.out: user=Fred
4002019-02-22 19:07:54.703 28670-28670/? I/System.out: password=fredpassword
4012019-02-22 19:07:54.703 28670-28670/? I/System.out: }
4022019-02-22 19:07:54.703 28670-28670/? I/System.out: 1 {
4032019-02-22 19:07:54.703 28670-28670/? I/System.out: _id=2
4042019-02-22 19:07:54.703 28670-28670/? I/System.out: user=Mary
4052019-02-22 19:07:54.704 28670-28670/? I/System.out: password=marypassword
4062019-02-22 19:07:54.704 28670-28670/? I/System.out: }
4072019-02-22 19:07:54.704 28670-28670/? I/System.out: <<<<<
4082019-02-22 19:07:54.705 28670-28670/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@acdb57
4092019-02-22 19:07:54.705 28670-28670/? I/System.out: 0 {
4102019-02-22 19:07:54.705 28670-28670/? I/System.out: _id=1
4112019-02-22 19:07:54.705 28670-28670/? I/System.out: user=Fred
4122019-02-22 19:07:54.705 28670-28670/? I/System.out: password=fredpassword
4132019-02-22 19:07:54.706 28670-28670/? I/System.out: }
4142019-02-22 19:07:54.706 28670-28670/? I/System.out: 1 {
4152019-02-22 19:07:54.706 28670-28670/? I/System.out: _id=2
4162019-02-22 19:07:54.706 28670-28670/? I/System.out: user=Mary
4172019-02-22 19:07:54.706 28670-28670/? I/System.out: password=marypassword
4182019-02-22 19:07:54.706 28670-28670/? I/System.out: }
4192019-02-22 19:07:54.706 28670-28670/? I/System.out: 2 {
4202019-02-22 19:07:54.706 28670-28670/? I/System.out: _id=3
4212019-02-22 19:07:54.706 28670-28670/? I/System.out: user=mr new user
4222019-02-22 19:07:54.706 28670-28670/? I/System.out: password=a password
4232019-02-22 19:07:54.706 28670-28670/? I/System.out: }
4242019-02-22 19:07:54.706 28670-28670/? I/System.out: <<<<<
425
4262019-02-22 19:09:43.724 28730-28730/mjt.so54807516 D/DBFILEVERSION: Database File Version = 1
4272019-02-22 19:09:43.724 28730-28730/mjt.so54807516 D/DBFILEVERSION: Asset Database File Version = 0
4282019-02-22 19:09:43.724 28730-28730/mjt.so54807516 D/DBFILEVERSION: Asset Database File Version = 0
4292019-02-22 19:09:43.725 28730-28730/mjt.so54807516 D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
4302019-02-22 19:09:43.725 28730-28730/mjt.so54807516 D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
4312019-02-22 19:09:43.729 28730-28730/mjt.so54807516 I/System.out: >>>>>
432..... etc
433
4342019-02-22 19:13:49.157 28866-28866/mjt.so54807516 D/DBFILEVERSION: Database File Version = 1
4352019-02-22 19:13:49.158 28866-28866/mjt.so54807516 D/DBFILEVERSION: Asset Database File Version = 0
4362019-02-22 19:13:49.158 28866-28866/mjt.so54807516 D/DBFILEVERSION: Asset Database File Version = 0
4372019-02-22 19:13:49.158 28866-28866/mjt.so54807516 D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
4382019-02-22 19:13:49.158 28866-28866/mjt.so54807516 D/DBPATH: DB Path is /data/user/0/mjt.so54807516/databases/pev1.db
4392019-02-22 19:13:49.158 28866-28866/mjt.so54807516 D/COPYDATABASE: Initiated Copy of the database file pev1mod.db from the assets folder.
4402019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Asset file pev1mod.db found so attmepting to copy to /data/user/0/mjt.so54807516/databases/pev1.db
4412019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Attempting copy of block 1 which has 4096 bytes.
4422019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Attempting copy of block 2 which has 4096 bytes.
4432019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Attempting copy of block 3 which has 4096 bytes.
4442019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Attempting copy of block 4 which has 4096 bytes.
4452019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: Finished copying Database pev1.db from the assets folder, to /data/user/0/mjt.so54807516/databases/pev1.db16384were copied, in 4 blocks of size 4096.
4462019-02-22 19:13:49.159 28866-28866/mjt.so54807516 D/COPYDATABASE: All Streams have been flushed and closed.
4472019-02-22 19:13:49.186 28866-28866/mjt.so54807516 E/SQLiteDatabase: Error inserting password=fredpassword user=Fred
448 android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: user.user (code 2067 SQLITE_CONSTRAINT_UNIQUE)
449 at
450 .........
451 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
4522019-02-22 19:13:49.191 28866-28866/mjt.so54807516 E/SQLiteDatabase: Error inserting password=a password user=mr new user
453 android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: user.user (code 2067 SQLITE_CONSTRAINT_UNIQUE)
454 at
455 .............
4562019-02-22 19:13:49.209 28866-28866/mjt.so54807516 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@34252b0
4572019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: 0 {
4582019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: type=table
4592019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: name=user
4602019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: tbl_name=user
4612019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: rootpage=2
4622019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: sql=CREATE TABLE "user" (
4632019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: "_id" INTEGER NOT NULL,
4642019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: "user" TEXT,
4652019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: "password" TEXT,
4662019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: "email" TEXT,
4672019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: PRIMARY KEY ("_id"),
4682019-02-22 19:13:49.210 28866-28866/mjt.so54807516 I/System.out: CONSTRAINT "user" UNIQUE ("user")
4692019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: )
4702019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: }
4712019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: 1 {
4722019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: type=index
4732019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: name=sqlite_autoindex_user_1
4742019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: tbl_name=user
4752019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: rootpage=4
4762019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: sql=null
4772019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: }
4782019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: 2 {
4792019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: type=table
4802019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: name=android_metadata
4812019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: tbl_name=android_metadata
4822019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: rootpage=3
4832019-02-22 19:13:49.211 28866-28866/mjt.so54807516 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
4842019-02-22 19:13:49.212 28866-28866/mjt.so54807516 I/System.out: }
4852019-02-22 19:13:49.212 28866-28866/mjt.so54807516 I/System.out: <<<<<
4862019-02-22 19:13:49.212 28866-28866/mjt.so54807516 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@c8f0529
4872019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: 0 {
4882019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: _id=1
4892019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: user=Fred
4902019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: password=fredpassword
4912019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: email=fred@email.com
4922019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: }
4932019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: 1 {
4942019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out: _id=2
4952019-02-22 19:13:49.213 28866-28866/mjt.so54807516 I/System.out:
496...... etc