Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d04f7b37 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Distinguish null blobs in SQLiteRawStatement" into main

parents 84a4a87a 19cf445a
Loading
Loading
Loading
Loading
+10 −3
Original line number Original line Diff line number Diff line
@@ -41,6 +41,11 @@
 */
 */
namespace android {
namespace android {


// A zero-length byte array that can be returned by getColumnBlob().  The theory is that
// zero-length blobs are common enough that it is worth having a single, global instance. The
// object is created in the jni registration function.  It is never destroyed.
static jbyteArray emptyArray = nullptr;

// Helper functions.
// Helper functions.
static sqlite3 *db(long statementPtr) {
static sqlite3 *db(long statementPtr) {
    return sqlite3_db_handle(reinterpret_cast<sqlite3_stmt*>(statementPtr));
    return sqlite3_db_handle(reinterpret_cast<sqlite3_stmt*>(statementPtr));
@@ -226,7 +231,7 @@ static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) {
    throwIfInvalidColumn(env, stmtPtr, col);
    throwIfInvalidColumn(env, stmtPtr, col);
    const void* blob = sqlite3_column_blob(stmt(stmtPtr), col);
    const void* blob = sqlite3_column_blob(stmt(stmtPtr), col);
    if (blob == nullptr) {
    if (blob == nullptr) {
        return NULL;
        return (sqlite3_column_type(stmt(stmtPtr), col) == SQLITE_NULL) ? NULL : emptyArray;
    }
    }
    size_t size = sqlite3_column_bytes(stmt(stmtPtr), col);
    size_t size = sqlite3_column_bytes(stmt(stmtPtr), col);
    jbyteArray result = env->NewByteArray(size);
    jbyteArray result = env->NewByteArray(size);
@@ -316,8 +321,10 @@ static const JNINativeMethod sStatementMethods[] =


int register_android_database_SQLiteRawStatement(JNIEnv *env)
int register_android_database_SQLiteRawStatement(JNIEnv *env)
{
{
    return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteRawStatement",
    RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteRawStatement",
                         sStatementMethods, NELEM(sStatementMethods));
                         sStatementMethods, NELEM(sStatementMethods));
    emptyArray = MakeGlobalRefOrDie(env, env->NewByteArray(0));
    return 0;
}
}


} // namespace android
} // namespace android
+95 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package android.database.sqlite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.fail;


@@ -507,6 +508,12 @@ public class SQLiteRawStatementTest {
                s.bindInt(1, 3);
                s.bindInt(1, 3);
                s.step();
                s.step();
                s.reset();
                s.reset();
                // Bind a zero-length blob
                s.clearBindings();
                s.bindInt(1, 4);
                s.bindBlob(2, new byte[0]);
                s.step();
                s.reset();
            }
            }
            mDatabase.setTransactionSuccessful();
            mDatabase.setTransactionSuccessful();
        } finally {
        } finally {
@@ -545,6 +552,17 @@ public class SQLiteRawStatementTest {
                for (int i = 0; i < c.length; i++) c[i] = 0;
                for (int i = 0; i < c.length; i++) c[i] = 0;
                s.bindInt(1, 3);
                s.bindInt(1, 3);
                assertTrue(s.step());
                assertTrue(s.step());
                assertNull(s.getColumnBlob(0));
                assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0));
                for (int i = 0; i < c.length; i++) assertEquals(0, c[i]);
                s.reset();

                // Fetch the zero-length blob
                s.bindInt(1, 4);
                assertTrue(s.step());
                byte[] r = s.getColumnBlob(0);
                assertNotNull(r);
                assertEquals(0, r.length);
                assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0));
                assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0));
                for (int i = 0; i < c.length; i++) assertEquals(0, c[i]);
                for (int i = 0; i < c.length; i++) assertEquals(0, c[i]);
                s.reset();
                s.reset();
@@ -571,6 +589,83 @@ public class SQLiteRawStatementTest {
        }
        }
    }
    }


    @Test
    public void testText() {
        mDatabase.beginTransaction();
        try {
            final String query = "CREATE TABLE t1 (i int, b text)";
            try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
                assertFalse(s.step());
            }
            mDatabase.setTransactionSuccessful();
        } finally {
            mDatabase.endTransaction();
        }

        // Insert data into the table.
        mDatabase.beginTransaction();
        try {
            final String query = "INSERT INTO t1 (i, b) VALUES (?1, ?2)";
            try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
                // Bind a string
                s.bindInt(1, 1);
                s.bindText(2, "text");
                s.step();
                s.reset();
                s.clearBindings();

                // Bind a zero-length string
                s.bindInt(1, 2);
                s.bindText(2, "");
                s.step();
                s.reset();
                s.clearBindings();

                // Bind a null string
                s.clearBindings();
                s.bindInt(1, 3);
                s.step();
                s.reset();
                s.clearBindings();
            }
            mDatabase.setTransactionSuccessful();
        } finally {
            mDatabase.endTransaction();
        }

        // Read back data and verify it against the reference copy.
        mDatabase.beginTransactionReadOnly();
        try {
            final String query = "SELECT (b) FROM t1 WHERE i = ?1";
            try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
                // Fetch the entire reference array.
                s.bindInt(1, 1);
                assertTrue(s.step());
                assertEquals(SQLiteRawStatement.SQLITE_DATA_TYPE_TEXT, s.getColumnType(0));

                String a = s.getColumnText(0);
                assertNotNull(a);
                assertEquals(a, "text");
                s.reset();

                s.bindInt(1, 2);
                assertTrue(s.step());
                String b = s.getColumnText(0);
                assertNotNull(b);
                assertEquals(b, "");
                s.reset();

                s.bindInt(1, 3);
                assertTrue(s.step());
                String c = s.getColumnText(0);
                assertNull(c);
                s.reset();
            }
        } finally {
            mDatabase.endTransaction();
        }
    }

    @Test
    @Test
    public void testParameterMetadata() {
    public void testParameterMetadata() {
        createComplexDatabase();
        createComplexDatabase();