Search in sources :

Example 11 with DB

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

the class Collection method basicCheck.

/**
 * DB maintenance *********************************************************** ************************************
 */
/*
     * Basic integrity check for syncing. True if ok.
     */
public boolean basicCheck() {
    // cards without notes
    if (mDb.queryScalar("select 1 from cards where nid not in (select id from notes) limit 1") > 0) {
        return false;
    }
    boolean badNotes = mDb.queryScalar("select 1 from notes where id not in (select distinct nid from cards) " + "or mid not in " + Utils.ids2str(getModels().ids()) + " limit 1") > 0;
    // notes without cards or models
    if (badNotes) {
        return false;
    }
    // invalid ords
    for (JSONObject m : getModels().all()) {
        // ignore clozes
        if (m.getInt("type") != Consts.MODEL_STD) {
            continue;
        }
        // Make a list of valid ords for this model
        JSONArray tmpls = m.getJSONArray("tmpls");
        boolean badOrd = mDb.queryScalar("select 1 from cards where (ord < 0 or ord >= ?) and nid in ( " + "select id from notes where mid = ?) limit 1", tmpls.length(), m.getLong("id")) > 0;
        if (badOrd) {
            return false;
        }
    }
    return true;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Example 12 with DB

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

the class Collection method load.

/**
 * DB-related *************************************************************** ********************************
 */
public void load() {
    Cursor cursor = null;
    String deckConf = "";
    try {
        // Read in deck table columns
        cursor = mDb.query("SELECT crt, mod, scm, dty, usn, ls, " + "conf, dconf, tags,ver FROM col");
        if (!cursor.moveToFirst()) {
            return;
        }
        mCrt = cursor.getLong(0);
        mMod = cursor.getLong(1);
        mScm = cursor.getLong(2);
        // No longer used
        mDty = cursor.getInt(3) == 1;
        mUsn = cursor.getInt(4);
        mLs = cursor.getLong(5);
        mConf = new JSONObject(cursor.getString(6));
        deckConf = cursor.getString(7);
        mTagsJson = cursor.getString(8);
        mTags.load(mTagsJson);
        mVer = cursor.getInt(9);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    // getModels().load(loadColumn("models")); This code has been
    // moved to `CollectionHelper::loadLazyCollection` for
    // efficiency Models are loaded lazily on demand. The
    // application layer can asynchronously pre-fetch those parts;
    // otherwise they get loaded when required.
    Timber.i("load new collection");
    mDecks.load(loadColumn("decks"), deckConf);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Cursor(android.database.Cursor)

Example 13 with DB

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

the class Sched method _fillRev.

@Override
protected boolean _fillRev(boolean allowSibling) {
    if (!mRevQueue.isEmpty()) {
        return true;
    }
    if (mRevCount == 0) {
        return false;
    }
    SupportSQLiteDatabase db = mCol.getDb().getDatabase();
    while (!mRevDids.isEmpty()) {
        long did = mRevDids.getFirst();
        int lim = Math.min(mQueueLimit, _deckRevLimit(did));
        Cursor cur = null;
        if (lim != 0) {
            mRevQueue.clear();
            // fill the queue with the current did
            try {
                /* Difference with upstream: we take current card into account.
                     *
                     * When current card is answered, the card is not due anymore, so does not belong to the queue.
                     * Furthermore, _burySiblings ensure that the siblings of the current cards are removed from the
                     * queue to ensure same day spacing. We simulate this action by ensuring that those siblings are not
                     * filled, except if we know there are cards and we didn't find any non-sibling card. This way, the
                     * queue is not empty if it should not be empty (important for the conditional belows), but the
                     * front of the queue contains distinct card.
                     */
                String idName = (allowSibling) ? "id" : "nid";
                long id = (allowSibling) ? currentCardId() : currentCardNid();
                cur = db.query("SELECT id FROM cards WHERE did = ? AND queue = " + Consts.QUEUE_TYPE_REV + " AND due <= ?" + " AND " + idName + " != ? LIMIT ?", new Object[] { did, mToday, id, lim });
                while (cur.moveToNext()) {
                    mRevQueue.add(cur.getLong(0));
                }
            } finally {
                if (cur != null && !cur.isClosed()) {
                    cur.close();
                }
            }
            if (!mRevQueue.isEmpty()) {
                // ordering
                if (mCol.getDecks().get(did).getInt("dyn") != 0) {
                // dynamic decks need due order preserved
                // Note: libanki reverses mRevQueue and returns the last element in _getRevCard().
                // AnkiDroid differs by leaving the queue intact and returning the *first* element
                // in _getRevCard().
                } else {
                    Random r = new Random();
                    r.setSeed(mToday);
                    mRevQueue.shuffle(r);
                }
                // is the current did empty?
                if (mRevQueue.size() < lim) {
                    mRevDids.remove();
                }
                return true;
            }
        }
        // nothing left in the deck; move to next
        mRevDids.remove();
    }
    // Since we didn't get a card and the count is non-zero, we
    // need to check again for any cards that were removed from
    // the queue but not buried
    _resetRev();
    return _fillRev(true);
}
Also used : SupportSQLiteDatabase(androidx.sqlite.db.SupportSQLiteDatabase) Random(java.util.Random) JSONObject(com.ichi2.utils.JSONObject) Cursor(android.database.Cursor)

Example 14 with DB

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

the class Storage method tableMatch.

private static boolean tableMatch(DB db, String tableName, String[] columnNames) {
    tableName = tableName.toLowerCase();
    String sql = String.format("PRAGMA table_info('%s')", tableName);
    try (Cursor cursor = db.getDatabase().query(sql, null)) {
        if (cursor.getCount() == columnNames.length) {
            int i = 0;
            while (cursor.moveToNext()) {
                if (!columnNames[i].equals(cursor.getString(cursor.getColumnIndex("name")))) {
                    return false;
                }
                i++;
            }
            return true;
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }
    return false;
}
Also used : Cursor(android.database.Cursor) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) JSONException(com.ichi2.utils.JSONException)

Example 15 with DB

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

the class Storage method Collection.

public static Collection Collection(Context context, String path, boolean server, boolean log, @NonNull Time time) {
    assert path.endsWith(".anki2");
    File dbFile = new File(path);
    boolean create = !dbFile.exists();
    // // connect
    DB db = new DB(path);
    try {
        // initialize
        int ver;
        Timber.i("new collection:%s", create);
        if (create) {
            AnkiDroidApp.getSharedPrefs(context).edit().remove(Consts.KEY_SYNC_CHINA_SESSION).apply();
            ver = _createDB(db, time);
        } else {
            ver = _upgradeSchema(db, time);
        }
        db.execute("PRAGMA temp_store = memory");
        // add db to col and do any remaining upgrades
        Collection col = new Collection(context, db, path, server, log, time);
        if (ver < Consts.SCHEMA_VERSION) {
            AnkiDroidApp.getSharedPrefs(context).edit().remove(Consts.KEY_SYNC_CHINA_SESSION).apply();
            _upgrade(col, ver);
        } else if (ver > Consts.SCHEMA_VERSION) {
            if (ver == 12 && _isVer11(db)) {
                // 判断数据库版本是否有问题
                db.execute("UPDATE col SET ver = 11");
            } else {
                throw new RuntimeException("This file requires a newer version of Anki.");
            }
        } else if (create) {
            // add in reverse order so basic is default
            for (int i = StdModels.stdModels.length - 1; i >= 0; i--) {
                StdModels.stdModels[i].add(col);
            }
            col.save();
        }
        return col;
    } catch (Exception e) {
        Timber.e(e, "Error opening collection; closing database");
        db.close();
        throw e;
    }
}
Also used : File(java.io.File) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) JSONException(com.ichi2.utils.JSONException)

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