Search in sources :

Example 46 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class Collection method getChunk.

private int getChunk() {
    if (sChunk != 0) {
        return sChunk;
    }
    // the window size is saved in
    // io.requery.android.database.CursorWindow.sCursorWindowSize.
    // Values are copied here. Ideally, a getter would allow to access it.
    final int WINDOW_SIZE_KB = 2048;
    int sCursorWindowSize = WINDOW_SIZE_KB * 1024;
    // We have the ability to look into our sqlite implementation on Android and use it's value
    // as a ceiling. Try it, with a reasonable fallback in case of failure
    SupportSQLiteDatabase db = mDb.getDatabase();
    if (!(db instanceof DatabaseChangeDecorator)) {
        return sChunk;
    }
    String db_name = ((DatabaseChangeDecorator) db).getWrapped().getClass().getName();
    if ("io.requery.android.database.sqlite.SQLiteDatabase".equals(db_name)) {
        try {
            Field cursorWindowSize = io.requery.android.database.CursorWindow.class.getDeclaredField("sDefaultCursorWindowSize");
            cursorWindowSize.setAccessible(true);
            int possibleCursorWindowSize = cursorWindowSize.getInt(null);
            Timber.d("Reflectively discovered database default cursor window size %d", possibleCursorWindowSize);
            if (possibleCursorWindowSize > 0) {
                sCursorWindowSize = possibleCursorWindowSize;
            } else {
                Timber.w("Obtained unusable cursor window size: %d. Using default %d", possibleCursorWindowSize, sCursorWindowSize);
            }
        } catch (Exception e) {
            Timber.w(e, "Unable to get window size from requery cursor.");
        }
    }
    // reduce the actual size a little bit.
    sChunk = (int) (sCursorWindowSize * 15. / 16.);
    return sChunk;
}
Also used : SupportSQLiteDatabase(androidx.sqlite.db.SupportSQLiteDatabase) Field(java.lang.reflect.Field) SuppressLint(android.annotation.SuppressLint) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) IOException(java.io.IOException) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) DatabaseChangeDecorator(com.ichi2.utils.DatabaseChangeDecorator)

Example 47 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class ZipFile method exportInto.

/**
 * Export source database into new destination database Note: The following python syntax isn't supported in
 * Android: for row in mSrc.db.execute("select * from cards where id in "+ids2str(cids)): therefore we use a
 * different method for copying tables
 *
 * @param path String path to destination database
 * @throws JSONException
 * @throws IOException
 */
public void exportInto(String path, Context context) throws JSONException, IOException, ImportExportException {
    // create a new collection at the target
    new File(path).delete();
    Collection dst = Storage.Collection(context, path);
    mSrc = mCol;
    // find cards
    Long[] cids = cardIds();
    // attach dst to src so we can copy data between them. This isn't done in original libanki as Python more
    // flexible
    dst.close();
    Timber.d("Attach DB");
    mSrc.getDb().getDatabase().execSQL("ATTACH '" + path + "' AS DST_DB");
    // copy cards, noting used nids (as unique set)
    Timber.d("Copy cards");
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.cards select * from cards where id in " + Utils.ids2str(cids));
    Set<Long> nids = new HashSet<>(mSrc.getDb().queryLongList("select nid from cards where id in " + Utils.ids2str(cids)));
    // notes
    Timber.d("Copy notes");
    ArrayList<Long> uniqueNids = new ArrayList<>(nids);
    String strnids = Utils.ids2str(uniqueNids);
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.notes select * from notes where id in " + strnids);
    // remove system tags if not exporting scheduling info
    if (!mIncludeSched) {
        Timber.d("Stripping system tags from list");
        ArrayList<String> srcTags = mSrc.getDb().queryStringList("select tags from notes where id in " + strnids);
        ArrayList<Object[]> args = new ArrayList<>(srcTags.size());
        Object[] arg = new Object[2];
        for (int row = 0; row < srcTags.size(); row++) {
            arg[0] = removeSystemTags(srcTags.get(row));
            arg[1] = uniqueNids.get(row);
            args.add(row, arg);
        }
        mSrc.getDb().executeMany("UPDATE DST_DB.notes set tags=? where id=?", args);
    }
    // models used by the notes
    Timber.d("Finding models used by notes");
    ArrayList<Long> mids = mSrc.getDb().queryLongList("select distinct mid from DST_DB.notes where id in " + strnids);
    // card history and revlog
    if (mIncludeSched) {
        Timber.d("Copy history and revlog");
        mSrc.getDb().getDatabase().execSQL("insert into DST_DB.revlog select * from revlog where cid in " + Utils.ids2str(cids));
        // reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
    } else {
        Timber.d("Detaching destination db and reopening");
        // first reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
        // then need to reset card state
        Timber.d("Resetting cards");
        dst.getSched().resetCards(cids);
    }
    // models - start with zero
    Timber.d("Copy models");
    for (Model m : mSrc.getModels().all()) {
        if (mids.contains(m.getLong("id"))) {
            Timber.d("Copy models:%s", m.getLong("id"));
            dst.getModels().update(m);
        }
    }
    for (Model m : dst.getModels().all()) {
        Timber.d("check dst model:%s", m.getLong("id"));
    }
    // decks
    Timber.d("Copy decks");
    ArrayList<Long> dids = new ArrayList<>();
    if (mDid != null) {
        dids.add(mDid);
        for (Long x : mSrc.getDecks().children(mDid).values()) {
            dids.add(x);
        }
    }
    JSONObject dconfs = new JSONObject();
    for (Deck d : mSrc.getDecks().all()) {
        if ("1".equals(d.getString("id"))) {
            continue;
        }
        if (mDid != null && !dids.contains(d.getLong("id"))) {
            continue;
        }
        if (d.getInt("dyn") != 1 && d.getLong("conf") != 1L) {
            if (mIncludeSched) {
                dconfs.put(Long.toString(d.getLong("conf")), true);
            }
        }
        Deck destinationDeck = d.deepClone();
        if (!mIncludeSched) {
            // scheduling not included, so reset deck settings to default
            destinationDeck.put("conf", 1);
        }
        dst.getDecks().update(destinationDeck);
    }
    // copy used deck confs
    Timber.d("Copy deck options");
    for (DeckConfig dc : mSrc.getDecks().allConf()) {
        if (dconfs.has(dc.getString("id"))) {
            dst.getDecks().updateConf(dc);
        }
    }
    // find used media
    Timber.d("Find used media");
    JSONObject media = new JSONObject();
    mMediaDir = mSrc.getMedia().dir();
    if (mIncludeMedia) {
        ArrayList<Long> mid = mSrc.getDb().queryLongList("select mid from notes where id in " + strnids);
        ArrayList<String> flds = mSrc.getDb().queryStringList("select flds from notes where id in " + strnids);
        for (int idx = 0; idx < mid.size(); idx++) {
            for (String file : mSrc.getMedia().filesInStr(mid.get(idx), flds.get(idx))) {
                // skip files in subdirs
                if (file.contains(File.separator)) {
                    continue;
                }
                media.put(file, true);
            }
        }
        if (mMediaDir != null) {
            for (File f : new File(mMediaDir).listFiles()) {
                if (f.isDirectory()) {
                    continue;
                }
                String fname = f.getName();
                if (fname.startsWith("_")) {
                    // Loop through every model that will be exported, and check if it contains a reference to f
                    for (JSONObject model : mSrc.getModels().all()) {
                        if (_modelHasMedia(model, fname)) {
                            media.put(fname, true);
                            break;
                        }
                    }
                }
            }
        }
    }
    JSONArray keys = media.names();
    if (keys != null) {
        for (int i = 0; i < keys.length(); i++) {
            mMediaFiles.add(keys.getString(i));
        }
    }
    Timber.d("Cleanup");
    dst.setCrt(mSrc.getCrt());
    // todo: tags?
    mCount = dst.cardCount();
    dst.setMod();
    postExport();
    dst.close();
}
Also used : ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) JSONObject(com.ichi2.utils.JSONObject) JSONObject(com.ichi2.utils.JSONObject) File(java.io.File) HashSet(java.util.HashSet)

Example 48 with DB

use of com.ichi2.libanki.DB in project Anki-Android by ankidroid.

the class ContentProviderTest method testInsertTemplate.

/**
 * Check that inserting and removing a note into default deck works as expected
 */
@Test
public void testInsertTemplate() throws Exception {
    // Get required objects for test
    final ContentResolver cr = getContentResolver();
    Collection col = getCol();
    // Add a new basic model that we use for testing purposes (existing models could potentially be corrupted)
    Model model = StdModels.BASIC_MODEL.add(col, BASIC_MODEL_NAME);
    long modelId = model.getLong("id");
    // Add the note
    Uri modelUri = ContentUris.withAppendedId(FlashCardsContract.Model.CONTENT_URI, modelId);
    // choose the last one because not the same as the basic model template
    int testIndex = TEST_MODEL_CARDS.length - 1;
    int expectedOrd = model.getJSONArray("tmpls").length();
    ContentValues cv = new ContentValues();
    cv.put(FlashCardsContract.CardTemplate.NAME, TEST_MODEL_CARDS[testIndex]);
    cv.put(FlashCardsContract.CardTemplate.QUESTION_FORMAT, TEST_MODEL_QFMT[testIndex]);
    cv.put(FlashCardsContract.CardTemplate.ANSWER_FORMAT, TEST_MODEL_AFMT[testIndex]);
    cv.put(FlashCardsContract.CardTemplate.BROWSER_QUESTION_FORMAT, TEST_MODEL_QFMT[testIndex]);
    cv.put(FlashCardsContract.CardTemplate.BROWSER_ANSWER_FORMAT, TEST_MODEL_AFMT[testIndex]);
    Uri templatesUri = Uri.withAppendedPath(modelUri, "templates");
    Uri templateUri = cr.insert(templatesUri, cv);
    // test that the changes are physically saved to the DB
    col = reopenCol();
    assertNotNull("Check template uri", templateUri);
    assertEquals("Check template uri ord", expectedOrd, ContentUris.parseId(templateUri));
    model = col.getModels().get(modelId);
    assertNotNull("Check model", model);
    JSONObject template = model.getJSONArray("tmpls").getJSONObject(expectedOrd);
    assertEquals("Check template JSONObject ord", expectedOrd, template.getInt("ord"));
    assertEquals("Check template name", TEST_MODEL_CARDS[testIndex], template.getString("name"));
    assertEquals("Check qfmt", TEST_MODEL_QFMT[testIndex], template.getString("qfmt"));
    assertEquals("Check afmt", TEST_MODEL_AFMT[testIndex], template.getString("afmt"));
    assertEquals("Check bqfmt", TEST_MODEL_QFMT[testIndex], template.getString("bqfmt"));
    assertEquals("Check bafmt", TEST_MODEL_AFMT[testIndex], template.getString("bafmt"));
    col.getModels().rem(model);
}
Also used : ContentValues(android.content.ContentValues) JSONObject(com.ichi2.utils.JSONObject) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver) Test(org.junit.Test)

Example 49 with DB

use of com.ichi2.libanki.DB in project Anki-Android by ankidroid.

the class DeckPickerCheckDatabaseListenerTest method validResultWithFailedDatabaseWillShowFailedDialog.

@Test
public void validResultWithFailedDatabaseWillShowFailedDialog() {
    CheckDatabaseResult failedDb = failedDatabase();
    Pair<Boolean, Collection.CheckDatabaseResult> result = validResultWithData(failedDb);
    execute(result);
    assertThat("Load Failed dialog should be shown if failed data is supplied", mImpl.didDisplayDialogLoadFailed());
    assertThat("Locked Database dialog should be shown if Db was locked", !mImpl.didDisplayLockedDialog());
    assertThat("Dialog should not be displayed", !mImpl.didDisplayMessage());
}
Also used : CheckDatabaseResult(com.ichi2.libanki.Collection.CheckDatabaseResult) Test(org.junit.Test)

Example 50 with DB

use of com.ichi2.libanki.DB in project Anki-Android by ankidroid.

the class Storage method Collection.

public static Collection Collection(Context context, @NonNull String path, boolean server, boolean log, @NonNull Time time) {
    assert (path.endsWith(".anki2") || path.endsWith(".anki21"));
    File dbFile = new File(path);
    boolean create = !dbFile.exists();
    DroidBackend backend = DroidBackendFactory.getInstance(useBackend());
    DB db = backend.openCollectionDatabase(sUseInMemory ? ":memory:" : path);
    try {
        // initialize
        int ver;
        if (create) {
            ver = _createDB(db, time, backend);
        } else {
            ver = _upgradeSchema(db, time);
        }
        db.execute("PRAGMA temp_store = memory");
        // add db to col and do any remaining upgrades
        Collection col = backend.createCollection(context, db, path, server, log, time);
        if (ver < Consts.SCHEMA_VERSION) {
            _upgrade(col, ver);
        } else if (ver > Consts.SCHEMA_VERSION) {
            throw new RuntimeException("This file requires a newer version of Anki.");
        } else if (create) {
            addNoteTypes(col, backend);
            col.onCreate();
            col.save();
        }
        return col;
    } catch (Exception e) {
        Timber.e(e, "Error opening collection; closing database");
        db.close();
        throw e;
    }
}
Also used : DroidBackend(com.ichi2.libanki.backend.DroidBackend) File(java.io.File) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) FileNotFoundException(java.io.FileNotFoundException) JSONException(com.ichi2.utils.JSONException) UnknownDatabaseVersionException(com.ichi2.libanki.exception.UnknownDatabaseVersionException)

Aggregations

File (java.io.File)19 JSONObject (com.ichi2.utils.JSONObject)18 Collection (com.ichi2.libanki.Collection)14 IOException (java.io.IOException)14 DB (com.ichi2.libanki.DB)13 FileNotFoundException (java.io.FileNotFoundException)13 ArrayList (java.util.ArrayList)11 JSONArray (com.ichi2.utils.JSONArray)10 Test (org.junit.Test)10 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)9 ContentValues (android.content.ContentValues)8 Resources (android.content.res.Resources)8 Uri (android.net.Uri)8 JSONException (com.ichi2.utils.JSONException)8 Cursor (android.database.Cursor)7 Model (com.ichi2.libanki.Model)7 ContentResolver (android.content.ContentResolver)6 FileInputStream (java.io.FileInputStream)6 SQLException (android.database.SQLException)4 BufferedInputStream (java.io.BufferedInputStream)4