gt:             if (ver < 10) {
context: /***************************************************************************************
   * Copyright (c) 2011 Norbert Nagold <norbert.nagold@gmail.com>                         *
   *                                                                                      *
   * This program is free software; you can redistribute it and/or modify it under        *
   * the terms of the GNU General Public License as published by the Free Software        *
   * Foundation; either version 3 of the License, or (at your option) any later           *
   * version.                                                                             *
   *                                                                                      *
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
   * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
   *                                                                                      *
   * You should have received a copy of the GNU General Public License along with         *
   * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
   ****************************************************************************************/
  
  package com.ichi2.libanki;
  
  import android.content.ContentValues;
  import android.content.Context;
  
  import com.ichi2.anki.UIUtils;
  import com.ichi2.anki.exception.ConfirmModSchemaException;
  
  import com.ichi2.libanki.backend.DroidBackend;
  import com.ichi2.libanki.backend.DroidBackendFactory;
  import com.ichi2.libanki.exception.UnknownDatabaseVersionException;
  import com.ichi2.libanki.utils.SystemTime;
  import com.ichi2.libanki.utils.Time;
  import com.ichi2.utils.JSONArray;
  import com.ichi2.utils.JSONException;
  import com.ichi2.utils.JSONObject;
  
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import androidx.annotation.NonNull;
  import timber.log.Timber;
  
  import static com.ichi2.libanki.Consts.DECK_STD;
  
  @SuppressWarnings({"PMD.AvoidThrowingRawExceptionTypes","PMD.AvoidReassigningParameters",
          "PMD.NPathComplexity","PMD.MethodNamingConventions","PMD.ExcessiveMethodLength","PMD.OneDeclarationPerLine",
          "PMD.SwitchStmtsShouldHaveDefault","PMD.EmptyIfStmt","PMD.SimplifyBooleanReturns","PMD.CollapsibleIfStatements"})
  public class Storage {
  
      private static boolean sUseBackend = true;
      private static boolean sUseInMemory = false;
  
  
      /* Open a new or existing collection. Path must be unicode */
      public static Collection Collection(Context context, @NonNull String path) {
          return Collection(context, path, false, false);
      }
  
      /** Helper method for when the collection can't be opened */
      public static int getDatabaseVersion(String path) throws UnknownDatabaseVersionException {
          try {
              if (!new File(path).exists()) {
                  throw new UnknownDatabaseVersionException(new FileNotFoundException(path));
              }
              DB db = new DB(path);
              int result = db.queryScalar("SELECT ver FROM col");
              db.close();
              return result;
          } catch (Exception e) {
              Timber.w(e, "Can't open database");
              throw new UnknownDatabaseVersionException(e);
          }
      }
  
      public static Collection Collection(Context context, @NonNull String path, boolean server, boolean log) {
          return Collection(context, path, server, log, new SystemTime());
      }
      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;
          }
      }
  
      /** Add note types when creating database */
      private static void addNoteTypes(Collection col, DroidBackend backend) {
          if (backend.databaseCreationInitializesData()) {
              Timber.i("skipping adding note types - already exist");
              return;
          }
          // add in reverse order so basic is default
          for (int i = StdModels.STD_MODELS.length-1; i>=0; i--) {
              StdModels.STD_MODELS[i].add(col);
          }
      }
  
  
      /**
       * Whether the collection should try to be opened with a Rust-based DB Backend
       * Falls back to Java if init fails.
       * */
      protected static boolean useBackend() {
          return sUseBackend;
      }
  
  
      private static int _upgradeSchema(DB db, @NonNull Time time) {
          int ver = db.queryScalar("SELECT ver FROM col");
          if (ver == Consts.SCHEMA_VERSION) {
              return ver;
          }
          // add odid to cards, edue->odue
          if (db.queryScalar("SELECT ver FROM col") == 1) {
              db.execute("ALTER TABLE cards RENAME TO cards2");
              _addSchema(db, false, time);
              db.execute("insert into cards select id, nid, did, ord, mod, usn, type, queue, due, ivl, factor, reps, lapses, left, edue, 0, flags, data from cards2");
              db.execute("DROP TABLE cards2");
              db.execute("UPDATE col SET ver = 2");
              _updateIndices(db);
          }
          // remove did from notes
          if (db.queryScalar("SELECT ver FROM col") == 2) {
              db.execute("ALTER TABLE notes RENAME TO notes2");
              _addSchema(db, true, time);
              db.execute("insert into notes select id, guid, mid, mod, usn, tags, flds, sfld, csum, flags, data from notes2");
              db.execute("DROP TABLE notes2");
              db.execute("UPDATE col SET ver = 3");
              _updateIndices(db);
          }
          return ver;
      }
  
  
      private static void _upgrade(Collection col, int ver) {
          try {
              if (ver < 3) {
                  // new deck properties
                  for (Deck d : col.getDecks().all()) {
                      d.put("dyn", DECK_STD);
                      d.put("collapsed", false);
                      col.getDecks().save(d);
                  }
              }
              if (ver < 4) {
                  col.modSchemaNoCheck();
                  List<Model> models = col.getModels().all();
                  ArrayList<Model> clozes = new ArrayList<>(models.size());
                  for (Model m : models) {
                      if (!m.getJSONArray("tmpls").getJSONObject(0).getString("qfmt").contains("{{cloze:")) {
                          m.put("type", Consts.MODEL_STD);
                      } else {
                          clozes.add(m);
                      }
                  }
                  for (Model m : clozes) {
                      try {
                          _upgradeClozeModel(col, m);
                      } catch (ConfirmModSchemaException e) {
                          // Will never be reached as we already set modSchemaNoCheck()
                          throw new RuntimeException(e);
                      }
                  }
                  col.getDb().execute("UPDATE col SET ver = 4");
              }
              if (ver < 5) {
                  col.getDb().execute("UPDATE cards SET odue = 0 WHERE queue = 2");
                  col.getDb().execute("UPDATE col SET ver = 5");
              }
              if (ver < 6) {
                  col.modSchemaNoCheck();
                  for (Model m : col.getModels().all()) {
                      m.put("css", new JSONObject(Models.DEFAULT_MODEL).getString("css"));
                      JSONArray ar = m.getJSONArray("tmpls");
                      for (JSONObject t: ar.jsonObjectIterable()) {
                          if (!t.has("css")) {
                              continue;
                          }
                          m.put("css",
                                  m.getString("css") + "\n"
                                          + t.getString("css").replace(".card ", ".card" + t.getInt("ord") + 1));
                          t.remove("css");
                      }
                      col.getModels().save(m);
                  }
                  col.getDb().execute("UPDATE col SET ver = 6");
              }
              if (ver < 7) {
                  col.modSchemaNoCheck();
                  col.getDb().execute("UPDATE cards SET odue = 0 WHERE (type = " + Consts.CARD_TYPE_LRN + " OR queue = 2) AND NOT odid");
                  col.getDb().execute("UPDATE col SET ver = 7");
              }
              if (ver < 8) {
                  col.modSchemaNoCheck();
                  col.getDb().execute("UPDATE cards SET due = due / 1000 WHERE due > 4294967296");
                  col.getDb().execute("UPDATE col SET ver = 8");
              }
              if (ver < 9) {
                  col.getDb().execute("UPDATE col SET ver = 9");
              }
  