Expand error codes in messages

List of error codes defined in https://www.sqlite.org/rescode.html

Test: Cause an exception and verify error codes are expanded:
      SQLiteConstraintException: NOT NULL constraint failed: test.num
      (code 1299 SQLITE_CONSTRAINT_NOTNULL)
Bug: 30014655
Bug: 64262688

Change-Id: Ia4f5fedebea9803805e7ab27fa623a5eec1e5cfe
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index eefcb74..34544d3 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -18,8 +18,108 @@
 
 #include <utils/String8.h>
 
+#include <map>
+
 namespace android {
 
+static const std::map<int, std::string> sErrorCodesMap = {
+    // Primary Result Code List
+    {4,     "SQLITE_ABORT"},
+    {23,    "SQLITE_AUTH"},
+    {5,     "SQLITE_BUSY"},
+    {14,    "SQLITE_CANTOPEN"},
+    {19,    "SQLITE_CONSTRAINT"},
+    {11,    "SQLITE_CORRUPT"},
+    {101,   "SQLITE_DONE"},
+    {16,    "SQLITE_EMPTY"},
+    {1,     "SQLITE_ERROR"},
+    {24,    "SQLITE_FORMAT"},
+    {13,    "SQLITE_FULL"},
+    {2,     "SQLITE_INTERNAL"},
+    {9,     "SQLITE_INTERRUPT"},
+    {10,    "SQLITE_IOERR"},
+    {6,     "SQLITE_LOCKED"},
+    {20,    "SQLITE_MISMATCH"},
+    {21,    "SQLITE_MISUSE"},
+    {22,    "SQLITE_NOLFS"},
+    {7,     "SQLITE_NOMEM"},
+    {26,    "SQLITE_NOTADB"},
+    {12,    "SQLITE_NOTFOUND"},
+    {27,    "SQLITE_NOTICE"},
+    {0,     "SQLITE_OK"},
+    {3,     "SQLITE_PERM"},
+    {15,    "SQLITE_PROTOCOL"},
+    {25,    "SQLITE_RANGE"},
+    {8,     "SQLITE_READONLY"},
+    {100,   "SQLITE_ROW"},
+    {17,    "SQLITE_SCHEMA"},
+    {18,    "SQLITE_TOOBIG"},
+    {28,    "SQLITE_WARNING"},
+    // Extended Result Code List
+    {516,   "SQLITE_ABORT_ROLLBACK"},
+    {261,   "SQLITE_BUSY_RECOVERY"},
+    {517,   "SQLITE_BUSY_SNAPSHOT"},
+    {1038,  "SQLITE_CANTOPEN_CONVPATH"},
+    {782,   "SQLITE_CANTOPEN_FULLPATH"},
+    {526,   "SQLITE_CANTOPEN_ISDIR"},
+    {270,   "SQLITE_CANTOPEN_NOTEMPDIR"},
+    {275,   "SQLITE_CONSTRAINT_CHECK"},
+    {531,   "SQLITE_CONSTRAINT_COMMITHOOK"},
+    {787,   "SQLITE_CONSTRAINT_FOREIGNKEY"},
+    {1043,  "SQLITE_CONSTRAINT_FUNCTION"},
+    {1299,  "SQLITE_CONSTRAINT_NOTNULL"},
+    {1555,  "SQLITE_CONSTRAINT_PRIMARYKEY"},
+    {2579,  "SQLITE_CONSTRAINT_ROWID"},
+    {1811,  "SQLITE_CONSTRAINT_TRIGGER"},
+    {2067,  "SQLITE_CONSTRAINT_UNIQUE"},
+    {2323,  "SQLITE_CONSTRAINT_VTAB"},
+    {267,   "SQLITE_CORRUPT_VTAB"},
+    {3338,  "SQLITE_IOERR_ACCESS"},
+    {2826,  "SQLITE_IOERR_BLOCKED"},
+    {3594,  "SQLITE_IOERR_CHECKRESERVEDLOCK"},
+    {4106,  "SQLITE_IOERR_CLOSE"},
+    {6666,  "SQLITE_IOERR_CONVPATH"},
+    {2570,  "SQLITE_IOERR_DELETE"},
+    {5898,  "SQLITE_IOERR_DELETE_NOENT"},
+    {4362,  "SQLITE_IOERR_DIR_CLOSE"},
+    {1290,  "SQLITE_IOERR_DIR_FSYNC"},
+    {1802,  "SQLITE_IOERR_FSTAT"},
+    {1034,  "SQLITE_IOERR_FSYNC"},
+    {6410,  "SQLITE_IOERR_GETTEMPPATH"},
+    {3850,  "SQLITE_IOERR_LOCK"},
+    {6154,  "SQLITE_IOERR_MMAP"},
+    {3082,  "SQLITE_IOERR_NOMEM"},
+    {2314,  "SQLITE_IOERR_RDLOCK"},
+    {266,   "SQLITE_IOERR_READ"},
+    {5642,  "SQLITE_IOERR_SEEK"},
+    {5130,  "SQLITE_IOERR_SHMLOCK"},
+    {5386,  "SQLITE_IOERR_SHMMAP"},
+    {4618,  "SQLITE_IOERR_SHMOPEN"},
+    {4874,  "SQLITE_IOERR_SHMSIZE"},
+    {522,   "SQLITE_IOERR_SHORT_READ"},
+    {1546,  "SQLITE_IOERR_TRUNCATE"},
+    {2058,  "SQLITE_IOERR_UNLOCK"},
+    {778,   "SQLITE_IOERR_WRITE"},
+    {262,   "SQLITE_LOCKED_SHAREDCACHE"},
+    {539,   "SQLITE_NOTICE_RECOVER_ROLLBACK"},
+    {283,   "SQLITE_NOTICE_RECOVER_WAL"},
+    {256,   "SQLITE_OK_LOAD_PERMANENTLY"},
+    {520,   "SQLITE_READONLY_CANTLOCK"},
+    {1032,  "SQLITE_READONLY_DBMOVED"},
+    {264,   "SQLITE_READONLY_RECOVERY"},
+    {776,   "SQLITE_READONLY_ROLLBACK"},
+    {284,   "SQLITE_WARNING_AUTOINDEX"},
+};
+
+static std::string sqlite3_error_code_to_msg(int errcode) {
+    auto it = sErrorCodesMap.find(errcode);
+    if (it != sErrorCodesMap.end()) {
+        return std::to_string(errcode) + " " + it->second;
+    } else {
+        return std::to_string(errcode);
+    }
+}
+
 /* throw a SQLiteException with a message appropriate for the error in handle */
 void throw_sqlite3_exception(JNIEnv* env, sqlite3* handle) {
     throw_sqlite3_exception(env, handle, NULL);
@@ -123,7 +223,8 @@
     if (sqlite3Message) {
         String8 fullMessage;
         fullMessage.append(sqlite3Message);
-        fullMessage.appendFormat(" (code %d)", errcode); // print extended error code
+        const char* errcode_msg = sqlite3_error_code_to_msg(errcode).c_str();
+        fullMessage.appendFormat(" (code %s)", errcode_msg); // print extended error code
         if (message) {
             fullMessage.append(": ");
             fullMessage.append(message);