Skip to content

Commit 3921f7f

Browse files
committed
Support binding an empty ByteArray to a BLOB
If you try to bind an empty ByteArray it will crash because ByteArray.refTo(0) cannot find an element at index 0. The solution is to explicitly handle when the ByteArray is empty and to make an empty BLOB.
1 parent c80bc7a commit 3921f7f

File tree

2 files changed

+15
-14
lines changed

2 files changed

+15
-14
lines changed

sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/interop/ActualSqliteStatement.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ internal class ActualSqliteStatement(private val db: SqliteDatabase, private val
2525

2626
override fun columnGetBlob(columnIndex: Int): ByteArray {
2727
val blobSize = sqlite3_column_bytes(stmtPointer, columnIndex)
28-
val blob = sqlite3_column_blob(stmtPointer, columnIndex)
28+
if (blobSize == 0) return byteArrayOf()
2929

30-
if (blobSize < 0 || blob == null)
31-
throw sqlException(db.logger, db.config, "Byte array size/type issue col $columnIndex")
30+
val blob = sqlite3_column_blob(stmtPointer, columnIndex)
31+
?: throw sqlException(db.logger, db.config, "Byte array size/type issue col $columnIndex")
3232

3333
return blob.readBytes(blobSize)
3434
}
@@ -123,7 +123,8 @@ internal class ActualSqliteStatement(private val db: SqliteDatabase, private val
123123
}
124124

125125
override fun bindBlob(index: Int, value: ByteArray) = opResult(db) {
126-
sqlite3_bind_blob(stmtPointer, index, value.refTo(0), value.size, SQLITE_TRANSIENT)
126+
if (value.isNotEmpty()) sqlite3_bind_blob(stmtPointer, index, value.refTo(0), value.size, SQLITE_TRANSIENT)
127+
else sqlite3_bind_zeroblob(stmtPointer, index, 0)
127128
}
128129

129130
private inline fun opResult(db: SqliteDatabase, block: () -> Int) {

sqliter-driver/src/nativeCommonTest/kotlin/co/touchlab/sqliter/NativeStatementTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,33 +218,33 @@ class NativeStatementTest : BaseDatabaseTest(){
218218
}
219219
}
220220

221-
val TWO_COL_WITH_BLOB = "CREATE TABLE test (num INTEGER NOT NULL, " +
222-
"blb BLOB NOT NULL)"
221+
val THREE_COL_WITH_BLOB = "CREATE TABLE test (num INTEGER NOT NULL, " +
222+
"blb BLOB NOT NULL, null_blb BLOB)"
223223

224-
// @Test
225-
// Need to review what other drivers do here. It's not acting as expected
226-
// https://github.com/touchlab/SQLiter/issues/62
224+
@Test
227225
fun bindEmptyBlob() {
228-
basicTestDb(TWO_COL_WITH_BLOB) {
226+
basicTestDb(THREE_COL_WITH_BLOB) {
229227
it.withConnection {
230-
it.withStatement("insert into test(num, blb)values(?,?)") {
228+
it.withStatement("insert into test(num, blb, null_blb)values(?,?,?)") {
231229
bindLong(1, 22)
232-
bindBlob(2, ByteArray(0){it.toByte()})
230+
bindBlob(2, byteArrayOf())
231+
bindBlob(3, null)
233232
executeInsert()
234233
}
235234

236-
it.withStatement("select blb from test") {
235+
it.withStatement("select blb, null_blb from test") {
237236
val query = query()
238237
query.next()
239238
assertEquals(query.getBytes(query.columnNames["blb"]!!).size, 0)
239+
assertEquals(query.getBytesOrNull(query.columnNames["null_blb"]!!), null)
240240
}
241241
}
242242
}
243243
}
244244

245245
@Test
246246
fun bindBlob() {
247-
basicTestDb(TWO_COL_WITH_BLOB) {
247+
basicTestDb(THREE_COL_WITH_BLOB) {
248248
it.withConnection {
249249
it.withTransaction {
250250
it.withStatement("insert into test(num, blb)values(?,?)") {

0 commit comments

Comments
 (0)