731bool SQLiteIDBBackingStore::migrateIndexInfoTableForIDUpdate(const HashMap<std::pair<uint64_t, uint64_t>, uint64_t>& indexIDMap)
732{
733 SQLiteDatabase& database = *m_sqliteDB;
734 SQLiteTransaction transaction(database);
735 transaction.begin();
736
737 if (!database.executeCommand(indexInfoTableSchema("_Temp_IndexInfo"))) {
738 LOG_ERROR("Error creating _Temp_IndexInfo table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
739 return false;
740 }
741
742 {
743 SQLiteStatement statement(database, "SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;"_s);
744 if (statement.prepare() != SQLITE_OK) {
745 LOG_ERROR("Error preparing statement to fetch records from IndexInfo table (%i) - %s", database.lastError(), database.lastErrorMsg());
746 return false;
747 }
748
749 int result = statement.step();
750 while (result == SQLITE_ROW) {
751 uint64_t id = statement.getColumnInt64(0);
752 String name = statement.getColumnText(1);
753 uint64_t objectStoreID = statement.getColumnInt64(2);
754 uint64_t newID = indexIDMap.get({ objectStoreID, id });
755 Vector<uint8_t> keyPathBuffer;
756 statement.getColumnBlobAsVector(3, keyPathBuffer);
757 bool unique = statement.getColumnInt(4);
758 bool multiEntry = statement.getColumnInt(5);
759
760 auto sql = cachedStatement(SQL::CreateTempIndexInfo, "INSERT INTO _Temp_IndexInfo VALUES (?, ?, ?, ?, ?, ?);"_s);
761 if (!sql
762 || sql->bindInt64(1, newID) != SQLITE_OK
763 || sql->bindText(2, name) != SQLITE_OK
764 || sql->bindInt64(3, objectStoreID) != SQLITE_OK
765 || sql->bindBlob(4, keyPathBuffer.data(), keyPathBuffer.size()) != SQLITE_OK
766 || sql->bindInt(5, unique) != SQLITE_OK
767 || sql->bindInt(6, multiEntry) != SQLITE_OK
768 || sql->step() != SQLITE_DONE) {
769 LOG_ERROR("Error adding index '%s' to _Temp_IndexInfo table (%i) - %s", name.utf8().data(), database.lastError(), database.lastErrorMsg());
770 return false;
771 }
772
773 result = statement.step();
774 }
775
776 if (result != SQLITE_DONE) {
777 LOG_ERROR("Error fetching indices from IndexInfo table (%i) - %s", database.lastError(), database.lastErrorMsg());
778 return false;
779 }
780 }
781
782 if (!database.executeCommand("DROP TABLE IndexInfo")) {
783 LOG_ERROR("Error dropping existing IndexInfo table (%i) - %s", database.lastError(), database.lastErrorMsg());
784 return false;
785 }
786
787 if (!database.executeCommand("ALTER TABLE _Temp_IndexInfo RENAME TO IndexInfo")) {
788 LOG_ERROR("Error renaming _Temp_IndexInfo table (%i) - %s", database.lastError(), database.lastErrorMsg());
789 return false;
790 }
791
792 transaction.commit();
793 return true;
794}
795
796bool SQLiteIDBBackingStore::migrateIndexRecordsTableForIDUpdate(const HashMap<std::pair<uint64_t, uint64_t>, uint64_t>& indexIDMap)
797{
798 SQLiteDatabase& database = *m_sqliteDB;
799 SQLiteTransaction transaction(database);
800 transaction.begin();
801
802 if (!database.executeCommand(v3IndexRecordsTableSchema("_Temp_IndexRecords"))) {
803 LOG_ERROR("Error creating _Temp_IndexRecords table in database (%i) - %s", database.lastError(), database.lastErrorMsg());
804 return false;
805 }
806
807 {
808 SQLiteStatement statement(database, "SELECT indexID, objectStoreID, key, value, objectStoreRecordID FROM IndexRecords;"_s);
809 if (statement.prepare() != SQLITE_OK) {
810 LOG_ERROR("Error preparing statement to fetch records from the IndexRecords table (%i) - %s", database.lastError(), database.lastErrorMsg());
811 return false;
812 }
813
814 int result = statement.step();
815 while (result == SQLITE_ROW) {
816 uint64_t id = statement.getColumnInt64(0);
817 uint64_t objectStoreID = statement.getColumnInt64(1);
818 uint64_t newID = indexIDMap.get({ objectStoreID, id });
819 Vector<uint8_t> keyBuffer;
820 statement.getColumnBlobAsVector(2, keyBuffer);
821 Vector<uint8_t> valueBuffer;
822 statement.getColumnBlobAsVector(3, valueBuffer);
823 uint64_t recordID = statement.getColumnInt64(4);
824
825 auto sql = cachedStatement(SQL::PutTempIndexRecord, "INSERT INTO _Temp_IndexRecords VALUES (?, ?, CAST(? AS TEXT), CAST(? AS TEXT), ?);"_s);
826 if (!sql
827 || sql->bindInt64(1, newID) != SQLITE_OK
828 || sql->bindInt64(2, objectStoreID) != SQLITE_OK
829 || sql->bindBlob(3, keyBuffer.data(), keyBuffer.size()) != SQLITE_OK
830 || sql->bindBlob(4, valueBuffer.data(), valueBuffer.size()) != SQLITE_OK
831 || sql->bindInt64(5, recordID) != SQLITE_OK
832 || sql->step() != SQLITE_DONE) {
833 LOG_ERROR("Error adding index record to _Temp_IndexRecords table (%i) - %s", database.lastError(), database.lastErrorMsg());
834 return false;
835 }
836
837 result = statement.step();
838 }
839
840 if (result != SQLITE_DONE) {
841 LOG_ERROR("Error fetching index record from database on disk (%i) - %s", database.lastError(), database.lastErrorMsg());
842 return false;
843 }
844 }
845
846 if (!database.executeCommand("DROP TABLE IndexRecords")) {
847 LOG_ERROR("Error dropping existing IndexRecords table (%i) - %s", database.lastError(), database.lastErrorMsg());
848 return false;
849 }
850
851 if (!database.executeCommand("ALTER TABLE _Temp_IndexRecords RENAME TO IndexRecords")) {
852 LOG_ERROR("Error renaming temporary IndexRecords table (%i) - %s", database.lastError(), database.lastErrorMsg());
853 return false;
854 }
855
856 transaction.commit();
857 return true;
858}
859
860bool SQLiteIDBBackingStore::removeExistingIndex(uint64_t indexID)
861{
862 SQLiteTransaction transaction(*m_sqliteDB);
863 transaction.begin();
864
865 {
866 auto sql = cachedStatement(SQL::RemoveIndexInfo, "DELETE FROM IndexInfo WHERE id = ?;"_s);
867 if (!sql
868 || sql->bindInt64(1, indexID) != SQLITE_OK
869 || sql->step() != SQLITE_DONE) {
870 LOG_ERROR("Unable to remove existing index from IndexInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
871 return false;
872 }
873 }
874
875 {
876 auto sql = cachedStatement(SQL::DeleteIndexRecords, "DELETE FROM IndexRecords WHERE indexID = ?;"_s);
877 if (!sql
878 || sql->bindInt64(1, indexID) != SQLITE_OK
879 || sql->step() != SQLITE_DONE) {
880 LOG_ERROR("Unable to remove existing index from IndexRecords table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
881 return false;
882 }
883 }
884
885 transaction.commit();
886 return true;
887}
888
889bool SQLiteIDBBackingStore::addExistingIndex(IDBObjectStoreInfo& objectStoreInfo, const IDBIndexInfo& info)
890{
891 SQLiteTransaction transaction(*m_sqliteDB);
892 transaction.begin();
893
894 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(info.keyPath());
895 if (!keyPathBlob) {
896 LOG_ERROR("Unable to serialize IDBKeyPath to save in database");
897 return false;
898 }
899
900 {
901 auto sql = cachedStatement(SQL::CreateIndexInfo, "INSERT INTO IndexInfo VALUES (?, ?, ?, ?, ?, ?);"_s);
902 if (!sql
903 || sql->bindInt64(1, info.identifier()) != SQLITE_OK
904 || sql->bindText(2, info.name()) != SQLITE_OK
905 || sql->bindInt64(3, info.objectStoreIdentifier()) != SQLITE_OK
906 || sql->bindBlob(4, keyPathBlob->data(), keyPathBlob->size()) != SQLITE_OK
907 || sql->bindInt(5, info.unique()) != SQLITE_OK
908 || sql->bindInt(6, info.multiEntry()) != SQLITE_OK
909 || sql->step() != SQLITE_DONE) {
910 LOG_ERROR("Could not add index '%s' to IndexInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
911 return false;
912 }
913 }
914
915 {
916 SQLiteStatement sql(*m_sqliteDB, "SELECT key, value, recordID FROM Records WHERE objectStoreID = ?;");
917 if (sql.prepare() != SQLITE_OK
918 || sql.bindInt64(1, info.objectStoreIdentifier()) != SQLITE_OK) {
919 LOG_ERROR("Unable to prepare statement or bind values (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
920 return false;
921 }
922
923 int result = sql.step();
924 while (result == SQLITE_ROW) {
925 Vector<uint8_t> keyBuffer;
926 IDBKeyData keyData;
927 sql.getColumnBlobAsVector(0, keyBuffer);
928 if (!deserializeIDBKeyData(keyBuffer.data(), keyBuffer.size(), keyData)) {
929 LOG_ERROR("Unable to deserialize key data from database while getting all records");
930 return false;
931 }
932
933 Vector<uint8_t> valueBuffer;
934 sql.getColumnBlobAsVector(1, valueBuffer);
935 auto value = ThreadSafeDataBuffer::create(WTFMove(valueBuffer));
936
937 uint64_t recordID = sql.getColumnInt64(2);
938 IDBError error = updateOneIndexForAddRecord(objectStoreInfo, info, keyData, value, recordID);
939 if (!error.isNull())
940 return false;
941
942 result = sql.step();
943 }
944
945 if (result != SQLITE_DONE) {
946 LOG_ERROR("Error fetching object records from Records table on disk");
947 return false;
948 }
949 }
950
951 transaction.commit();
952
953 return true;
954}
955
956bool SQLiteIDBBackingStore::handleDuplicateIndexIDs(const HashMap<uint64_t, Vector<IDBIndexInfo>>& indexInfoMap, IDBDatabaseInfo& databaseInfo)
957{
958 for (auto& [indexID, infos] : indexInfoMap) {
959 if (infos.size() == 1)
960 continue;
961
962 if (!removeExistingIndex(indexID))
963 return false;
964
965 for (auto info : infos) {
966 auto objectStoreInfo = databaseInfo.infoForExistingObjectStore(info.objectStoreIdentifier());
967 ASSERT(objectStoreInfo);
968 objectStoreInfo->deleteIndex(info.identifier());
969
970 // A new index with the same name may be added.
971 if (objectStoreInfo->hasIndex(info.name()))
972 continue;
973
974 info.setIdentifier(databaseInfo.generateNextIndexID());
975 if (!addExistingIndex(*objectStoreInfo, info))
976 return false;
977
978 objectStoreInfo->addExistingIndex(info);
979 }
980 }
981
982 return true;
983}
984