IDB: Index cursor preliminary support
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Jan 2014 22:18:08 +0000 (22:18 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 Jan 2014 22:18:08 +0000 (22:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=127869

Reviewed by Sam Weinig.

This gets index cursors running and - for some situations - returning results.

Bug 127870 will make them fully functional.

* DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.cpp:
(WebKit::getIndexStatement): Using the key and sorting parameters, find the appropriate SQL
  statement to run an index cursor.
(WebKit::getObjectStoreStatement): Same, but for object store cursors.
(WebKit::SQLiteIDBCursor::establishStatement): Depending on the type of cursor, choose the
  correct SQL query and id to use.
(WebKit::SQLiteIDBCursor::createSQLiteStatement): With the passed in SQL and id, handle both
  index and object store cursors.
* DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@163200 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.cpp
Source/WebKit2/DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.h

index 68cfeaf..719f28f 100644 (file)
@@ -1,3 +1,24 @@
+2014-01-31  Brady Eidson  <beidson@apple.com>
+
+        IDB: Index cursor preliminary support
+        https://bugs.webkit.org/show_bug.cgi?id=127869
+
+        Reviewed by Sam Weinig.
+
+        This gets index cursors running and - for some situations - returning results.
+
+        Bug 127870 will make them fully functional.
+
+        * DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.cpp:
+        (WebKit::getIndexStatement): Using the key and sorting parameters, find the appropriate SQL
+          statement to run an index cursor.
+        (WebKit::getObjectStoreStatement): Same, but for object store cursors.
+        (WebKit::SQLiteIDBCursor::establishStatement): Depending on the type of cursor, choose the
+          correct SQL query and id to use.
+        (WebKit::SQLiteIDBCursor::createSQLiteStatement): With the passed in SQL and id, handle both
+          index and object store cursors.
+        * DatabaseProcess/IndexedDB/sqlite/SQLiteIDBCursor.h:
+
 2014-01-29  Oliver Hunt  <oliver@apple.com>
 
         Make it possible to implement JS builtins in JS
index 2104821..cfd8fe9 100644 (file)
@@ -63,61 +63,141 @@ SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction* transaction, const IDBIde
     ASSERT(m_objectStoreID);
 }
 
-bool SQLiteIDBCursor::establishStatement()
+static const String& getIndexStatement(bool lowerKey, bool lowerOpen, bool upperKey, bool upperOpen, bool descending)
 {
-    if (m_indexID != IDBIndexMetadata::InvalidId)
-        return createIndexCursorStatement();
+    DEFINE_STATIC_LOCAL(Vector<String>, indexStatements, ());
+
+    if (indexStatements.isEmpty()) {
+        indexStatements.reserveCapacity(18);
+
+        // No lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+
+        // Closed lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+
+        // Open lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM IndexRecords WHERE indexID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+    }
 
-    return createObjectStoreCursorStatement();
+    size_t i = 0;
+    if (lowerKey)
+        i += 6;
+    if (lowerOpen)
+        i += 6;
+    if (upperKey)
+        i += 2;
+    if (upperOpen)
+        i += 2;
+    if (descending)
+        i += 1;
+
+    return indexStatements[i];
 }
 
-bool SQLiteIDBCursor::createIndexCursorStatement()
+static const String& getObjectStoreStatement(bool lowerKey, bool lowerOpen, bool upperKey, bool upperOpen, bool descending)
 {
-    LOG_ERROR("Index cursor not yet supported (index id is %lli)", m_indexID);
-    return false;
+    DEFINE_STATIC_LOCAL(Vector<String>, indexStatements, ());
+
+    if (indexStatements.isEmpty()) {
+        indexStatements.reserveCapacity(18);
+
+        // No lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+
+        // Closed lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+
+        // Open lower key statements (6)
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key DESC;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key;"));
+        indexStatements.append(ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ? AND key > CAST(? AS TEXT) AND key < CAST(? AS TEXT) ORDER BY key DESC;"));
+    }
+
+    size_t i = 0;
+    if (lowerKey)
+        i += 6;
+    if (lowerOpen)
+        i += 6;
+    if (upperKey)
+        i += 2;
+    if (upperOpen)
+        i += 2;
+    if (descending)
+        i += 1;
+
+    return indexStatements[i];
 }
 
-bool SQLiteIDBCursor::createObjectStoreCursorStatement()
+bool SQLiteIDBCursor::establishStatement()
 {
-    ASSERT(m_transaction->sqliteTransaction());
-    SQLiteDatabase& database = m_transaction->sqliteTransaction()->database();
-
-    String lowerSQL;
-    if (!m_keyRange.lowerKey.isNull)
-        lowerSQL = m_keyRange.lowerOpen ? ASCIILiteral("AND key >= CAST(? AS TEXT)") : ASCIILiteral("AND key > CAST(? AS TEXT)");
-
-    String upperSQL;
-    if (!m_keyRange.upperKey.isNull)
-        lowerSQL = m_keyRange.upperOpen ? ASCIILiteral("AND key <= CAST(? AS TEXT)") : ASCIILiteral("AND key < CAST(? AS TEXT)");
+    String sql;
+    int64_t id;
+
+    if (m_indexID != IDBIndexMetadata::InvalidId) {
+        sql = getIndexStatement(!m_keyRange.lowerKey.isNull, m_keyRange.lowerOpen, !m_keyRange.upperKey.isNull, m_keyRange.upperOpen, m_cursorDirection == IndexedDB::CursorDirection::Prev || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate);
+        id = m_indexID;
+    } else {
+        sql = getObjectStoreStatement(!m_keyRange.lowerKey.isNull, m_keyRange.lowerOpen, !m_keyRange.upperKey.isNull, m_keyRange.upperOpen, m_cursorDirection == IndexedDB::CursorDirection::Prev || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate);
+        id = m_objectStoreID;
+    }
 
-    String orderSQL;
-    if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate)
-        orderSQL = ASCIILiteral(" ORDER BY key;");
-    else
-        orderSQL = ASCIILiteral(" ORDER BY key DESC;");
+    return createSQLiteStatement(sql, id);
+}
 
-    String sql = ASCIILiteral("SELECT key, value FROM Records WHERE objectStoreID = ?") + lowerSQL + upperSQL + orderSQL;
+bool SQLiteIDBCursor::createSQLiteStatement(const String& sql, int64_t idToBind)
+{
+    ASSERT(m_transaction->sqliteTransaction());
+    SQLiteDatabase& database = m_transaction->sqliteTransaction()->database();
 
     LOG(IDB, "Creating cursor with SQL query: \"%s\"", sql.utf8().data());
 
     m_statement = std::make_unique<SQLiteStatement>(database, sql);
 
     if (m_statement->prepare() != SQLResultOk
-        || m_statement->bindInt64(1, m_objectStoreID) != SQLResultOk) {
+        || m_statement->bindInt64(1, idToBind) != SQLResultOk) {
         LOG_ERROR("Could not create cursor statement");
         return false;
     }
 
     int nextBindArgument = 2;
 
-    if (!lowerSQL.isEmpty()) {
+    if (!m_keyRange.lowerKey.isNull) {
         RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_keyRange.lowerKey);
         if (m_statement->bindBlob(nextBindArgument++, buffer->data(), buffer->size()) != SQLResultOk) {
             LOG_ERROR("Could not create cursor statement");
             return false;
         }
     }
-    if (!upperSQL.isEmpty()) {
+    if (!m_keyRange.upperKey.isNull) {
         RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_keyRange.upperKey);
         if (m_statement->bindBlob(nextBindArgument, buffer->data(), buffer->size()) != SQLResultOk) {
             LOG_ERROR("Could not create cursor statement");
index 6030cf5..d6896dc 100644 (file)
@@ -67,8 +67,7 @@ private:
     SQLiteIDBCursor(SQLiteIDBTransaction*, const IDBIdentifier& cursorIdentifier, int64_t objectStoreID, int64_t indexID, WebCore::IndexedDB::CursorDirection, WebCore::IndexedDB::CursorType, WebCore::IDBDatabaseBackend::TaskType, const WebCore::IDBKeyRangeData&);
 
     bool establishStatement();
-    bool createIndexCursorStatement();
-    bool createObjectStoreCursorStatement();
+    bool createSQLiteStatement(const String& sql, int64_t idToBind);
 
     SQLiteIDBTransaction* m_transaction;
     IDBIdentifier m_cursorIdentifier;