void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassOwnPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionState& exceptionState) { ASSERT(m_executionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { reportChangeVersionResult(1, SQLError::DATABASE_ERR, 0); setLastErrorMessage("unable to changeVersion from within a transaction"); exceptionState.throwUninformativeAndGenericDOMException(SQLDatabaseError); return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false); transaction->begin(exceptionState); if (exceptionState.hadException()) { ASSERT(!lastErrorMessage().isEmpty()); return; } String actualVersion; if (!getVersionFromDatabase(actualVersion)) { reportChangeVersionResult(2, SQLError::UNKNOWN_ERR, sqliteDatabase().lastError()); setLastErrorMessage("unable to read the current version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg()); exceptionState.throwDOMException(UnknownError, SQLError::unknownErrorMessage); return; } if (actualVersion != oldVersion) { reportChangeVersionResult(3, SQLError::VERSION_ERR, 0); setLastErrorMessage("current version of the database and `oldVersion` argument do not match"); exceptionState.throwDOMException(VersionError, SQLError::versionErrorMessage); return; } transaction->execute(exceptionState); if (exceptionState.hadException()) { ASSERT(!lastErrorMessage().isEmpty()); return; } if (!setVersionInDatabase(newVersion)) { reportChangeVersionResult(4, SQLError::UNKNOWN_ERR, sqliteDatabase().lastError()); setLastErrorMessage("unable to set the new version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg()); exceptionState.throwDOMException(UnknownError, SQLError::unknownErrorMessage); return; } transaction->commit(exceptionState); if (exceptionState.hadException()) { ASSERT(!lastErrorMessage().isEmpty()); setCachedVersion(oldVersion); return; } reportChangeVersionResult(0, -1, 0); // OK setExpectedVersion(newVersion); setLastErrorMessage(""); }
void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionCode& ec) { ASSERT(m_scriptExecutionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { reportChangeVersionResult(1, SQLException::DATABASE_ERR, 0); setLastErrorMessage("unable to changeVersion from within a transaction"); ec = SQLException::DATABASE_ERR; return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false); if ((ec = transaction->begin())) { ASSERT(!lastErrorMessage().isEmpty()); return; } String actualVersion; if (!getVersionFromDatabase(actualVersion)) { reportChangeVersionResult(2, SQLException::UNKNOWN_ERR, sqliteDatabase().lastError()); setLastErrorMessage("unable to read the current version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg()); ec = SQLException::UNKNOWN_ERR; return; } if (actualVersion != oldVersion) { reportChangeVersionResult(3, SQLException::VERSION_ERR, 0); setLastErrorMessage("current version of the database and `oldVersion` argument do not match"); ec = SQLException::VERSION_ERR; return; } if ((ec = transaction->execute())) { ASSERT(!lastErrorMessage().isEmpty()); return; } if (!setVersionInDatabase(newVersion)) { reportChangeVersionResult(4, SQLException::UNKNOWN_ERR, sqliteDatabase().lastError()); setLastErrorMessage("unable to set the new version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg()); ec = SQLException::UNKNOWN_ERR; return; } if ((ec = transaction->commit())) { ASSERT(!lastErrorMessage().isEmpty()); setCachedVersion(oldVersion); return; } reportChangeVersionResult(0, -1, 0); // OK setExpectedVersion(newVersion); setLastErrorMessage(""); }
Vector<String> Database::performGetTableNames() { disableAuthorizer(); SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';"); if (statement.prepare() != SQLResultOk) { LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data()); enableAuthorizer(); return Vector<String>(); } Vector<String> tableNames; int result; while ((result = statement.step()) == SQLResultRow) { String name = statement.getColumnText(0); if (name != databaseInfoTableName()) tableNames.append(name); } enableAuthorizer(); if (result != SQLResultDone) { LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data()); return Vector<String>(); } return tableNames; }
void DatabaseSync::runTransaction(PassOwnPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionState& exceptionState) { ASSERT(m_executionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { setLastErrorMessage("unable to start a transaction from within a transaction"); exceptionState.throwUninformativeAndGenericDOMException(SQLDatabaseError); return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly); transaction->begin(exceptionState); if (exceptionState.hadException()) { rollbackTransaction(transaction); return; } transaction->execute(exceptionState); if (exceptionState.hadException()) { rollbackTransaction(transaction); return; } transaction->commit(exceptionState); if (exceptionState.hadException()) { rollbackTransaction(transaction); return; } setLastErrorMessage(""); }
bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key) { if (!m_unique) return true; SQLiteStatement query(sqliteDatabase(), "SELECT id FROM IndexData " + whereClause(key)); bool ok = query.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? bindWhereClause(query, m_id, key); bool existingValue = query.step() == SQLResultRow; return !existingValue; }
void DatabaseSync::runTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionCode& ec) { ASSERT(m_scriptExecutionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { ec = SQLException::DATABASE_ERR; return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly); if ((ec = transaction->begin()) || (ec = transaction->execute()) || (ec = transaction->commit())) transaction->rollback(); }
void IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks> callbacks) { if (m_indexes.contains(name)) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Index name already exists.")); return; } SQLiteStatement insert(sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)"); bool ok = insert.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. insert.bindInt64(1, m_id); insert.bindText(2, name); insert.bindText(3, keyPath); insert.bindInt(4, static_cast<int>(unique)); ok = insert.step() == SQLResultDone; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. int64_t id = sqliteDatabase().lastInsertRowID(); RefPtr<IDBIndexBackendInterface> index = IDBIndexBackendImpl::create(this, id, name, keyPath, unique); ASSERT(index->name() == name); m_indexes.set(name, index); callbacks->onSuccess(index.release()); }
void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) { SQLiteStatement query(sqliteDatabase(), "DELETE FROM ObjectStoreData " + whereClause(key->type())); bool ok = query.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? bindWhereClause(query, m_id, key.get()); if (query.step() != SQLResultDone) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); return; } callbacks->onSuccess(); }
void IDBDatabaseBackendImpl::loadObjectStores() { SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores WHERE databaseId = ?"); bool ok = objectStoresQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? objectStoresQuery.bindInt64(1, m_id); while (objectStoresQuery.step() == SQLResultRow) { int64_t id = objectStoresQuery.getColumnInt64(0); String name = objectStoresQuery.getColumnText(1); String keyPath = objectStoresQuery.getColumnText(2); bool autoIncrement = !!objectStoresQuery.getColumnInt(3); m_objectStores.set(name, IDBObjectStoreBackendImpl::create(m_sqliteDatabase.get(), id, name, keyPath, autoIncrement)); } }
void IDBObjectStoreBackendImpl::loadIndexes() { SQLiteStatement indexQuery(sqliteDatabase(), "SELECT id, name, keyPath, isUnique FROM Indexes WHERE objectStoreId = ?"); bool ok = indexQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? indexQuery.bindInt64(1, m_id); while (indexQuery.step() == SQLResultRow) { int64_t id = indexQuery.getColumnInt64(0); String name = indexQuery.getColumnText(1); String keyPath = indexQuery.getColumnText(2); bool unique = !!indexQuery.getColumnInt(3); m_indexes.set(name, IDBIndexBackendImpl::create(this, id, name, keyPath, unique)); } }
void DatabaseSync::runTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionCode& ec) { ASSERT(m_scriptExecutionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { setLastErrorMessage("unable to start a transaction from within a transaction"); ec = SQLException::DATABASE_ERR; return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly); if ((ec = transaction->begin()) || (ec = transaction->execute()) || (ec = transaction->commit())) { ASSERT(!lastErrorMessage().isEmpty()); transaction->rollback(); } setLastErrorMessage(""); }
void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks) { // FIXME: Fully implement. RefPtr<IDBKey> key = range->left(); SQLiteStatement query(sqliteDatabase(), "SELECT id, value FROM ObjectStoreData " + whereClause(key->type())); bool ok = query.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? bindWhereClause(query, m_id, key.get()); if (query.step() != SQLResultRow) { callbacks->onSuccess(); return; } RefPtr<SerializedScriptValue> value = SerializedScriptValue::createFromWire(query.getColumnText(1)); RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(this, range, static_cast<IDBCursor::Direction>(direction), key.release(), value.release()); callbacks->onSuccess(cursor.release()); }
void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) { SQLiteStatement query(sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key->type())); bool ok = query.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? bindWhereClause(query, m_id, key.get()); if (query.step() != SQLResultRow) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); return; } ASSERT((key->type() == IDBKey::StringType) != query.isColumnNull(0)); // FIXME: Implement date. ASSERT((key->type() == IDBKey::NumberType) != query.isColumnNull(2)); callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(3))); ASSERT(query.step() != SQLResultRow); }
void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCallbacks> callbacks) { if (!m_indexes.contains(name)) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Index name does not exist.")); return; } SQLiteStatement deleteQuery(sqliteDatabase(), "DELETE FROM Indexes WHERE name = ? AND objectStoreId = ?"); bool ok = deleteQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. deleteQuery.bindText(1, name); deleteQuery.bindInt64(2, m_id); ok = deleteQuery.step() == SQLResultDone; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling. // FIXME: Delete index data as well. m_indexes.remove(name); callbacks->onSuccess(); }
void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionCode& ec) { ASSERT(m_scriptExecutionContext->isContextThread()); if (sqliteDatabase().transactionInProgress()) { ec = SQLException::DATABASE_ERR; return; } RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false); if ((ec = transaction->begin())) return; String actualVersion; if (!getVersionFromDatabase(actualVersion)) { ec = SQLException::UNKNOWN_ERR; return; } if (actualVersion != oldVersion) { ec = SQLException::VERSION_ERR; return; } if ((ec = transaction->execute())) return; if (!setVersionInDatabase(newVersion)) { ec = SQLException::UNKNOWN_ERR; return; } if ((ec = transaction->commit())) return; setExpectedVersion(newVersion); }
void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks) { RefPtr<SerializedScriptValue> value = prpValue; RefPtr<IDBKey> key = prpKey; if (!m_keyPath.isNull()) { if (key) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath.")); return; } Vector<RefPtr<SerializedScriptValue> > values; values.append(value); Vector<RefPtr<IDBKey> > idbKeys; IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, m_keyPath, idbKeys); if (idbKeys.isEmpty()) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "An invalid keyPath was supplied for an objectStore.")); return; } key = idbKeys[0]; } if (!key) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied.")); return; } SQLiteStatement getQuery(sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key->type())); bool ok = getQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? bindWhereClause(getQuery, m_id, key.get()); bool existingValue = getQuery.step() == SQLResultRow; if (addOnly && existingValue) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store.")); return; } String sql = existingValue ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?" : "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)"; SQLiteStatement putQuery(sqliteDatabase(), sql); ok = putQuery.prepare() == SQLResultOk; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? switch (key->type()) { case IDBKey::StringType: putQuery.bindText(1, key->string()); putQuery.bindNull(2); putQuery.bindNull(3); break; // FIXME: Implement date. case IDBKey::NumberType: putQuery.bindNull(1); putQuery.bindNull(2); putQuery.bindInt(3, key->number()); break; case IDBKey::NullType: putQuery.bindNull(1); putQuery.bindNull(2); putQuery.bindNull(3); break; default: ASSERT_NOT_REACHED(); } putQuery.bindText(4, value->toWireString()); if (existingValue) putQuery.bindInt(5, getQuery.getColumnInt(0)); else putQuery.bindInt64(5, m_id); ok = putQuery.step() == SQLResultDone; ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? callbacks->onSuccess(key.get()); }