|
1 /* |
|
2 * Copyright (C) 2010 Google 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 are |
|
6 * met: |
|
7 * |
|
8 * * Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * * Redistributions in binary form must reproduce the above |
|
11 * copyright notice, this list of conditions and the following disclaimer |
|
12 * in the documentation and/or other materials provided with the |
|
13 * distribution. |
|
14 * * Neither the name of Google Inc. nor the names of its |
|
15 * contributors may be used to endorse or promote products derived from |
|
16 * this software without specific prior written permission. |
|
17 * |
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 */ |
|
30 |
|
31 #include "config.h" |
|
32 #include "SQLTransactionSync.h" |
|
33 |
|
34 #if ENABLE(DATABASE) |
|
35 |
|
36 #include "DatabaseSync.h" |
|
37 #include "PlatformString.h" |
|
38 #include "SQLException.h" |
|
39 #include "SQLResultSet.h" |
|
40 #include "SQLStatementSync.h" |
|
41 #include "SQLTransactionClient.h" |
|
42 #include "SQLTransactionSyncCallback.h" |
|
43 #include "SQLValue.h" |
|
44 #include "SQLiteTransaction.h" |
|
45 #include "ScriptExecutionContext.h" |
|
46 #include <wtf/PassRefPtr.h> |
|
47 #include <wtf/RefPtr.h> |
|
48 |
|
49 namespace WebCore { |
|
50 |
|
51 PassRefPtr<SQLTransactionSync> SQLTransactionSync::create(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly) |
|
52 { |
|
53 return adoptRef(new SQLTransactionSync(db, callback, readOnly)); |
|
54 } |
|
55 |
|
56 SQLTransactionSync::SQLTransactionSync(DatabaseSync* db, PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly) |
|
57 : m_database(db) |
|
58 , m_callback(callback) |
|
59 , m_readOnly(readOnly) |
|
60 , m_modifiedDatabase(false) |
|
61 , m_transactionClient(new SQLTransactionClient()) |
|
62 { |
|
63 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
64 } |
|
65 |
|
66 SQLTransactionSync::~SQLTransactionSync() |
|
67 { |
|
68 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
69 if (m_sqliteTransaction && m_sqliteTransaction->inProgress()) |
|
70 rollback(); |
|
71 } |
|
72 |
|
73 PassRefPtr<SQLResultSet> SQLTransactionSync::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, ExceptionCode& ec) |
|
74 { |
|
75 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
76 if (!m_database->opened()) { |
|
77 ec = SQLException::UNKNOWN_ERR; |
|
78 return 0; |
|
79 } |
|
80 |
|
81 if (!m_database->versionMatchesExpected()) { |
|
82 ec = SQLException::VERSION_ERR; |
|
83 return 0; |
|
84 } |
|
85 |
|
86 if (sqlStatement.isEmpty()) |
|
87 return 0; |
|
88 |
|
89 bool readOnlyMode = m_readOnly || m_database->scriptExecutionContext()->isDatabaseReadOnly(); |
|
90 SQLStatementSync statement(sqlStatement, arguments, readOnlyMode); |
|
91 |
|
92 m_database->resetAuthorizer(); |
|
93 bool retryStatement = true; |
|
94 RefPtr<SQLResultSet> resultSet; |
|
95 while (retryStatement) { |
|
96 retryStatement = false; |
|
97 resultSet = statement.execute(m_database.get(), ec); |
|
98 if (!resultSet) { |
|
99 if (m_sqliteTransaction->wasRolledBackBySqlite()) |
|
100 return 0; |
|
101 |
|
102 if (ec == SQLException::QUOTA_ERR) { |
|
103 if (m_transactionClient->didExceedQuota(database())) { |
|
104 ec = 0; |
|
105 retryStatement = true; |
|
106 } else |
|
107 return 0; |
|
108 } |
|
109 } |
|
110 } |
|
111 |
|
112 if (m_database->lastActionChangedDatabase()) { |
|
113 m_modifiedDatabase = true; |
|
114 m_transactionClient->didExecuteStatement(database()); |
|
115 } |
|
116 |
|
117 return resultSet.release(); |
|
118 } |
|
119 |
|
120 ExceptionCode SQLTransactionSync::begin() |
|
121 { |
|
122 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
123 if (!m_database->opened()) |
|
124 return SQLException::UNKNOWN_ERR; |
|
125 |
|
126 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); |
|
127 |
|
128 // Set the maximum usage for this transaction if this transactions is not read-only. |
|
129 if (!m_readOnly) |
|
130 m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); |
|
131 |
|
132 ASSERT(!m_sqliteTransaction); |
|
133 m_sqliteTransaction.set(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); |
|
134 |
|
135 m_database->resetDeletes(); |
|
136 m_database->disableAuthorizer(); |
|
137 m_sqliteTransaction->begin(); |
|
138 m_database->enableAuthorizer(); |
|
139 |
|
140 // Check if begin() succeeded. |
|
141 if (!m_sqliteTransaction->inProgress()) { |
|
142 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); |
|
143 m_sqliteTransaction.clear(); |
|
144 return SQLException::DATABASE_ERR; |
|
145 } |
|
146 |
|
147 return 0; |
|
148 } |
|
149 |
|
150 ExceptionCode SQLTransactionSync::execute() |
|
151 { |
|
152 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
153 if (!m_database->opened() || !m_callback || !m_callback->handleEvent(m_database->scriptExecutionContext(), this)) { |
|
154 m_callback = 0; |
|
155 return SQLException::UNKNOWN_ERR; |
|
156 } |
|
157 |
|
158 m_callback = 0; |
|
159 return 0; |
|
160 } |
|
161 |
|
162 ExceptionCode SQLTransactionSync::commit() |
|
163 { |
|
164 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
165 if (!m_database->opened()) |
|
166 return SQLException::UNKNOWN_ERR; |
|
167 |
|
168 ASSERT(m_sqliteTransaction); |
|
169 |
|
170 m_database->disableAuthorizer(); |
|
171 m_sqliteTransaction->commit(); |
|
172 m_database->enableAuthorizer(); |
|
173 |
|
174 // If the commit failed, the transaction will still be marked as "in progress" |
|
175 if (m_sqliteTransaction->inProgress()) |
|
176 return SQLException::DATABASE_ERR; |
|
177 |
|
178 m_sqliteTransaction.clear(); |
|
179 |
|
180 // Vacuum the database if anything was deleted. |
|
181 if (m_database->hadDeletes()) |
|
182 m_database->incrementalVacuumIfNeeded(); |
|
183 |
|
184 // The commit was successful. If the transaction modified this database, notify the delegates. |
|
185 if (m_modifiedDatabase) |
|
186 m_transactionClient->didCommitWriteTransaction(database()); |
|
187 |
|
188 return 0; |
|
189 } |
|
190 |
|
191 void SQLTransactionSync::rollback() |
|
192 { |
|
193 ASSERT(m_database->scriptExecutionContext()->isContextThread()); |
|
194 m_database->disableAuthorizer(); |
|
195 if (m_sqliteTransaction) { |
|
196 m_sqliteTransaction->rollback(); |
|
197 m_sqliteTransaction.clear(); |
|
198 } |
|
199 m_database->enableAuthorizer(); |
|
200 |
|
201 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); |
|
202 } |
|
203 |
|
204 } // namespace WebCore |
|
205 |
|
206 #endif // ENABLE(DATABASE) |