1

I need to implement an update of the database lying in the assets. User data, namely, in the "favorite" record or not, should be saved.

I already asked a question and they helped me -https://stackoverflow.com/a/53827525/10261947

Everything worked in a test application. But when I transferred the code (exactly the same) to the real application, an error occurs - E/AndroidRuntime: FATAL EXCEPTION: ModernAsyncTask #1

 Process: rodionova.lyubov.brodsky, PID: 4196
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:161)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:784)
     Caused by: java.lang.IllegalArgumentException: the bind value at index 4 is null
        at android.database.sqlite.SQLiteProgram.bindString(SQLiteProgram.java:169)
        at android.database.sqlite.SQLiteProgram.bindAllArgsAsStrings(SQLiteProgram.java:205)
        at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:47)
        at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1397)
        at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1239)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1110)
        at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1278)
        at rodionova.lyubov.brodsky.db.PoemsDbHelper.insertCorePoem(PoemsDbHelper.java:121)
        at rodionova.lyubov.brodsky.db.PoemsDbHelper.getNewPoems(PoemsDbHelper.java:90)
        at rodionova.lyubov.brodsky.db.PoemsDbHelper.onUpgrade(PoemsDbHelper.java:41)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getWritableDatabase(SQLiteAssetHelper.java:197)
        at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getReadableDatabase(SQLiteAssetHelper.java:254)
        at rodionova.lyubov.brodsky.db.PoemsProvider.query(PoemsProvider.java:45)
        at android.content.ContentProvider.query(ContentProvider.java:1057)

If you do not perform the update, the application is working properly, so I will post only the code DbHelper

public class PoemsDbHelper extends SQLiteAssetHelper {
        public static final String DB_NAME = "brodsky.db";
        public static final int DBVERSION = 3;
        public static final String TBLNAME = "poems_table";
        public static final String COL_ID = "id";
        public static final String COL_TITLE = "title";
        public static final String COl_POEM = "poem";
        public static final String COL_SUBJECT = "subject";
        public static final String COL_YEARS = "years";
        public static final String COL_FAVOURITE = "favorite";

        Context mContext;

        public PoemsDbHelper(Context context) {
            super(context, DB_NAME, null, DBVERSION);
            mContext = context;
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            if(newVersion > oldVersion)
            getNewPoems(mContext, db);
        }


        private void getNewPoems(Context context, SQLiteDatabase db) {
            InputStream is;
            OutputStream os;
            final String tempNewDbName = "temp_brodsky.db";
            int buffersize = 4096;
            byte[] buffer = new byte[buffersize];
            String newDBPath = mContext.getDatabasePath(tempNewDbName).getPath();


            File newDBFile = new File(newDBPath);
            if (newDBFile.exists()) {
                newDBFile.delete();
            }

            File newDBFileDirectory = newDBFile.getParentFile();
            if (!newDBFileDirectory.exists()) {
                newDBFileDirectory.mkdirs();
            }

            try {
                is = context.getAssets().open("databases/" + DB_NAME);
                os = new FileOutputStream(newDBFile);
                int bytes_read;
                while ((bytes_read = is.read(buffer,0,buffersize)) > 0) {
                    os.write(buffer);
                }
                os.flush();
                os.close();
                is.close();

            }catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("Ouch updated database not copied - processing stopped - see stack-trace above.");
            }

            long id = maxid(db) + 1;
            SQLiteDatabase newdb = SQLiteDatabase.openDatabase(newDBFile.getPath(),null,SQLiteDatabase.OPEN_READONLY);
            Cursor csr = newdb.query(TBLNAME,null,null,null,null,null,null);
            long insert_result;
            db.beginTransaction();
            while (csr.moveToNext()) {
                insert_result = insertCorePoem(
                        db,
                        id,
                        csr.getString(csr.getColumnIndex(COL_TITLE)),
                        csr.getString(csr.getColumnIndex(COl_POEM)),
                        csr.getString(csr.getColumnIndex(COL_SUBJECT)),
                        csr.getString(csr.getColumnIndex(COL_YEARS)),
                        csr.getString(csr.getColumnIndex(COL_FAVOURITE))
                );

                if (insert_result > 0) {
                    id++;
                }

            }
            db.setTransactionSuccessful();
            db.endTransaction();
            csr.close();
            newDBFile.delete();
        }

        public long insertCorePoem(SQLiteDatabase db, long id, String title, String poem, String subject, String years, String favourite) {

            String whereclause = COL_TITLE + "=? AND " + COl_POEM + "=? AND " + COL_SUBJECT + "=? AND " + COL_YEARS + "=?";
            String[] whereargs = new String[]{
                    title,
                    poem,
                    subject,
                    years
            };

            Cursor csr = db.query(TBLNAME,null,whereclause,whereargs,null,null,null);
            boolean rowexists = (csr.getCount() > 0);
            csr.close();
            if (rowexists) {
                Log.d("INSERTCOREPOEM","Skipping insert of row");
                return -2;
            }

            ContentValues cv = new ContentValues();
            cv.put(COL_ID,id);
            cv.put(COL_TITLE,title);
            cv.put(COl_POEM,poem);
            cv.put(COL_SUBJECT,subject);
            cv.put(COL_YEARS,years);
            cv.put(COL_FAVOURITE,favourite);
            Log.d("INSERTCOREPOEM","Inserting new column with id " + String.valueOf(id));
            return db.insert(TBLNAME, null, cv);
        }

        private long maxid(SQLiteDatabase db) {
            long rv = 0;
            String extractcolumn = "maxid";
            String[] col = new String[]{"max(" + COL_ID + ") AS " + extractcolumn};
            Cursor csr = db.query(TBLNAME,col,null,null,null,null,null);
            if (csr.moveToFirst()) {
                rv = csr.getLong(csr.getColumnIndex(extractcolumn));
            }
            csr.close();
            return rv;
        }

    }

I do not understand what is wrong. Identical code works great friend application. I would be grateful for the help.

1 Answers1

0

Your issue is that you likely have a value of null in the years column of a row or rows in the updated database that data is being copied from.

Although you could change the code to handle (skip insertion or use provide a year value) the end result may not be desired. So the most likely fix would be to amend the database to have valid/useful year values.

MikeT
  • 51,415
  • 16
  • 49
  • 68