Skip to content

Commit

Permalink
Move SQLiteClosable to common, Inline NativeCursorWindow (#17)
Browse files Browse the repository at this point in the history
* Move SQLiteClosable to common

* Inline NativeCursorWindow, part 1
  • Loading branch information
illarionov authored Mar 18, 2024
1 parent 1a915ac commit 98ce16e
Show file tree
Hide file tree
Showing 26 changed files with 349 additions and 493 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ import ru.pixnews.wasm.sqlite.open.helper.internal.SQLiteDatabase
import ru.pixnews.wasm.sqlite.open.helper.internal.SQLiteDebug
import ru.pixnews.wasm.sqlite.open.helper.internal.WasmSqliteOpenHelper
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.GraalNativeBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.GraalWindowBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.SqlOpenHelperNativeBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.SqlOpenHelperWindowBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3ConnectionPtr
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3StatementPtr
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3WindowPtr
import ru.pixnews.wasm.sqlite.open.helper.path.DatabasePathResolver

/**
Expand Down Expand Up @@ -55,21 +52,19 @@ internal class WasmSqliteOpenHelperFactory(
cb = configuration.callback,
ops = configurationOptions,
bindings = bindings,
windowBindings = GraalWindowBindings(logger),
)
}

private class CallbackSqliteOpenHelper<CP : Sqlite3ConnectionPtr, SP : Sqlite3StatementPtr, WP : Sqlite3WindowPtr>(
private class CallbackSqliteOpenHelper<CP : Sqlite3ConnectionPtr, SP : Sqlite3StatementPtr>(
pathResolver: DatabasePathResolver,
defaultLocale: Locale,
debugConfig: SQLiteDebug,
rootLogger: Logger,
name: String?,
cb: SupportSQLiteOpenHelper.Callback,
ops: Iterable<ConfigurationOptions>,
bindings: SqlOpenHelperNativeBindings<CP, SP, WP>,
windowBindings: SqlOpenHelperWindowBindings<WP>,
) : WasmSqliteOpenHelper<CP, SP, WP>(
bindings: SqlOpenHelperNativeBindings<CP, SP>,
) : WasmSqliteOpenHelper<CP, SP>(
pathResolver = pathResolver,
defaultLocale = defaultLocale,
debugConfig = debugConfig,
Expand All @@ -79,22 +74,21 @@ internal class WasmSqliteOpenHelperFactory(
version = cb.version,
errorHandler = CallbackDatabaseErrorHandler(cb),
bindings = bindings,
windowBindings = windowBindings,
) {
private val callback: SupportSQLiteOpenHelper.Callback = cb
private val configurationOptions = ops

override fun onConfigure(db: SQLiteDatabase<CP, SP, WP>) = callback.onConfigure(db)
override fun onConfigure(db: SQLiteDatabase<CP, SP>) = callback.onConfigure(db)

override fun onCreate(db: SQLiteDatabase<CP, SP, WP>) = callback.onCreate(db)
override fun onCreate(db: SQLiteDatabase<CP, SP>) = callback.onCreate(db)

override fun onUpgrade(db: SQLiteDatabase<CP, SP, WP>, oldVersion: Int, newVersion: Int) =
override fun onUpgrade(db: SQLiteDatabase<CP, SP>, oldVersion: Int, newVersion: Int) =
callback.onUpgrade(db, oldVersion, newVersion)

override fun onDowngrade(db: SQLiteDatabase<CP, SP, WP>, oldVersion: Int, newVersion: Int): Unit =
override fun onDowngrade(db: SQLiteDatabase<CP, SP>, oldVersion: Int, newVersion: Int): Unit =
callback.onDowngrade(db, oldVersion, newVersion)

override fun onOpen(db: SQLiteDatabase<CP, SP, WP>) = callback.onOpen(db)
override fun onOpen(db: SQLiteDatabase<CP, SP>) = callback.onOpen(db)

override fun createConfiguration(
path: String,
Expand All @@ -114,6 +108,6 @@ internal class WasmSqliteOpenHelperFactory(
private class CallbackDatabaseErrorHandler(
private val callback: SupportSQLiteOpenHelper.Callback,
) : DatabaseErrorHandler {
override fun onCorruption(dbObj: SQLiteDatabase<*, *, *>) = callback.onCorruption(dbObj)
override fun onCorruption(dbObj: SQLiteDatabase<*, *>) = callback.onCorruption(dbObj)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package ru.pixnews.wasm.sqlite.open.helper.base
import android.database.CharArrayBuffer
import android.database.StaleDataException
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.NativeCursorWindow
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3WindowPtr

/**
* A base class for Cursors that store their data in [android.database.CursorWindow]s.
Expand All @@ -35,13 +34,13 @@ import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3WindowPtr
* (because it is owned by the cursor) and set to null.
*
*/
internal abstract class AbstractWindowedCursor<WP : Sqlite3WindowPtr>(
private val windowFactory: (name: String?) -> CursorWindow<WP>,
internal abstract class AbstractWindowedCursor(
private val windowFactory: (name: String?) -> CursorWindow,
) : AbstractCursor() {
/**
* The cursor window owned by this cursor.
*/
open var window: CursorWindow<WP>? = null
open var window: CursorWindow? = null
/**
* Sets a new cursor window for the cursor to use.
*
Expand Down Expand Up @@ -75,8 +74,35 @@ internal abstract class AbstractWindowedCursor<WP : Sqlite3WindowPtr>(
return window!!.getString(pos, column)
}

/**
* Copies the text of the field at the specified row and column index into
* a [CharArrayBuffer].
*
*
* The buffer is populated as follows:
*
* * If the buffer is too small for the value to be copied, then it is
* automatically resized.
* * If the field is of type [Cursor.FIELD_TYPE_NULL], then the buffer
* is set to an empty string.
* * If the field is of type [Cursor.FIELD_TYPE_STRING], then the buffer
* is set to the contents of the string.
* * If the field is of type [Cursor.FIELD_TYPE_INTEGER], then the buffer
* is set to a string representation of the integer in decimal, obtained by formatting the
* value with the `printf` family of functions using
* format specifier `%lld`.
* * If the field is of type [Cursor.FIELD_TYPE_FLOAT], then the buffer is
* set to a string representation of the floating-point value in decimal, obtained by
* formatting the value with the `printf` family of functions using
* format specifier `%g`.
* * If the field is of type [Cursor.FIELD_TYPE_BLOB], then a
* [SQLiteException] is thrown.
*
*/
override fun copyStringToBuffer(columnIndex: Int, buffer: CharArrayBuffer) {
window!!.copyStringToBuffer(pos, columnIndex, buffer)
val chars = getString(columnIndex)?.toCharArray() ?: charArrayOf()
buffer.data = chars
buffer.sizeCopied = chars.size
}

override fun getShort(column: Int): Short {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,26 @@ package ru.pixnews.wasm.sqlite.open.helper.base
* Licensed under the Apache License, Version 2.0 (the "License")
*/

import android.database.CharArrayBuffer
import ru.pixnews.wasm.sqlite.open.helper.common.api.Logger
import ru.pixnews.wasm.sqlite.open.helper.internal.SQLiteClosable
import ru.pixnews.wasm.sqlite.open.helper.internal.cursor.CursorWindowAllocationException
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.GraalWindowBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.NativeCursorWindow
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.SqlOpenHelperWindowBindings
import ru.pixnews.wasm.sqlite.open.helper.internal.interop.Sqlite3WindowPtr

/**
* A buffer containing multiple cursor rows.
*/
internal class CursorWindow<WP : Sqlite3WindowPtr>(
internal class CursorWindow(
name: String?,
private val bindings: SqlOpenHelperWindowBindings<WP>,
rootLogger: Logger,
val windowSizeBytes: Int = WINDOW_SIZE_KB * @Suppress("MagicNumber") 1024,
) : SQLiteClosable() {
private val bindings: GraalWindowBindings = GraalWindowBindings(rootLogger)

/**
* The native CursorWindow object pointer. (FOR INTERNAL USE ONLY)
*/
var windowPtr: WP?
var windowPtr: NativeCursorWindow?

/**
* Sets the start position of this cursor window.
Expand Down Expand Up @@ -226,45 +228,6 @@ internal class CursorWindow<WP : Sqlite3WindowPtr>(
return bindings.nativeGetString(windowPtr!!, row - startPosition, column)
}

/**
* Copies the text of the field at the specified row and column index into
* a [CharArrayBuffer].
*
*
* The buffer is populated as follows:
*
* * If the buffer is too small for the value to be copied, then it is
* automatically resized.
* * If the field is of type [Cursor.FIELD_TYPE_NULL], then the buffer
* is set to an empty string.
* * If the field is of type [Cursor.FIELD_TYPE_STRING], then the buffer
* is set to the contents of the string.
* * If the field is of type [Cursor.FIELD_TYPE_INTEGER], then the buffer
* is set to a string representation of the integer in decimal, obtained by formatting the
* value with the `printf` family of functions using
* format specifier `%lld`.
* * If the field is of type [Cursor.FIELD_TYPE_FLOAT], then the buffer is
* set to a string representation of the floating-point value in decimal, obtained by
* formatting the value with the `printf` family of functions using
* format specifier `%g`.
* * If the field is of type [Cursor.FIELD_TYPE_BLOB], then a
* [SQLiteException] is thrown.
*
*
*
* @param row The zero-based row index.
* @param column The zero-based column index.
* @param buffer The [CharArrayBuffer] to hold the string. It is automatically
* resized if the requested string is larger than the buffer's current capacity.
*/
fun copyStringToBuffer(row: Int, column: Int, buffer: CharArrayBuffer?) {
requireNotNull(buffer) { "CharArrayBuffer should not be null" }
// TODO not as optimal as the original code
val chars = getString(row, column)?.toCharArray() ?: charArrayOf()
buffer.data = chars
buffer.sizeCopied = chars.size
}

/**
* Gets the value of the field at the specified row and column index as a `long`.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ internal interface DatabaseErrorHandler {
* @param dbObj the [SQLiteDatabase] object representing the database on which corruption
* is detected.
*/
fun onCorruption(dbObj: SQLiteDatabase<*, *, *>)
fun onCorruption(dbObj: SQLiteDatabase<*, *>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import java.io.File
* as the default [DatabaseErrorHandler].
*/
internal class DefaultDatabaseErrorHandler : DatabaseErrorHandler {
override fun onCorruption(dbObj: SQLiteDatabase<*, *, *>) {
override fun onCorruption(dbObj: SQLiteDatabase<*, *>) {
Log.e(TAG, "Corruption reported by sqlite on database: ${dbObj.path}")

// is the corruption detected even before database could be 'opened'?
Expand Down
Loading

0 comments on commit 98ce16e

Please sign in to comment.