Changeset 80220 in webkit
- Timestamp:
- Mar 3, 2011 2:37:41 AM (13 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r80218 r80220 1 2011-03-03 Hans Wennborg <hans@chromium.org> 2 3 Reviewed by Jeremy Orlow. 4 5 IndexedDB: Move SQL code, especially for cursors, to IDBBackingStore 6 https://bugs.webkit.org/show_bug.cgi?id=55376 7 8 Move SQL code from IDBKey, IDBKeyRange, IDBIndexBackendImpl, 9 IDBObjectStoreBackendImpl, and especially IDBCursorBackendImpl. 10 11 No new functionality, so no new tests. 12 13 * storage/IDBBackingStore.cpp: 14 (WebCore::lowerCursorWhereFragment): 15 (WebCore::upperCursorWhereFragment): 16 (WebCore::IDBBackingStore::deleteObjectStoreRecord): 17 (WebCore::IDBBackingStore::keyExistsInObjectStore): 18 (WebCore::IDBBackingStore::getObjectViaIndex): 19 (WebCore::keyFromQuery): 20 (WebCore::IDBBackingStore::getPrimaryKeyViaIndex): 21 (WebCore::IDBBackingStore::keyExistsInIndex): 22 (WebCore::CursorImplCommon::CursorImplCommon::continueInternal): 23 (WebCore::CursorImplCommon::ObjectStoreCursorImpl::ObjectStoreCursorImpl): 24 (WebCore::CursorImplCommon::ObjectStoreCursorImpl::objectStoreDataId): 25 (WebCore::CursorImplCommon::ObjectStoreCursorImpl::key): 26 (WebCore::CursorImplCommon::ObjectStoreCursorImpl::value): 27 (WebCore::CursorImplCommon::ObjectStoreCursorImpl::continueFunction): 28 (WebCore::IDBBackingStore::openObjectStoreCursor): 29 (WebCore::ObjectStoreCursorImpl::loadCurrentRow): 30 (WebCore::ObjectStoreCursorImpl::currentRowExists): 31 (WebCore::IndexKeyCursorImpl::IndexKeyCursorImpl): 32 (WebCore::IndexKeyCursorImpl::indexDataId): 33 (WebCore::IndexKeyCursorImpl::key): 34 (WebCore::IndexKeyCursorImpl::primaryKey): 35 (WebCore::IndexKeyCursorImpl::continueFunction): 36 (WebCore::IDBBackingStore::openIndexKeyCursor): 37 (WebCore::IndexKeyCursorImpl::loadCurrentRow): 38 (WebCore::IndexKeyCursorImpl::currentRowExists): 39 (WebCore::IndexCursorImpl::IndexCursorImpl): 40 (WebCore::IndexCursorImpl::indexDataId): 41 (WebCore::IndexCursorImpl::key): 42 (WebCore::IndexCursorImpl::primaryKey): 43 (WebCore::IndexCursorImpl::value): 44 (WebCore::IndexCursorImpl::continueFunction): 45 (WebCore::IDBBackingStore::openIndexCursor): 46 (WebCore::IndexCursorImpl::loadCurrentRow): 47 (WebCore::IndexCursorImpl::currentRowExists): 48 * storage/IDBBackingStore.h: 49 (WebCore::IDBBackingStore::Cursor::~Cursor): 50 * storage/IDBCursorBackendImpl.cpp: 51 (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl): 52 (WebCore::IDBCursorBackendImpl::key): 53 (WebCore::IDBCursorBackendImpl::value): 54 (WebCore::IDBCursorBackendImpl::update): 55 (WebCore::IDBCursorBackendImpl::continueFunctionInternal): 56 (WebCore::IDBCursorBackendImpl::deleteFunction): 57 * storage/IDBCursorBackendImpl.h: 58 (WebCore::IDBCursorBackendImpl::create): 59 * storage/IDBIndexBackendImpl.cpp: 60 (WebCore::IDBIndexBackendImpl::openCursorInternal): 61 (WebCore::IDBIndexBackendImpl::getInternal): 62 (WebCore::IDBIndexBackendImpl::addingKeyAllowed): 63 * storage/IDBIndexBackendImpl.h: 64 * storage/IDBKey.cpp: 65 (WebCore::IDBKey::isEqual): 66 * storage/IDBKey.h: 67 * storage/IDBKeyRange.cpp: 68 * storage/IDBKeyRange.h: 69 * storage/IDBObjectStoreBackendImpl.cpp: 70 (WebCore::IDBObjectStoreBackendImpl::putInternal): 71 (WebCore::IDBObjectStoreBackendImpl::deleteInternal): 72 (WebCore::IDBObjectStoreBackendImpl::openCursorInternal): 73 * storage/IDBObjectStoreBackendImpl.h: 74 1 75 2011-03-03 Peter Kasting <pkasting@google.com> 2 76 -
trunk/Source/WebCore/storage/IDBBackingStore.cpp
r79445 r80220 32 32 #include "IDBFactoryBackendImpl.h" 33 33 #include "IDBKey.h" 34 #include "IDBKeyRange.h" 34 35 #include "SQLiteDatabase.h" 35 36 #include "SQLiteStatement.h" … … 335 336 ASSERT_NOT_REACHED(); 336 337 return 0; 338 } 339 340 static String lowerCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "") 341 { 342 switch (key.type()) { 343 case IDBKey::StringType: 344 return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND "; 345 case IDBKey::DateType: 346 return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate OR NOT " + qualifiedTableName + "keyString IS NULL) AND "; 347 case IDBKey::NumberType: 348 return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber OR NOT " + qualifiedTableName + "keyString IS NULL OR NOT " + qualifiedTableName + "keyDate IS NULL) AND "; 349 case IDBKey::NullType: 350 if (comparisonOperator == "<") 351 return "NOT(" + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL) AND "; 352 return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op. 353 } 354 ASSERT_NOT_REACHED(); 355 return ""; 356 } 357 358 static String upperCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "") 359 { 360 switch (key.type()) { 361 case IDBKey::StringType: 362 return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND "; 363 case IDBKey::DateType: 364 return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND "; 365 case IDBKey::NumberType: 366 return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND "; 367 case IDBKey::NullType: 368 if (comparisonOperator == "<") 369 return "0 != 0 AND "; 370 return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL AND "; 371 } 372 ASSERT_NOT_REACHED(); 373 return ""; 337 374 } 338 375 … … 416 453 } 417 454 455 void IDBBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId) 456 { 457 SQLiteStatement osQuery(m_db, "DELETE FROM ObjectStoreData WHERE id = ?"); 458 bool ok = osQuery.prepare() == SQLResultOk; 459 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 460 461 osQuery.bindInt64(1, objectStoreDataId); 462 463 ok = osQuery.step() == SQLResultDone; 464 ASSERT_UNUSED(ok, ok); 465 466 SQLiteStatement indexQuery(m_db, "DELETE FROM IndexData WHERE objectStoreDataId = ?"); 467 ok = indexQuery.prepare() == SQLResultOk; 468 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 469 470 indexQuery.bindInt64(1, objectStoreDataId); 471 472 ok = indexQuery.step() == SQLResultDone; 473 ASSERT_UNUSED(ok, ok); 474 } 475 418 476 double IDBBackingStore::nextAutoIncrementNumber(int64_t objectStoreId) 419 477 { … … 428 486 429 487 return query.getColumnDouble(0); 488 } 489 490 bool IDBBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey& key, int64_t& foundObjectStoreDataId) 491 { 492 String sql = String("SELECT id FROM ObjectStoreData WHERE objectStoreId = ? AND ") + whereSyntaxForKey(key); 493 SQLiteStatement query(m_db, sql); 494 bool ok = query.prepare() == SQLResultOk; 495 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 496 497 query.bindInt64(1, objectStoreId); 498 bindKeyToQuery(query, 2, key); 499 500 if (query.step() != SQLResultRow) 501 return false; 502 503 foundObjectStoreDataId = query.getColumnInt64(0); 504 return true; 430 505 } 431 506 … … 516 591 } 517 592 593 String IDBBackingStore::getObjectViaIndex(int64_t indexId, const IDBKey& key) 594 { 595 String sql = String("SELECT ") 596 + "ObjectStoreData.value " 597 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " 598 + "WHERE IndexData.indexId = ? AND " + whereSyntaxForKey(key, "IndexData.") 599 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. 600 SQLiteStatement query(m_db, sql); 601 bool ok = query.prepare() == SQLResultOk; 602 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 603 604 query.bindInt64(1, indexId); 605 bindKeyToQuery(query, 2, key); 606 607 if (query.step() != SQLResultRow) 608 return String(); 609 610 String foundValue = query.getColumnBlobAsString(0); 611 ASSERT(query.step() != SQLResultRow); 612 return foundValue; 613 } 614 615 static PassRefPtr<IDBKey> keyFromQuery(SQLiteStatement& query, int baseColumn) 616 { 617 if (query.columnCount() <= baseColumn) 618 return 0; 619 620 if (!query.isColumnNull(baseColumn)) 621 return IDBKey::createString(query.getColumnText(baseColumn)); 622 623 if (!query.isColumnNull(baseColumn + 1)) 624 return IDBKey::createDate(query.getColumnDouble(baseColumn + 1)); 625 626 if (!query.isColumnNull(baseColumn + 2)) 627 return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2)); 628 629 return IDBKey::createNull(); 630 } 631 632 PassRefPtr<IDBKey> IDBBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const IDBKey& key) 633 { 634 String sql = String("SELECT ") 635 + "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber " 636 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " 637 + "WHERE IndexData.indexId = ? AND " + whereSyntaxForKey(key, "IndexData.") 638 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. 639 SQLiteStatement query(m_db, sql); 640 bool ok = query.prepare() == SQLResultOk; 641 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 642 643 query.bindInt64(1, indexId); 644 bindKeyToQuery(query, 2, key); 645 646 if (query.step() != SQLResultRow) 647 return false; 648 649 RefPtr<IDBKey> foundKey = keyFromQuery(query, 0); 650 ASSERT(query.step() != SQLResultRow); 651 return foundKey.release(); 652 } 653 654 bool IDBBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key) 655 { 656 String sql = String("SELECT id FROM IndexData WHERE indexId = ? AND ") + whereSyntaxForKey(key); 657 SQLiteStatement query(m_db, sql); 658 bool ok = query.prepare() == SQLResultOk; 659 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 660 661 query.bindInt64(1, indexId); 662 bindKeyToQuery(query, 2, key); 663 664 return query.step() == SQLResultRow; 665 } 666 667 namespace { 668 669 class CursorImplCommon : public IDBBackingStore::Cursor { 670 public: 671 CursorImplCommon(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint) 672 : m_query(sqliteDatabase, query) 673 , m_db(sqliteDatabase) 674 , m_uniquenessConstraint(uniquenessConstraint) 675 { 676 } 677 virtual ~CursorImplCommon() {} 678 679 // IDBBackingStore::Cursor 680 virtual bool continueFunction(const IDBKey*); 681 virtual PassRefPtr<IDBKey> key() { return m_currentKey; } 682 virtual PassRefPtr<IDBKey> primaryKey() { return m_currentKey; } 683 virtual String value() = 0; 684 virtual int64_t objectStoreDataId() = 0; 685 virtual int64_t indexDataId() = 0; 686 687 virtual void loadCurrentRow() = 0; 688 virtual bool currentRowExists() = 0; 689 690 SQLiteStatement m_query; 691 692 protected: 693 SQLiteDatabase& m_db; 694 bool m_uniquenessConstraint; 695 int64_t m_currentId; 696 RefPtr<IDBKey> m_currentKey; 697 }; 698 699 bool CursorImplCommon::continueFunction(const IDBKey* key) 700 { 701 while (true) { 702 if (m_query.step() != SQLResultRow) 703 return false; 704 705 RefPtr<IDBKey> oldKey = m_currentKey; 706 loadCurrentRow(); 707 708 // Skip if this entry has been deleted from the object store. 709 if (!currentRowExists()) 710 continue; 711 712 // If a key was supplied, we must loop until we find that key (or hit the end). 713 if (key && !key->isEqual(m_currentKey.get())) 714 continue; 715 716 // If we don't have a uniqueness constraint, we can stop now. 717 if (!m_uniquenessConstraint) 718 break; 719 if (!m_currentKey->isEqual(oldKey.get())) 720 break; 721 } 722 723 return true; 724 } 725 726 class ObjectStoreCursorImpl : public CursorImplCommon { 727 public: 728 ObjectStoreCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint) 729 : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint) 730 { 731 } 732 733 // CursorImplCommon. 734 virtual String value() { return m_currentValue; } 735 virtual int64_t objectStoreDataId() { return m_currentId; } 736 virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; } 737 virtual void loadCurrentRow(); 738 virtual bool currentRowExists(); 739 740 private: 741 String m_currentValue; 742 }; 743 744 void ObjectStoreCursorImpl::loadCurrentRow() 745 { 746 m_currentId = m_query.getColumnInt64(0); 747 m_currentKey = keyFromQuery(m_query, 1); 748 m_currentValue = m_query.getColumnBlobAsString(4); 749 } 750 751 bool ObjectStoreCursorImpl::currentRowExists() 752 { 753 String sql = "SELECT id FROM ObjectStoreData WHERE id = ?"; 754 SQLiteStatement statement(m_db, sql); 755 756 bool ok = statement.prepare() == SQLResultOk; 757 ASSERT_UNUSED(ok, ok); 758 759 statement.bindInt64(1, m_currentId); 760 return statement.step() == SQLResultRow; 761 } 762 763 class IndexKeyCursorImpl : public CursorImplCommon { 764 public: 765 IndexKeyCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint) 766 : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint) 767 { 768 } 769 770 // CursorImplCommon 771 virtual PassRefPtr<IDBKey> primaryKey() { return m_currentPrimaryKey; } 772 virtual String value() { ASSERT_NOT_REACHED(); return String(); } 773 virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; } 774 virtual int64_t indexDataId() { return m_currentId; } 775 virtual void loadCurrentRow(); 776 virtual bool currentRowExists(); 777 778 private: 779 RefPtr<IDBKey> m_currentPrimaryKey; 780 }; 781 782 void IndexKeyCursorImpl::loadCurrentRow() 783 { 784 m_currentId = m_query.getColumnInt64(0); 785 m_currentKey = keyFromQuery(m_query, 1); 786 m_currentPrimaryKey = keyFromQuery(m_query, 4); 787 } 788 789 bool IndexKeyCursorImpl::currentRowExists() 790 { 791 String sql = "SELECT id FROM IndexData WHERE id = ?"; 792 SQLiteStatement statement(m_db, sql); 793 794 bool ok = statement.prepare() == SQLResultOk; 795 ASSERT_UNUSED(ok, ok); 796 797 statement.bindInt64(1, m_currentId); 798 return statement.step() == SQLResultRow; 799 } 800 801 class IndexCursorImpl : public CursorImplCommon { 802 public: 803 IndexCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint) 804 : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint) 805 { 806 } 807 808 // CursorImplCommon 809 virtual PassRefPtr<IDBKey> primaryKey() { return m_currentPrimaryKey; } 810 virtual String value() { return m_currentValue; } 811 virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; } 812 virtual int64_t indexDataId() { return m_currentId; } 813 virtual void loadCurrentRow(); 814 virtual bool currentRowExists(); 815 816 private: 817 RefPtr<IDBKey> m_currentPrimaryKey; 818 String m_currentValue; 819 }; 820 821 void IndexCursorImpl::loadCurrentRow() 822 { 823 m_currentId = m_query.getColumnInt64(0); 824 m_currentKey = keyFromQuery(m_query, 1); 825 m_currentValue = m_query.getColumnBlobAsString(4); 826 m_currentPrimaryKey = keyFromQuery(m_query, 5); 827 } 828 829 bool IndexCursorImpl::currentRowExists() 830 { 831 String sql = "SELECT id FROM IndexData WHERE id = ?"; 832 SQLiteStatement statement(m_db, sql); 833 834 bool ok = statement.prepare() == SQLResultOk; 835 ASSERT_UNUSED(ok, ok); 836 837 statement.bindInt64(1, m_currentId); 838 return statement.step() == SQLResultRow; 839 } 840 841 } // namespace 842 843 PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction) 844 { 845 bool lowerBound = range && range->lower(); 846 bool upperBound = range && range->upper(); 847 848 String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE "; 849 if (lowerBound) 850 sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<="); 851 if (upperBound) 852 sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<="); 853 sql += "objectStoreId = ? ORDER BY "; 854 855 if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) 856 sql += "keyString, keyDate, keyNumber"; 857 else 858 sql += "keyString DESC, keyDate DESC, keyNumber DESC"; 859 860 RefPtr<ObjectStoreCursorImpl> cursor = adoptRef(new ObjectStoreCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE)); 861 862 bool ok = cursor->m_query.prepare() == SQLResultOk; 863 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 864 865 int currentColumn = 1; 866 if (lowerBound) 867 currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->lower()); 868 if (upperBound) 869 currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->upper()); 870 cursor->m_query.bindInt64(currentColumn, objectStoreId); 871 872 if (cursor->m_query.step() != SQLResultRow) 873 return 0; 874 875 cursor->loadCurrentRow(); 876 return cursor.release(); 877 } 878 879 PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexKeyCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) 880 { 881 String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") 882 + ("ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") 883 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; 884 885 bool lowerBound = range && range->lower(); 886 bool upperBound = range && range->upper(); 887 888 if (lowerBound) 889 sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData."); 890 if (upperBound) 891 sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData."); 892 sql += "IndexData.indexId = ? ORDER BY "; 893 894 if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) 895 sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; 896 else 897 sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; 898 899 RefPtr<IndexKeyCursorImpl> cursor = adoptRef(new IndexKeyCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE)); 900 901 bool ok = cursor->m_query.prepare() == SQLResultOk; 902 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 903 904 int indexColumn = 1; 905 if (lowerBound) 906 indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower()); 907 if (upperBound) 908 indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper()); 909 cursor->m_query.bindInt64(indexColumn, indexId); 910 911 if (cursor->m_query.step() != SQLResultRow) 912 return 0; 913 914 cursor->loadCurrentRow(); 915 return cursor.release(); 916 } 917 918 PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction) 919 { 920 String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") 921 + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") 922 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; 923 924 bool lowerBound = range && range->lower(); 925 bool upperBound = range && range->upper(); 926 927 if (lowerBound) 928 sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData."); 929 if (upperBound) 930 sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData."); 931 sql += "IndexData.indexId = ? ORDER BY "; 932 933 if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) 934 sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; 935 else 936 sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; 937 938 RefPtr<IndexCursorImpl> cursor = adoptRef(new IndexCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE)); 939 940 bool ok = cursor->m_query.prepare() == SQLResultOk; 941 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 942 943 int indexColumn = 1; 944 if (lowerBound) 945 indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower()); 946 if (upperBound) 947 indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper()); 948 cursor->m_query.bindInt64(indexColumn, indexId); 949 950 if (cursor->m_query.step() != SQLResultRow) 951 return 0; 952 953 cursor->loadCurrentRow(); 954 return cursor.release(); 955 } 956 518 957 } // namespace WebCore 519 958 -
trunk/Source/WebCore/storage/IDBBackingStore.h
r79445 r80220 29 29 #if ENABLE(INDEXED_DATABASE) 30 30 31 #include "IDBCursor.h" 31 32 #include "SQLiteDatabase.h" 32 33 #include <wtf/PassRefPtr.h> … … 39 40 class IDBFactoryBackendImpl; 40 41 class IDBKey; 42 class IDBKeyRange; 41 43 class SecurityOrigin; 42 44 … … 55 57 bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId); 56 58 void clearObjectStore(int64_t objectStoreId); 59 void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId); 57 60 double nextAutoIncrementNumber(int64_t objectStoreId); 61 bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId); 58 62 59 63 class ObjectStoreRecordCallback { … … 69 73 bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId); 70 74 bool deleteIndexDataForRecord(int64_t objectStoreDataId); 75 String getObjectViaIndex(int64_t indexId, const IDBKey&); 76 PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&); 77 bool keyExistsInIndex(int64_t indexId, const IDBKey&); 78 79 class Cursor : public RefCounted<Cursor> { 80 public: 81 virtual bool continueFunction(const IDBKey* = 0) = 0; 82 virtual PassRefPtr<IDBKey> key() = 0; 83 virtual PassRefPtr<IDBKey> primaryKey() = 0; 84 virtual String value() = 0; 85 virtual int64_t objectStoreDataId() = 0; 86 virtual int64_t indexDataId() = 0; 87 virtual ~Cursor() {}; 88 }; 89 90 PassRefPtr<Cursor> openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction); 91 PassRefPtr<Cursor> openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); 92 PassRefPtr<Cursor> openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction); 71 93 72 94 SQLiteDatabase& db() { return m_db; } -
trunk/Source/WebCore/storage/IDBCursorBackendImpl.cpp
r80171 r80220 32 32 #include "IDBBackingStore.h" 33 33 #include "IDBCallbacks.h" 34 #include "IDBDatabaseBackendImpl.h"35 34 #include "IDBDatabaseError.h" 36 35 #include "IDBDatabaseException.h" 37 #include "IDBIndexBackendImpl.h"38 36 #include "IDBKeyRange.h" 39 37 #include "IDBObjectStoreBackendImpl.h" 40 38 #include "IDBRequest.h" 41 39 #include "IDBTransactionBackendInterface.h" 42 #include "SQLiteDatabase.h"43 #include "SQLiteStatement.h"44 40 #include "SerializedScriptValue.h" 45 41 46 42 namespace WebCore { 47 43 48 IDBCursorBackendImpl::IDBCursorBackendImpl(IDBBackingStore* backingStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) 49 : m_backingStore(backingStore) 50 , m_keyRange(keyRange) 44 IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) 45 : m_cursor(cursor) 51 46 , m_direction(direction) 52 , m_query(query)53 47 , m_cursorType(cursorType) 54 48 , m_transaction(transaction) 55 49 , m_objectStore(objectStore) 56 50 { 57 loadCurrentRow();58 51 } 59 52 … … 69 62 PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const 70 63 { 71 return m_cur rentKey;64 return m_cursor->key(); 72 65 } 73 66 74 67 PassRefPtr<IDBKey> IDBCursorBackendImpl::primaryKey() const 75 68 { 76 return m_cur rentPrimaryKey;69 return m_cursor->primaryKey(); 77 70 } 78 71 … … 80 73 { 81 74 ASSERT(m_cursorType != IndexKeyCursor); 82 return m_currentValue;75 return SerializedScriptValue::createFromWire(m_cursor->value()); 83 76 } 84 77 85 78 void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBCallbacks> callbacks, ExceptionCode& ec) 86 79 { 87 if (!m_ query || m_currentId == InvalidId|| m_cursorType == IndexKeyCursor) {80 if (!m_cursor || m_cursorType == IndexKeyCursor) { 88 81 ec = IDBDatabaseException::NOT_ALLOWED_ERR; 89 82 return; 90 83 } 91 84 92 m_objectStore->put(value, m_cur rentPrimaryKey, IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec);85 m_objectStore->put(value, m_cursor->primaryKey(), IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec); 93 86 } 94 87 … … 102 95 } 103 96 104 bool IDBCursorBackendImpl::currentRowExists()105 {106 String sql = m_cursorType == ObjectStoreCursor ? "SELECT id FROM ObjectStoreData WHERE id = ?" : "SELECT id FROM IndexData WHERE id = ?";107 SQLiteStatement statement(m_backingStore->db(), sql);108 109 bool ok = statement.prepare() == SQLResultOk;110 ASSERT_UNUSED(ok, ok);111 112 statement.bindInt64(1, m_currentId);113 return statement.step() == SQLResultRow;114 }115 116 97 // IMPORTANT: If this ever 1) fires an 'error' event and 2) it's possible to fire another event afterwards, 117 98 // IDBRequest::hasPendingActivity() will need to be modified to handle this!!! … … 120 101 RefPtr<IDBCursorBackendImpl> cursor = prpCursor; 121 102 RefPtr<IDBKey> key = prpKey; 122 while (true) {123 if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {124 cursor->m_query = 0;125 cursor->m_currentId = InvalidId;126 cursor->m_currentKey = 0;127 cursor->m_currentPrimaryKey = 0;128 cursor->m_currentValue = 0;129 callbacks->onSuccess(SerializedScriptValue::nullValue());130 return;131 }132 103 133 RefPtr<IDBKey> oldKey = cursor->m_currentKey; 134 cursor->loadCurrentRow(); 135 136 // Skip if this entry has been deleted from the object store. 137 if (!cursor->currentRowExists()) 138 continue; 139 140 // If a key was supplied, we must loop until we find that key (or hit the end). 141 if (key && !key->isEqual(cursor->m_currentKey.get())) 142 continue; 143 144 // If we don't have a uniqueness constraint, we can stop now. 145 if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV) 146 break; 147 if (!cursor->m_currentKey->isEqual(oldKey.get())) 148 break; 104 if (!cursor->m_cursor || !cursor->m_cursor->continueFunction(key.get())) { 105 cursor->m_cursor = 0; 106 callbacks->onSuccess(SerializedScriptValue::nullValue()); 107 return; 149 108 } 150 109 … … 154 113 void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec) 155 114 { 156 if (!m_ query || m_currentId == InvalidId|| m_cursorType == IndexKeyCursor) {115 if (!m_cursor || m_cursorType == IndexKeyCursor) { 157 116 ec = IDBDatabaseException::NOT_ALLOWED_ERR; 158 117 return; 159 118 } 160 119 161 m_objectStore->deleteFunction(m_currentPrimaryKey, prpCallbacks, m_transaction.get(), ec); 162 } 163 164 165 void IDBCursorBackendImpl::loadCurrentRow() 166 { 167 // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal and/or IDBIndexBackendImpl::openCursorInternal. 168 m_currentId = m_query->getColumnInt64(0); 169 m_currentKey = IDBKey::fromQuery(*m_query, 1); 170 m_currentValue = SerializedScriptValue::createFromWire(m_query->getColumnBlobAsString(4)); 171 m_currentPrimaryKey = IDBKey::fromQuery(*m_query, 5); 172 } 173 174 SQLiteDatabase& IDBCursorBackendImpl::database() const 175 { 176 return m_backingStore->db(); 120 m_objectStore->deleteFunction(m_cursor->primaryKey(), prpCallbacks, m_transaction.get(), ec); 177 121 } 178 122 -
trunk/Source/WebCore/storage/IDBCursorBackendImpl.h
r80171 r80220 30 30 #if ENABLE(INDEXED_DATABASE) 31 31 32 #include "IDBBackingStore.h" 32 33 #include "IDBCursor.h" 33 34 #include "IDBCursorBackendInterface.h" … … 50 51 class IDBCursorBackendImpl : public IDBCursorBackendInterface { 51 52 public: 52 static PassRefPtr<IDBCursorBackendImpl> create( IDBBackingStore* backingStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)53 static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBBackingStore::Cursor> cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore) 53 54 { 54 return adoptRef(new IDBCursorBackendImpl( backingStore, keyRange, direction, query, cursorType, transaction, objectStore));55 return adoptRef(new IDBCursorBackendImpl(cursor, direction, cursorType, transaction, objectStore)); 55 56 } 56 57 virtual ~IDBCursorBackendImpl(); … … 65 66 66 67 private: 67 IDBCursorBackendImpl(IDBBackingStore*, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*); 68 69 bool currentRowExists(); 70 void loadCurrentRow(); 71 SQLiteDatabase& database() const; 68 IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor>, IDBCursor::Direction, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*); 72 69 73 70 static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>); 74 71 75 static const int64_t InvalidId = -1; 76 77 RefPtr<IDBBackingStore> m_backingStore; 78 79 RefPtr<IDBKeyRange> m_keyRange; 72 RefPtr<IDBBackingStore::Cursor> m_cursor; 80 73 IDBCursor::Direction m_direction; 81 OwnPtr<SQLiteStatement> m_query;82 74 CursorType m_cursorType; 83 int64_t m_currentId;84 85 RefPtr<IDBKey> m_currentKey;86 RefPtr<IDBKey> m_currentPrimaryKey;87 RefPtr<SerializedScriptValue> m_currentValue;88 89 75 RefPtr<IDBTransactionBackendInterface> m_transaction; 90 76 RefPtr<IDBObjectStoreBackendInterface> m_objectStore; -
trunk/Source/WebCore/storage/IDBIndexBackendImpl.cpp
r80171 r80220 38 38 #include "IDBKeyRange.h" 39 39 #include "IDBObjectStoreBackendImpl.h" 40 #include "SQLiteDatabase.h"41 #include "SQLiteStatement.h"42 40 43 41 namespace WebCore { … … 69 67 void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction) 70 68 { 71 // Several files depend on this order of selects. 72 String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ") 73 + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") 74 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE "; 69 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection); 75 70 76 bool lowerBound = range && range->lower(); 77 bool upperBound = range && range->upper(); 78 79 if (lowerBound) 80 sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator(), "IndexData."); 81 if (upperBound) 82 sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator(), "IndexData."); 83 sql += "IndexData.indexId = ? ORDER BY "; 71 RefPtr<IDBBackingStore::Cursor> backingStoreCursor; 84 72 85 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection); 86 if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) 87 sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id"; 88 else 89 sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC"; 73 switch (cursorType) { 74 case IDBCursorBackendInterface::IndexKeyCursor: 75 backingStoreCursor = index->m_backingStore->openIndexKeyCursor(index->id(), range.get(), direction); 76 break; 77 case IDBCursorBackendInterface::IndexCursor: 78 backingStoreCursor = index->m_backingStore->openIndexCursor(index->id(), range.get(), direction); 79 break; 80 case IDBCursorBackendInterface::ObjectStoreCursor: 81 case IDBCursorBackendInterface::InvalidCursorType: 82 ASSERT_NOT_REACHED(); 83 break; 84 } 90 85 91 OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(index->sqliteDatabase(), sql)); 92 bool ok = query->prepare() == SQLResultOk; 93 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 94 95 int indexColumn = 1; 96 if (lowerBound) 97 indexColumn += range->lower()->bind(*query, indexColumn); 98 if (upperBound) 99 indexColumn += range->upper()->bind(*query, indexColumn); 100 query->bindInt64(indexColumn, index->id()); 101 102 if (query->step() != SQLResultRow) { 86 if (!backingStoreCursor) { 103 87 callbacks->onSuccess(SerializedScriptValue::nullValue()); 104 88 return; … … 109 93 ASSERT(objectStore && !ec); 110 94 111 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create( index->m_backingStore.get(), range, direction, query.release(), cursorType, transaction.get(), objectStore.get());95 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), direction, cursorType, transaction.get(), objectStore.get()); 112 96 callbacks->onSuccess(cursor.release()); 113 97 } … … 135 119 void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks) 136 120 { 137 String sql = String("SELECT ") 138 + (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ") 139 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id " 140 + "WHERE IndexData.indexId = ? AND " + key->whereSyntax("IndexData.") 141 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails. 142 SQLiteStatement query(index->sqliteDatabase(), sql); 143 bool ok = query.prepare() == SQLResultOk; 144 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 145 146 query.bindInt64(1, index->id()); 147 key->bind(query, 2); 148 if (query.step() != SQLResultRow) { 149 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); 150 return; 121 // FIXME: Split getInternal into two functions, getting rid off |getObject|. 122 if (getObject) { 123 String value = index->m_backingStore->getObjectViaIndex(index->id(), *key); 124 if (value.isNull()) { 125 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); 126 return; 127 } 128 callbacks->onSuccess(SerializedScriptValue::createFromWire(value)); 129 } else { 130 RefPtr<IDBKey> keyResult = index->m_backingStore->getPrimaryKeyViaIndex(index->id(), *key); 131 if (!keyResult) { 132 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); 133 return; 134 } 135 callbacks->onSuccess(keyResult.get()); 151 136 } 152 153 if (getObject)154 callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0)));155 else156 callbacks->onSuccess(IDBKey::fromQuery(query, 0));157 ASSERT(query.step() != SQLResultRow);158 137 } 159 138 … … 176 155 } 177 156 178 static String whereClause(IDBKey* key)179 {180 return "WHERE indexId = ? AND " + key->whereSyntax();181 }182 183 static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)184 {185 query.bindInt64(1, id);186 key->bind(query, 2);187 }188 189 157 bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key) 190 158 { … … 192 160 return true; 193 161 194 SQLiteStatement query(sqliteDatabase(), "SELECT id FROM IndexData " + whereClause(key)); 195 bool ok = query.prepare() == SQLResultOk; 196 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 197 bindWhereClause(query, m_id, key); 198 bool existingValue = query.step() == SQLResultRow; 199 200 return !existingValue; 201 } 202 203 SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const 204 { 205 return m_backingStore->db(); 162 return !m_backingStore->keyExistsInIndex(m_id, *key); 206 163 } 207 164 -
trunk/Source/WebCore/storage/IDBIndexBackendImpl.h
r80171 r80220 77 77 IDBIndexBackendImpl(IDBBackingStore*, const String& name, const String& storeName, const String& keyPath, bool unique); 78 78 79 SQLiteDatabase& sqliteDatabase() const;80 81 79 static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, unsigned short direction, IDBCursorBackendInterface::CursorType, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>); 82 80 static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKey>, bool getObject, PassRefPtr<IDBCallbacks>); -
trunk/Source/WebCore/storage/IDBKey.cpp
r74342 r80220 29 29 #if ENABLE(INDEXED_DATABASE) 30 30 31 #include "SQLiteStatement.h"32 #include "SerializedScriptValue.h"33 34 31 namespace WebCore { 35 32 … … 43 40 } 44 41 45 PassRefPtr<IDBKey> IDBKey::fromQuery(SQLiteStatement& query, int baseColumn) 46 { 47 if (query.columnCount() <= baseColumn) 48 return 0; 49 50 if (!query.isColumnNull(baseColumn)) 51 return IDBKey::createString(query.getColumnText(baseColumn)); 52 53 if (!query.isColumnNull(baseColumn + 1)) 54 return IDBKey::createDate(query.getColumnDouble(baseColumn + 1)); 55 56 if (!query.isColumnNull(baseColumn + 2)) 57 return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2)); 58 59 return IDBKey::createNull(); 60 } 61 62 bool IDBKey::isEqual(IDBKey* other) 42 bool IDBKey::isEqual(IDBKey* other) const 63 43 { 64 44 if (!other || other->m_type != m_type) … … 80 60 } 81 61 82 String IDBKey::whereSyntax(String qualifiedTableName) const83 {84 switch (m_type) {85 case IDBKey::StringType:86 return qualifiedTableName + "keyString = ? AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL ";87 case IDBKey::NumberType:88 return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber = ? ";89 case IDBKey::DateType:90 return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate = ? AND " + qualifiedTableName + "keyNumber IS NULL ";91 case IDBKey::NullType:92 return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL ";93 }94 95 ASSERT_NOT_REACHED();96 return "";97 }98 99 String IDBKey::lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName)100 {101 switch (m_type) {102 case StringType:103 return "? " + comparisonOperator + " " + qualifiedTableName + "keyString AND ";104 case DateType:105 return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate OR NOT " + qualifiedTableName + "keyString IS NULL) AND ";106 case NumberType:107 return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber OR NOT " + qualifiedTableName + "keyString IS NULL OR NOT " + qualifiedTableName + "keyDate IS NULL) AND ";108 case NullType:109 if (comparisonOperator == "<")110 return "NOT(" + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL) AND ";111 return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.112 }113 ASSERT_NOT_REACHED();114 return "";115 }116 117 String IDBKey::upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName)118 {119 switch (m_type) {120 case StringType:121 return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ? OR " + qualifiedTableName + "keyString IS NULL) AND ";122 case DateType:123 return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND ";124 case NumberType:125 return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL) AND " + qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND ";126 case NullType:127 if (comparisonOperator == "<")128 return "0 != 0 AND ";129 return qualifiedTableName + "keyString IS NULL AND " + qualifiedTableName + "keyDate IS NULL AND " + qualifiedTableName + "keyNumber IS NULL AND ";130 }131 ASSERT_NOT_REACHED();132 return "";133 }134 135 // Returns the number of items bound.136 int IDBKey::bind(SQLiteStatement& query, int column) const137 {138 switch (m_type) {139 case IDBKey::StringType:140 query.bindText(column, m_string);141 return 1;142 case IDBKey::DateType:143 query.bindDouble(column, m_date);144 return 1;145 case IDBKey::NumberType:146 query.bindDouble(column, m_number);147 return 1;148 case IDBKey::NullType:149 return 0;150 }151 152 ASSERT_NOT_REACHED();153 return 0;154 }155 156 void IDBKey::bindWithNulls(SQLiteStatement& query, int baseColumn) const157 {158 switch (m_type) {159 case IDBKey::StringType:160 query.bindText(baseColumn + 0, m_string);161 query.bindNull(baseColumn + 1);162 query.bindNull(baseColumn + 2);163 break;164 case IDBKey::DateType:165 query.bindNull(baseColumn + 0);166 query.bindDouble(baseColumn + 1, m_date);167 query.bindNull(baseColumn + 2);168 break;169 case IDBKey::NumberType:170 query.bindNull(baseColumn + 0);171 query.bindNull(baseColumn + 1);172 query.bindDouble(baseColumn + 2, m_number);173 break;174 case IDBKey::NullType:175 query.bindNull(baseColumn + 0);176 query.bindNull(baseColumn + 1);177 query.bindNull(baseColumn + 2);178 break;179 default:180 ASSERT_NOT_REACHED();181 }182 }183 184 62 } // namespace WebCore 185 63 -
trunk/Source/WebCore/storage/IDBKey.h
r74266 r80220 100 100 } 101 101 102 static PassRefPtr<IDBKey> fromQuery(SQLiteStatement& query, int baseColumn); 103 104 bool isEqual(IDBKey* other); 105 String whereSyntax(String qualifiedTableName = "") const; 106 String lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); 107 String upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName = ""); 108 int bind(SQLiteStatement& query, int column) const; 109 void bindWithNulls(SQLiteStatement& query, int baseColumn) const; 102 bool isEqual(IDBKey* other) const; 110 103 111 104 using ThreadSafeShared<IDBKey>::ref; -
trunk/Source/WebCore/storage/IDBKeyRange.cpp
r80076 r80220 62 62 } 63 63 64 String IDBKeyRange::lowerWhereClauseComparisonOperator() const65 {66 ASSERT(m_lower);67 if (m_lowerOpen)68 return "<";69 return "<=";70 }71 72 String IDBKeyRange::upperWhereClauseComparisonOperator() const73 {74 ASSERT(m_upper);75 if (m_upperOpen)76 return "<";77 return "<=";78 }79 80 64 } // namespace WebCore 81 65 -
trunk/Source/WebCore/storage/IDBKeyRange.h
r80076 r80220 44 44 ~IDBKeyRange() { } 45 45 46 47 46 PassRefPtr<IDBKey> lower() const { return m_lower; } 48 47 PassRefPtr<IDBKey> upper() const { return m_upper; } 49 48 bool lowerOpen() const { return m_lowerOpen; } 50 49 bool upperOpen() const { return m_upperOpen; } 51 52 String lowerWhereClauseComparisonOperator() const;53 String upperWhereClauseComparisonOperator() const;54 50 55 51 static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value); -
trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp
r80171 r80220 44 44 #include "IDBTransactionBackendInterface.h" 45 45 #include "ScriptExecutionContext.h" 46 #include "SQLiteDatabase.h"47 #include "SQLiteStatement.h"48 #include "SQLiteTransaction.h"49 46 50 47 namespace WebCore { … … 83 80 } 84 81 85 static String whereClause(IDBKey* key)86 {87 return "WHERE objectStoreId = ? AND " + key->whereSyntax();88 }89 90 static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)91 {92 query.bindInt64(1, id);93 key->bind(query, 2);94 }95 96 82 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) 97 83 { … … 242 228 } 243 229 244 SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get())); 245 bool ok = getQuery.prepare() == SQLResultOk; 246 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 247 248 bindWhereClause(getQuery, objectStore->id(), key.get()); 249 bool isExistingValue = getQuery.step() == SQLResultRow; 230 int64_t dataRowId = InvalidId; 231 bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, dataRowId); 232 250 233 if (putMode == AddOnly && isExistingValue) { 251 234 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store.")); … … 255 238 // Before this point, don't do any mutation. After this point, rollback the transaction in case of error. 256 239 257 int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId;258 240 if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->id(), *key, value->toWireString(), dataRowId, dataRowId == InvalidId)) { 259 241 // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors. … … 302 284 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks) 303 285 { 304 SQLiteStatement idQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get())); 305 bool ok = idQuery.prepare() == SQLResultOk; 306 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 307 bindWhereClause(idQuery, objectStore->id(), key.get()); 308 if (idQuery.step() != SQLResultRow) { 286 int64_t id; 287 if (!objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, id)) { 309 288 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store.")); 310 289 return; 311 290 } 312 291 313 int64_t id = idQuery.getColumnInt64(0); 314 315 SQLiteStatement osQuery(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE id = ?"); 316 ok = osQuery.prepare() == SQLResultOk; 317 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 318 319 osQuery.bindInt64(1, id); 320 321 ok = osQuery.step() == SQLResultDone; 322 ASSERT_UNUSED(ok, ok); 323 324 SQLiteStatement indexQuery(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE objectStoreDataId = ?"); 325 ok = indexQuery.prepare() == SQLResultOk; 326 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 327 328 indexQuery.bindInt64(1, id); 329 330 ok = indexQuery.step() == SQLResultDone; 331 ASSERT_UNUSED(ok, ok); 332 292 objectStore->m_backingStore->deleteObjectStoreRecord(objectStore->id(), id); 333 293 callbacks->onSuccess(SerializedScriptValue::nullValue()); 334 294 } … … 485 445 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction) 486 446 { 487 bool lowerBound = range && range->lower();488 bool upperBound = range && range->upper();489 490 // Several files depend on this order of selects.491 String sql = "SELECT id, keyString, keyDate, keyNumber, value, keyString, keyDate, keyNumber FROM ObjectStoreData WHERE ";492 if (lowerBound)493 sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator());494 if (upperBound)495 sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator());496 sql += "objectStoreId = ? ORDER BY ";497 498 447 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection); 499 if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE) 500 sql += "keyString, keyDate, keyNumber"; 501 else 502 sql += "keyString DESC, keyDate DESC, keyNumber DESC"; 503 504 OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(objectStore->sqliteDatabase(), sql)); 505 bool ok = query->prepare() == SQLResultOk; 506 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling? 507 508 int currentColumn = 1; 509 if (lowerBound) 510 currentColumn += range->lower()->bind(*query, currentColumn); 511 if (upperBound) 512 currentColumn += range->upper()->bind(*query, currentColumn); 513 query->bindInt64(currentColumn, objectStore->id()); 514 515 if (query->step() != SQLResultRow) { 448 449 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->m_backingStore->openObjectStoreCursor(objectStore->id(), range.get(), direction); 450 if (!backingStoreCursor) { 516 451 callbacks->onSuccess(SerializedScriptValue::nullValue()); 517 452 return; 518 453 } 519 454 520 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create( objectStore->m_backingStore.get(), range, direction, query.release(), IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());455 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get()); 521 456 callbacks->onSuccess(cursor.release()); 522 457 } … … 538 473 } 539 474 540 SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const541 {542 return m_backingStore->db();543 }544 545 475 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index) 546 476 { -
trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h
r79426 r80220 83 83 84 84 void loadIndexes(); 85 SQLiteDatabase& sqliteDatabase() const;86 85 PassRefPtr<IDBKey> genAutoIncrementKey(); 87 86 void resetAutoIncrementKeyCache() { m_autoIncrementNumber = -1; }
Note: See TracChangeset
for help on using the changeset viewer.