diff --git a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt index 6b793ad..5467cd4 100644 --- a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt +++ b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/CommonBasicTest.kt @@ -26,16 +26,17 @@ import kotlin.test.assertEquals class CommonBasicTest(private val path: DatabasePath) { - private data class Book( + private class Book( val name: String, val author: String, val pages: Int, val price: Double, + val array: ByteArray, ) private val bookList = listOf( - Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96), - Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95), + Book(name = "The Da Vinci Code", author = "Dan Brown", pages = 454, price = 16.96, byteArrayOf()), + Book(name = "The Lost Symbol", author = "Dan Brown", pages = 510, price = 19.95, byteArrayOf(1, 2, 3)), ) fun testCreateAndUpgrade() { @@ -84,8 +85,8 @@ class CommonBasicTest(private val path: DatabasePath) { val readWriteConfig = getDefaultDBConfig(false) openDatabase(readWriteConfig) { it.withTransaction { connection -> - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96)) - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95)) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96, byteArrayOf())) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95, byteArrayOf(1, 2, 3))) } } val readOnlyConfig = getDefaultDBConfig(true) @@ -98,6 +99,7 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(book.author, cursor.getString(++columnIndex)) assertEquals(book.pages, cursor.getInt(++columnIndex)) assertEquals(book.price, cursor.getDouble(++columnIndex)) + assertEquals(book.array.size, cursor.getByteArray(++columnIndex)?.size) } } } @@ -161,8 +163,8 @@ class CommonBasicTest(private val path: DatabasePath) { val readWriteConfig = getDefaultDBConfig(false) openDatabase(readWriteConfig) { it.withTransaction { connection -> - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96)) - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95)) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96, byteArrayOf())) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95, byteArrayOf(1, 2, 3))) } try { @@ -202,13 +204,14 @@ class CommonBasicTest(private val path: DatabasePath) { assertEquals(book.author, cursor.getString(++columnIndex)) assertEquals(book.pages, cursor.getInt(++columnIndex)) assertEquals(book.price, cursor.getDouble(++columnIndex)) + assertEquals(book.array.size, cursor.getByteArray(++columnIndex)?.size) } } } } it.withTransaction { connection -> - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96)) - connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95)) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Da Vinci Code", "Dan Brown", 454, 16.96, byteArrayOf())) + connection.executeInsert(SQL.INSERT_BOOK, arrayOf("The Lost Symbol", "Dan Brown", 510, 19.95, byteArrayOf(1, 2, 3))) } } } diff --git a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt index 2fc0f77..a062eb5 100644 --- a/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt +++ b/sqllin-driver/src/commonTest/kotlin/com/ctrip/sqllin/driver/SQL.kt @@ -25,13 +25,13 @@ object SQL { const val DATABASE_NAME = "BookStore.db" - const val CREATE_BOOK = "create table book (id integer primary key autoincrement, name text, author text, pages integer, price real)" + const val CREATE_BOOK = "create table book (id integer primary key autoincrement, name text, author text, pages integer, price real, array blob)" const val CREATE_CATEGORY = "create table Category (id integer primary key autoincrement, category_name text, category_code integer)" const val ASSOCIATE = "alter table Book add column category_id integer" - const val INSERT_BOOK = "insert into Book (name, author, pages, price) values (?, ?, ?, ?)" + const val INSERT_BOOK = "insert into Book (name, author, pages, price, array) values (?, ?, ?, ?, ?)" const val QUERY_BOOK = "select * from Book" diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeStatement.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeStatement.kt index 3eb1dc4..3368984 100644 --- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeStatement.kt +++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/cinterop/NativeStatement.kt @@ -35,6 +35,7 @@ import com.ctrip.sqllin.sqlite3.sqlite3_bind_int64 import com.ctrip.sqllin.sqlite3.sqlite3_bind_null import com.ctrip.sqllin.sqlite3.sqlite3_bind_parameter_index import com.ctrip.sqllin.sqlite3.sqlite3_bind_text +import com.ctrip.sqllin.sqlite3.sqlite3_bind_zeroblob import com.ctrip.sqllin.sqlite3.sqlite3_changes import com.ctrip.sqllin.sqlite3.sqlite3_clear_bindings import com.ctrip.sqllin.sqlite3.sqlite3_column_blob @@ -86,12 +87,11 @@ internal class NativeStatement( override fun columnGetBlob(columnIndex: Int): ByteArray { val blobSize = sqlite3_column_bytes(cStatementPointer, columnIndex) - val blob = sqlite3_column_blob(cStatementPointer, columnIndex) - - if (blobSize < 0 || blob == null) - throw sqliteException("Byte array size/type issue col $columnIndex") - - return blob.readBytes(blobSize) + return if (blobSize == 0) + byteArrayOf() + else + sqlite3_column_blob(cStatementPointer, columnIndex)?.readBytes(blobSize) + ?: throw sqliteException("Byte array size/type issue col $columnIndex") } override fun columnCount(): Int = sqlite3_column_count(cStatementPointer) @@ -106,9 +106,7 @@ internal class NativeStatement( when (val err = sqlite3_step(cStatementPointer)) { SQLITE_ROW -> return true SQLITE_DONE -> return false - SQLITE_LOCKED, SQLITE_BUSY -> { - usleep(1000u) - } + SQLITE_LOCKED, SQLITE_BUSY -> usleep(1000u) else -> throw sqliteException("sqlite3_step failed", err) } } @@ -151,12 +149,11 @@ internal class NativeStatement( } private fun executeForLastInsertedRowId(): Long { - val err = executeNonQuery(); - return if (err == SQLITE_DONE && sqlite3_changes(database.dbPointer) > 0) { + val err = executeNonQuery() + return if (err == SQLITE_DONE && sqlite3_changes(database.dbPointer) > 0) sqlite3_last_insert_rowid(database.dbPointer) - } else { + else -1 - } } override fun executeUpdateDelete(): Int = try { @@ -168,11 +165,10 @@ internal class NativeStatement( private fun executeForChangedRowCount(): Int { val err = executeNonQuery() - return if (err == SQLITE_DONE) { + return if (err == SQLITE_DONE) sqlite3_changes(database.dbPointer) - } else { + else -1 - } } private fun executeNonQuery(): Int { @@ -199,12 +195,14 @@ internal class NativeStatement( } override fun bindString(index: Int, value: String) = opResult(database) { - // TODO: Was using UTF 16 function previously. Do a little research. sqlite3_bind_text(cStatementPointer, index, value, -1, SQLITE_TRANSIENT) } override fun bindBlob(index: Int, value: ByteArray) = opResult(database) { - sqlite3_bind_blob(cStatementPointer, index, value.refTo(0), value.size, SQLITE_TRANSIENT) + if (value.isEmpty()) + sqlite3_bind_zeroblob(cStatementPointer, index, 0) + else + sqlite3_bind_blob(cStatementPointer, index, value.refTo(0), value.size, SQLITE_TRANSIENT) } private inline fun opResult(database: NativeDatabase, block: () -> Int) {