int pkgdb_repo_check_version(struct pkgdb *db, const char *database) { int reposcver; int repomajor; int ret; assert(db != NULL); assert(database != NULL); if ((ret = get_repo_user_version(db->sqlite, database, &reposcver)) != EPKG_OK) return (ret); /* sqlite error */ /* * If the local pkgng uses a repo schema behind that used to * create the repo, we may still be able use it for reading * (ie pkg install), but pkg repo can't do an incremental * update unless the actual schema matches the compiled in * schema version. * * Use a major - minor version schema: as the user_version * PRAGMA takes an integer version, encode this as MAJOR * * 1000 + MINOR. * * So long as the major versions are the same, the local pkgng * should be compatible with any repo created by a more recent * pkgng, although it may need some modification of the repo * schema */ /* --- Temporary ---- Grandfather in the old repo schema version so this patch doesn't immediately invalidate all the repos out there */ if (reposcver == 2) reposcver = 2000; if (reposcver == 3) reposcver = 2001; repomajor = reposcver / 1000; if (repomajor < REPO_SCHEMA_MAJOR) { pkg_emit_error("Repo %s (schema version %d) is too old - " "need at least schema %d", database, reposcver, REPO_SCHEMA_MAJOR * 1000); return (EPKG_REPOSCHEMA); } if (repomajor > REPO_SCHEMA_MAJOR) { pkg_emit_error("Repo %s (schema version %d) is too new - " "we can accept at most schema %d", database, reposcver, ((REPO_SCHEMA_MAJOR + 1) * 1000) - 1); return (EPKG_REPOSCHEMA); } /* This is a repo schema version we can work with */ ret = EPKG_OK; if (reposcver < REPO_SCHEMA_VERSION) { if (sqlite3_db_readonly(db->sqlite, database)) { pkg_emit_error("Repo %s needs schema upgrade from " "%d to %d but it is opened readonly", database, reposcver, REPO_SCHEMA_VERSION ); ret = EPKG_FATAL; } else ret = upgrade_repo_schema(db, database, reposcver); } else if (reposcver > REPO_SCHEMA_VERSION) { if (sqlite3_db_readonly(db->sqlite, database)) { pkg_emit_error("Repo %s needs schema downgrade from " "%d to %d but it is opened readonly", database, reposcver, REPO_SCHEMA_VERSION ); ret = EPKG_FATAL; } else ret = downgrade_repo_schema(db, database, reposcver); } return (ret); }
bool Handle::isReadonly() { return sqlite3_db_readonly((sqlite3 *) m_handle, NULL) == 1; }
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags, jstring labelStr, jboolean enableTrace, jboolean enableProfile) { int sqliteFlags; if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) { sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; } else if (openFlags & SQLiteConnection::OPEN_READONLY) { sqliteFlags = SQLITE_OPEN_READONLY; } else { sqliteFlags = SQLITE_OPEN_READWRITE; } const char* pathChars = env->GetStringUTFChars(pathStr, NULL); String8 path(pathChars); env->ReleaseStringUTFChars(pathStr, pathChars); const char* labelChars = env->GetStringUTFChars(labelStr, NULL); String8 label(labelChars); env->ReleaseStringUTFChars(labelStr, labelChars); sqlite3* db; int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL); if (err != SQLITE_OK) { throw_sqlite3_exception_errcode(env, err, "Could not open database"); return 0; } // Check that the database is really read/write when that is what we asked for. if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) { throw_sqlite3_exception(env, db, "Could not open the database in read/write mode."); sqlite3_close(db); return 0; } // Set the default busy handler to retry automatically before returning SQLITE_BUSY. err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS); if (err != SQLITE_OK) { throw_sqlite3_exception(env, db, "Could not set busy timeout"); sqlite3_close(db); return 0; } // Register custom Android functions. err = register_android_functions(db, UTF16_STORAGE); if (err) { throw_sqlite3_exception(env, db, "Could not register Android SQL functions."); sqlite3_close(db); return 0; } // Create wrapper object. SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label); // Enable tracing and profiling if requested. if (enableTrace) { sqlite3_trace(db, &sqliteTraceCallback, connection); } if (enableProfile) { sqlite3_profile(db, &sqliteProfileCallback, connection); } ALOGV("Opened connection %p with label '%s'", db, label.string()); return reinterpret_cast<jlong>(connection); }
/* public native void dbopen(String path, int flags, String locale); */ void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags) { int err; sqlite3 * handle = NULL; sqlite3_stmt * statement = NULL; char const * path8 = env->GetStringUTFChars(pathString, NULL); int sqliteFlags; // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. registerLoggingFunc(path8); // convert our flags into the sqlite flags if (flags & CREATE_IF_NECESSARY) { sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; } else if (flags & OPEN_READONLY) { sqliteFlags = SQLITE_OPEN_READONLY; } else { sqliteFlags = SQLITE_OPEN_READWRITE; } err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL); if (err != SQLITE_OK) { LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags); throw_sqlite3_exception_errcode(env, err, "Could not open database"); goto done; } // Check that the database is really read/write when that is what we asked for. if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(handle, NULL)) { throw_sqlite3_exception(env, handle, "Could not open the database in read/write mode."); goto done; } // The soft heap limit prevents the page cache allocations from growing // beyond the given limit, no matter what the max page cache sizes are // set to. The limit does not, as of 3.5.0, affect any other allocations. sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT); // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY err = sqlite3_busy_timeout(handle, 1000 /* ms */); if (err != SQLITE_OK) { LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8); throw_sqlite3_exception(env, handle, "Could not set busy timeout"); goto done; } #ifdef DB_INTEGRITY_CHECK static const char* integritySql = "pragma integrity_check(1);"; err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL); if (err != SQLITE_OK) { LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8); throw_sqlite3_exception(env, handle, "sqlite_prepare_v2(handle, \"pragma integrity_check(1);\") failed"); goto done; } // first is OK or error message err = sqlite3_step(statement); if (err != SQLITE_ROW) { LOGE("integrity check failed for \"%s\"\n", integritySql, path8); throw_sqlite3_exception(env, handle); goto done; } else { const char *text = (const char*)sqlite3_column_text(statement, 0); if (strcmp(text, "ok") != 0) { LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text); jniThrowException(env, "net/sqlcipher/database/SQLiteDatabaseCorruptException", text); goto done; } } #endif sqlite3_enable_load_extension(handle, 1); LOGV("Opened '%s' - %p\n", path8, handle); env->SetLongField(object, offset_db_handle, (intptr_t)handle); handle = NULL; // The caller owns the handle now. done: // Release allocated resources if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8); if (statement != NULL) sqlite3_finalize(statement); if (handle != NULL) sqlite3_close(handle); }