Reviewed by Levi and Tim Omernick.
[WebKit-https.git] / WebCore / icon / IconDatabase.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 #include "IconDatabase.h"
26
27 #include "DeprecatedString.h"
28 #include "Logging.h"
29 #include "PlatformString.h"
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34
35 const char* DefaultIconDatabaseFilename = "/icon.db";
36
37 namespace WebCore {
38
39 IconDatabase* IconDatabase::m_sharedInstance = 0;
40 const int IconDatabase::currentDatabaseVersion = 3;
41
42 IconDatabase* IconDatabase::sharedIconDatabase()
43 {
44     if (!m_sharedInstance) {
45         m_sharedInstance = new IconDatabase();
46     }
47     return m_sharedInstance;
48 }
49
50 IconDatabase::IconDatabase()
51 {
52
53 }
54
55 bool IconDatabase::open(const String& databasePath)
56 {
57     close();
58     String dbFilename = databasePath + DefaultIconDatabaseFilename;
59     if (!m_db.open(dbFilename)) {
60         LOG(IconDatabase, "Unable to open icon database at path %s", dbFilename.deprecatedString().ascii());
61         return false;
62     }
63     
64     if (!isValidDatabase()) {
65         LOG(IconDatabase, "%s is in an invalid state - reconstructing", dbFilename.deprecatedString().ascii());
66         clearDatabase();
67         recreateDatabase();
68     }
69     
70     return isOpen();
71 }
72
73 void IconDatabase::close()
74 {
75     //TODO - sync any cached info before close();
76     m_db.close();
77 }
78
79
80 bool IconDatabase::isValidDatabase()
81 {
82     if (!m_db.tableExists("IconDatabaseInfo")) {
83         return false;
84     }
85     
86     String query = "SELECT value FROM IconDatabaseInfo WHERE key = 'Version';";
87     SQLStatement sql(m_db, query);
88     sql.prepare();
89     sql.step();
90     if (sql.getColumnInt(0) < currentDatabaseVersion) {
91         LOG(IconDatabase, "DB version is not found or below expected valid version");
92         return false;
93     }
94     
95     if (!m_db.tableExists("Icon") || !m_db.tableExists("PageURL") || !m_db.tableExists("IconResource")) {
96         return false;
97     }
98     return true;
99 }
100
101 void IconDatabase::clearDatabase()
102 {
103     String query = "SELECT name FROM sqlite_master WHERE type='table';";
104     Vector<String> tables;
105     if (!SQLStatement(m_db, query).returnTextResults16(0, tables)) {
106         LOG(IconDatabase, "Unable to retrieve list of tables from database");
107         return;
108     }
109     
110     for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) {
111         if (!m_db.executeCommand("DROP TABLE " + *table)) {
112             LOG(IconDatabase, "Unable to drop table %s", (*table).deprecatedString().ascii());
113         }
114     }
115 }
116
117 void IconDatabase::recreateDatabase()
118 {
119     if (!m_db.executeCommand("CREATE TABLE IconDatabaseInfo (key varchar NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value integer NOT NULL ON CONFLICT FAIL);")) {
120         LOG_ERROR("Could not create IconDatabaseInfo table in icon.db (%i)\n%s", m_db.lastError(), m_db.lastErrorMsg());
121         m_db.close();
122         return;
123     }
124     if (!m_db.executeCommand(String("INSERT INTO IconDatabaseInfo VALUES ('Version', ") + String::number(currentDatabaseVersion) + ");")) {
125         LOG_ERROR("Could not insert icon database version into IconDatabaseInfo table (%i)\n%s", m_db.lastError(), m_db.lastErrorMsg());
126         m_db.close();
127         return;
128     }
129     if (!m_db.executeCommand("CREATE TABLE PageURL (url varchar NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,iconID integer NOT NULL ON CONFLICT FAIL);")) {
130         LOG_ERROR("Could not create PageURL table in icon.db (%i)\n%s", m_db.lastError(), m_db.lastErrorMsg());
131         m_db.close();
132         return;
133     }
134     if (!m_db.executeCommand("CREATE TABLE Icon (id integer PRIMARY KEY ON CONFLICT FAIL,url varchar NOT NULL UNIQUE ON CONFLICT FAIL);")) {
135         LOG_ERROR("Could not create Icon table in icon.db (%i)\n%s", m_db.lastError(), m_db.lastErrorMsg());
136         m_db.close();
137         return;
138     }
139     if (!m_db.executeCommand("CREATE TABLE IconResource (iconID integer NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,data blob NOT NULL ON CONFLICT FAIL);")) {
140         LOG_ERROR("Could not create IconResource table in icon.db (%i)\n%s", m_db.lastError(), m_db.lastErrorMsg());
141         m_db.close();
142         return;
143     }
144     
145     
146 }    
147
148 IconDatabase::~IconDatabase()
149 {
150     m_db.close();
151 }
152
153 } //namespace WebCore
154