sql >> Database >  >> RDS >> SQLite

Hoe het versienummer te lezen uit een databasebestand in Android dat in de activamap is geplaatst

Er is niet één versienummer, maar het versienummer kan meerdere waarden bevatten.

Ik vermoed dat je het hebt over de user_version die de Android SDK SQLiteOpenHelper gebruikt.

Er is ook de application_id , die net als de user_version kan worden gebruikt als een gebruikersvariabele.

Je bent de SQLite_Version al tegengekomen, dus dat kan worden verdisconteerd.

Er is ook de data_version, dit is waarschijnlijk niet het versienummer, omdat het bedoeld is om te gebruiken als indicatie of het databasebestand in realtime is gewijzigd.

Er is ook de schema_version, deze wil je waarschijnlijk NIET gebruiken als Waarschuwing:misbruik van dit pragma kan leiden tot databasecorruptie.

user_version

Zoals eerder gezegd heb je het waarschijnlijk over de user_version . Het eerste dat moet worden opgemerkt, is dat het een door de gebruiker bestuurde variabele/veld is die beschikbaar is gemaakt voor aangepast gebruik. SQLite gebruikt of wijzigt de user_version . niet maar staat wel toe dat het gewijzigd en gebruikt wordt.

Verder zouden SQLite Managers (zoals DB Browser, Navicat etc) het versienummer niet automatisch wijzigen. Als zodanig zou u opzettelijk de user_version moeten wijzigen voordat deze beschikbaar is voordat u het databasebestand naar de activamap kopieert (merk op dat als u dit doet en u een subklasse van SQLiteOpenHelper gebruikt dat de onUpgrade en de onDowngrade methoden kunnen worden aangeroepen).

Als de user_version niet specifiek is gewijzigd en de database alleen is geopend door de SQLite Manager-tool, dan is de user_version 0. Als het databasebestand is geopend door het databasebestand te kopiëren van een Android-app die een subklasse van SQLiteOpenHelper gebruikt, heeft het een user_version van 1 of meer (afhankelijk van de laatste waarde die is gebruikt als de 4e parameter voor de SQLiteOpenHelper's constrcutor). Als de user_version programmatisch wordt gewijzigd, wordt een dergelijke wijziging natuurlijk ook doorgevoerd als het bestand naar een SQlite Manager-tool wordt gekopieerd.

Voordat het bestand wordt gekopieerd, wordt de user_version normaal gesproken in de SQlite Manager-tool gewijzigd in een geschikte waarde.

U kunt de user_version . wijzigen met behulp van de SQL PRAGMA user_version = 5; U kunt de user_version . ophalen met behulp van PRAGMA user_version of SELECT * FROM pragma_user_version;

Als u de versie moet controleren voordat u de database opent, kunt u de 4 bytes op offset 60 lezen en de 4 bytes converteren naar een geheel getal, om de user_version te vergelijken met een andere waarde. Anders zou u waarschijnlijk het bestand moeten kopiëren, waarschijnlijk met een andere naam, uit de activamap, het openen als een SQLiteDatabase en de user_version ophalen met behulp van de bovenstaande SQL en het vervolgens vergelijken met de andere waarde, waarbij het databasebestand wordt gesloten. Het verwijderen van het bestand indien niet nodig, anders het eerdere databasebestand verwijderen en vervolgens het gekopieerde bestand hernoemen.

Voorbeeld

Het volgende is een werkend voorbeeld (merk op dat ik Kotlin zelden gebruik en dit is geconverteerd met AS studio van java).

Deze gebruikt een klasse, namelijk SQLAssetVersionCheck die het versienummer uit het bestand haalt in plaats van het bestand te openen als een SQLiteDatabase.

SQLAssetVersionCheck.kt :-

class SQLAssetVersionCheck
/**
 * Full SQLAssetVersionCheck Constructor - sub directories can be specified
 * @param context           Assets are part of package so use the context to get the asset file
 * @param dbName            The database name (i.e. the file name)
 * @param subDirectories    The sub-directories as per the heirarchial order
 * @param dbVersion         The database version to check against
 */
(context: Context, val databaseName: String, subDirectories: Array<String>?, dbVersion: Int) {
    val assetPath: String
    var databaseVersion: Int = 0
        private set
    var result: Int = 0
        private set


    init {
        assetPath = applySubDirectories(databaseName, subDirectories)
        Log.d("SQLAVC", "Looking for Asset $assetPath")
        var stage = 0
        try {
            val `is` = context.assets.open(assetPath)
            stage++
            // Get the first 64 bytes of the header
            val v = ByteArray(64)
            `is`.read(v, 0, 64)
            // only interested in the 4 bytes from offset 60 so get them
            val v2 = ByteArray(4)
            for (i in 60..63) {
                v2[i - 60] = v[i]
            }
            stage++
            // Done with the InputStream so close it
            `is`.close()
            // Extarct the stored DBVersion
            databaseVersion = ByteBuffer.wrap(v2).int
            if (databaseVersion < dbVersion) {
                result = ASSETVERSIONLOW

            }
            if (databaseVersion > dbVersion) {
                result = ASSETVERSIONHIGH
            }
            if (databaseVersion == dbVersion) {
                result = ASSETVERSIONMATCH
            }

        } catch (e: IOException) {
            e.printStackTrace()
            when (stage) {
                0 -> result = ASSETNOTFOUND
                1 -> result = ASSETIOERROR
            }
        }

    }

    constructor(context: Context, dbName: String, dbVersion: Int) : this(context, dbName, null, dbVersion) {}

    private fun applySubDirectories(dbname: String, subDirectories: Array<String>?): String {
        val base = StringBuffer("")
        var firstdirectory = true
        if (subDirectories != null) {
            for (d in subDirectories) {
                if (!firstdirectory) {
                    base.append(File.separatorChar)
                }
                firstdirectory = false
                base.append(d)
            }
        }
        if (base.length > 0) {
            base.append(File.separatorChar)
        }
        base.append(dbname)
        return base.toString()
    }

    companion object {

        val ASSETNOTFOUND = -2
        val ASSETIOERROR = -3
        val ASSETVERSIONMATCH = 0
        val ASSETVERSIONHIGH = 1
        val ASSETVERSIONLOW = -1
    }
}

En hier is een activiteit die de bovenstaande klasse twee keer gebruikt om te proberen de versie in de testdb te controleren bestand.

  • Het eerste gebruik vindt het databasebestand testdb niet zoals het zoekt in activa map (niet de submap databases).

  • Het tweede gebruik vindt de testdb bestand als de submap databases is gespecificeerd (3e parameter van de volledige constructor), te vinden in de assets/databases/ map, bijv. assets/databases/testdb :-

MainActivity.kt :-

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val db_version_to_check_against = 100

        var mAVC1 = SQLAssetVersionCheck(this, "testdb", 100)

        var result = ""
        when (mAVC1.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC1.databaseName + " was not located at  " + mAVC1.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")

        var mAVC2 = SQLAssetVersionCheck(this, "testdb", arrayOf("databases"), db_version_to_check_against)
        result = ""
        when (mAVC2.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC2.databaseName + " was not located at  " + mAVC2.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")
    }
}

Resultaat (log):-

2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning W/System.err: java.io.FileNotFoundException: testdb
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:744)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:721)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:31)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:67)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.MainActivity.onCreate(MainActivity.kt:17)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7136)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7127)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Looper.loop(Looper.java:193)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset, for Database testdb was not located at  testdb




2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:11:34.477 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • De eerste poging vindt het bestand niet (de uitzondering die werd gevangen wordt weergegeven) en geeft de regel weer Het resultaat van de versiecontrole was - De Asset, voor Database testdb bevond zich niet op testdb worden weergegeven.

  • De tweede poging werkt en resulteert in Het resultaat van de versiecontrole was - De Asset was gelokaliseerd en het versienummer van 5 was lager dan de te controleren versie die 100 was

  • De tussenruimte van lege regels is toegevoegd om de tweede poging van de eerste te splitsen.

Aanvullend

Na het gebruik van de SQLite Manager-tool (Navicat) en het gebruik van :-

PRAGMA user_version = 101;

Kopieer vervolgens het bestand (na het sluiten van de verbinding in Navicat) naar de activamap (dus ik heb twee testdb-bestanden) en het resultaat is:-

2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 101 was higher than the version to be checked which was 100
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • d.w.z. het nieuwe bestand heeft de user_version als 101 en dus vindt de eerste het bestand, de tweede het bestand (user_version 5) zoals voorheen.



  1. Een array van gegevens doorgeven als invoerparameter aan een Oracle-procedure

  2. Bulksgewijs invoegen met tekstkwalificatie in SQL Server

  3. Hele DataTable in één keer in de database invoegen in plaats van rij voor rij?

  4. Functies van PostgreSQL-back-upmethode in AWS S3