Loading core/java/android/database/sqlite/SQLiteRawStatement.java +2 −2 Original line number Diff line number Diff line Loading @@ -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() { Loading core/jni/android_database_SQLiteRawStatement.cpp +24 −5 Original line number Diff line number Diff line Loading @@ -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)) { Loading @@ -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)); } Loading Loading @@ -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)); Loading core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -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(); } } } Loading
core/java/android/database/sqlite/SQLiteRawStatement.java +2 −2 Original line number Diff line number Diff line Loading @@ -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() { Loading
core/jni/android_database_SQLiteRawStatement.cpp +24 −5 Original line number Diff line number Diff line Loading @@ -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)) { Loading @@ -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)); } Loading Loading @@ -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)); Loading
core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -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(); } } }