1/* 2 * Copyright (C) 2012 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20 21#include "AutofillBackingStore.h" 22 23#include "FileSystem.h" 24#include "SQLiteStatement.h" 25#include <BlackBerryPlatformSettings.h> 26 27#define HANDLE_SQL_EXEC_FAILURE(statement, returnValue, ...) \ 28 if (statement) { \ 29 LOG_ERROR(__VA_ARGS__); \ 30 return returnValue; \ 31 } 32 33namespace WebCore { 34 35AutofillBackingStore& autofillBackingStore() 36{ 37 DEFINE_STATIC_LOCAL(AutofillBackingStore, backingStore, ()); 38 if (!backingStore.m_database.isOpen()) 39 backingStore.open(pathByAppendingComponent(BlackBerry::Platform::Settings::instance()->applicationDataDirectory().c_str(), "/autofill.db")); 40 return backingStore; 41} 42 43AutofillBackingStore::AutofillBackingStore() 44 : m_addStatement(0) 45 , m_updateStatement(0) 46 , m_containsStatement(0) 47 , m_getStatement(0) 48{ 49} 50 51AutofillBackingStore::~AutofillBackingStore() 52{ 53 delete m_addStatement; 54 m_addStatement = 0; 55 delete m_updateStatement; 56 m_updateStatement = 0; 57 delete m_containsStatement; 58 m_containsStatement = 0; 59 delete m_getStatement; 60 m_getStatement = 0; 61 62 if (m_database.isOpen()) 63 m_database.close(); 64} 65 66bool AutofillBackingStore::open(const String& dbPath) 67{ 68 ASSERT(!m_database.isOpen()); 69 70 HANDLE_SQL_EXEC_FAILURE(!m_database.open(dbPath), false, 71 "Failed to open database file %s for autofill database", dbPath.utf8().data()); 72 73 if (!m_database.tableExists("autofill")) { 74 HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE TABLE autofill (id INTEGER PRIMARY KEY, name VARCHAR NOT NULL, value VARCHAR NOT NULL, count INTEGER DEFAULT 1)"), 75 false, "Failed to create table autofill for autofill database"); 76 77 // Create index for table autofill. 78 HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE INDEX autofill_name ON autofill (name)"), 79 false, "Failed to create autofill_name index for table autofill"); 80 } 81 82 // Prepare the statements. 83 m_addStatement = new SQLiteStatement(m_database, "INSERT INTO autofill (name, value) VALUES (?, ?)"); 84 HANDLE_SQL_EXEC_FAILURE(m_addStatement->prepare() != SQLResultOk, 85 false, "Failed to prepare add statement"); 86 87 m_updateStatement = new SQLiteStatement(m_database, "UPDATE autofill SET count = (SELECT count + 1 from autofill WHERE name = ? AND value = ?) WHERE name = ? AND value = ?"); 88 HANDLE_SQL_EXEC_FAILURE(m_updateStatement->prepare() != SQLResultOk, 89 false, "Failed to prepare update statement"); 90 91 m_containsStatement = new SQLiteStatement(m_database, "SELECT COUNT(*) FROM autofill WHERE name = ? AND value = ?"); 92 HANDLE_SQL_EXEC_FAILURE(m_containsStatement->prepare() != SQLResultOk, 93 false, "Failed to prepare contains statement"); 94 95 m_getStatement = new SQLiteStatement(m_database, "SELECT value FROM autofill WHERE name = ? and value like ? ORDER BY count DESC"); 96 HANDLE_SQL_EXEC_FAILURE(m_getStatement->prepare() != SQLResultOk, 97 false, "Failed to prepare get statement"); 98 99 return true; 100} 101 102bool AutofillBackingStore::add(const String& name, const String& value) 103{ 104 if (name.isEmpty() || value.isEmpty()) 105 return false; 106 107 ASSERT(m_database.isOpen()); 108 ASSERT(m_database.tableExists("autofill")); 109 110 if (contains(name, value)) 111 return update(name, value); 112 113 if (!m_addStatement) 114 return false; 115 116 m_addStatement->bindText(1, name); 117 m_addStatement->bindText(2, value); 118 119 int result = m_addStatement->step(); 120 m_addStatement->reset(); 121 HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false, 122 "Failed to add autofill item into table autofill - %i", result); 123 124 return true; 125} 126 127bool AutofillBackingStore::update(const String& name, const String& value) 128{ 129 if (!m_updateStatement) 130 return false; 131 132 m_updateStatement->bindText(1, name); 133 m_updateStatement->bindText(2, value); 134 m_updateStatement->bindText(3, name); 135 m_updateStatement->bindText(4, value); 136 137 int result = m_updateStatement->step(); 138 m_updateStatement->reset(); 139 HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false, 140 "Failed to update autofill item in table autofill - %i", result); 141 142 return true; 143} 144 145bool AutofillBackingStore::contains(const String& name, const String& value) const 146{ 147 if (!m_containsStatement) 148 return false; 149 150 m_containsStatement->bindText(1, name); 151 m_containsStatement->bindText(2, value); 152 153 int result = m_containsStatement->step(); 154 int numberOfRows = m_containsStatement->getColumnInt(0); 155 m_containsStatement->reset(); 156 HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, false, 157 "Failed to execute select autofill item from table autofill in contains - %i", result); 158 159 return numberOfRows; 160} 161 162Vector<String> AutofillBackingStore::get(const String& name, const String& valueHint) 163{ 164 ASSERT(m_database.isOpen()); 165 ASSERT(m_database.tableExists("autofill")); 166 167 Vector<String> candidates; 168 if (name.isEmpty() || valueHint.isEmpty() || !m_getStatement) 169 return candidates; 170 171 String value = valueHint + "%"; 172 m_getStatement->bindText(1, name); 173 m_getStatement->bindText(2, value); 174 175 int result; 176 while ((result = m_getStatement->step()) == SQLResultRow) 177 candidates.append(m_getStatement->getColumnText(0)); 178 m_getStatement->reset(); 179 HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, candidates, 180 "Failed to execute select autofill item from table autofill in get - %i", result); 181 182 return candidates; 183} 184 185bool AutofillBackingStore::clear() 186{ 187 ASSERT(m_database.isOpen()); 188 ASSERT(m_database.tableExists("autofill")); 189 190 HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("DELETE FROM autofill"), 191 false, "Failed to clear table autofill"); 192 193 return true; 194} 195 196} // namespace WebCore 197