diff options
author | 2024-12-10 22:44:59 +0000 | |
---|---|---|
committer | 2024-12-10 22:44:59 +0000 | |
commit | 4acfb8f36066345744fbc065d9d1018ece8b15cb (patch) | |
tree | bf7b7b306e7b3608be4fdc91e15b1caac8e51fa7 | |
parent | 0959be77a3eea5ba133e3f67b2e2517a3f4f1e00 (diff) | |
parent | dee229be307d1847b9c6ca0534b820b7db8ee2eb (diff) |
Merge "Correct check on SQLiteRawStatement.getColumnName" into main
3 files changed, 49 insertions, 7 deletions
diff --git a/core/java/android/database/sqlite/SQLiteRawStatement.java b/core/java/android/database/sqlite/SQLiteRawStatement.java index 3f3e46b4334c..ce2334a8247a 100644 --- a/core/java/android/database/sqlite/SQLiteRawStatement.java +++ b/core/java/android/database/sqlite/SQLiteRawStatement.java @@ -533,11 +533,11 @@ public final class SQLiteRawStatement implements Closeable { } /** - * Return the number of columns in the current result row. + * Return the number of columns in the result set for the statement. * * @see <a href="http://sqlite.org/c3ref/column_count.html">sqlite3_column_count</a> * - * @return The number of columns in the result row. + * @return The number of columns in the result set. * @throws IllegalStateException if the statement is closed or this is a foreign thread. */ public int getResultColumnCount() { diff --git a/core/jni/android_database_SQLiteRawStatement.cpp b/core/jni/android_database_SQLiteRawStatement.cpp index 32c2ef73a5b1..5fa808361178 100644 --- a/core/jni/android_database_SQLiteRawStatement.cpp +++ b/core/jni/android_database_SQLiteRawStatement.cpp @@ -81,10 +81,11 @@ static bool throwIfError(JNIEnv *env, jlong stmtPtr) { return true; } -// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out of -// bounds. It throws SQLiteMisuseException if the statement's column count is zero; that -// generally occurs because the client has forgotten to call step() or the client has stepped -// past the end of the query. The function returns true if an exception was thrown. +// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is outside the +// bounds of the row data set. It throws SQLiteMisuseException if the statement's data column +// count is zero; that generally occurs because the client has forgotten to call step() or the +// client has stepped past the end of the query. The function returns true if an exception was +// thrown. static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { int count = sqlite3_data_count(stmt(stmtPtr)); if (throwIfError(env, stmtPtr)) { @@ -106,6 +107,24 @@ static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { } } +// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is outside the +// bounds of the result set. (This is not the same as the data columns in a row). The function +// returns true if an exception was thrown. +static bool throwIfInvalidResultColumn(JNIEnv *env, jlong stmtPtr, jint col) { + int count = sqlite3_column_count(stmt(stmtPtr)); + if (throwIfError(env, stmtPtr)) { + return true; + } else if (col < 0 || col >= count) { + std::string message = android::base::StringPrintf( + "column index %d out of bounds [0,%d]", col, count - 1); + char const * errmsg = sqlite3_errstr(SQLITE_RANGE); + throw_sqlite3_exception(env, SQLITE_RANGE, errmsg, message.c_str()); + return true; + } else { + return false; + } +} + static jint bindParameterCount(JNIEnv* env, jclass, jlong stmtPtr) { return sqlite3_bind_parameter_count(stmt(stmtPtr)); } @@ -235,7 +254,7 @@ static jint columnType(JNIEnv* env, jclass, jlong stmtPtr, jint col) { } static jstring columnName(JNIEnv* env, jclass, jlong stmtPtr, jint col) { - if (throwIfInvalidColumn(env, stmtPtr, col)) { + if (throwIfInvalidResultColumn(env, stmtPtr, col)) { return nullptr; } const jchar* name = static_cast<const jchar*>(sqlite3_column_name16(stmt(stmtPtr), col)); diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java index 13b12fcf300a..51a43ac01d75 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java @@ -1048,5 +1048,28 @@ public class SQLiteRawStatementTest { } finally { mDatabase.endTransaction(); } + + // Ensure that column names and column types can be fetched even if the statement is not + // stepped. A new SQL statement is created to avoid interaction from the statement cache. + mDatabase.beginTransactionReadOnly(); + try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1 WHERE j = 3")) { + // Do not step the statement. + assertEquals("i", s.getColumnName(0)); + assertEquals("j", s.getColumnName(1)); + } finally { + mDatabase.endTransaction(); + } + + mDatabase.beginTransactionReadOnly(); + try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { + // Do not step the statement. + s.getColumnName(3); // out-of-range column + fail("JNI exception not thrown"); + } catch (SQLiteBindOrColumnIndexOutOfRangeException e) { + // Passing case. + } finally { + mDatabase.endTransaction(); + } + } } |