• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple 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 
26 #include "config.h"
27 #include "modules/webdatabase/sqlite/SQLiteStatement.h"
28 
29 #include <sqlite3.h>
30 #include "platform/Logging.h"
31 #include "modules/webdatabase/sqlite/SQLValue.h"
32 #include "wtf/Assertions.h"
33 #include "wtf/text/CString.h"
34 
35 // SQLite 3.6.16 makes sqlite3_prepare_v2 automatically retry preparing the statement
36 // once if the database scheme has changed. We rely on this behavior.
37 #if SQLITE_VERSION_NUMBER < 3006016
38 #error SQLite version 3.6.16 or newer is required
39 #endif
40 
41 namespace WebCore {
42 
SQLiteStatement(SQLiteDatabase & db,const String & sql)43 SQLiteStatement::SQLiteStatement(SQLiteDatabase& db, const String& sql)
44     : m_database(db)
45     , m_query(sql)
46     , m_statement(0)
47 #ifndef NDEBUG
48     , m_isPrepared(false)
49 #endif
50 {
51 }
52 
~SQLiteStatement()53 SQLiteStatement::~SQLiteStatement()
54 {
55     finalize();
56 }
57 
prepare()58 int SQLiteStatement::prepare()
59 {
60     ASSERT(!m_isPrepared);
61 
62     CString query = m_query.stripWhiteSpace().utf8();
63 
64     ThreadState::SafePointScope scope(ThreadState::HeapPointersOnStack);
65     MutexLocker databaseLock(m_database.databaseMutex());
66     if (m_database.isInterrupted())
67         return SQLITE_INTERRUPT;
68 
69     WTF_LOG(SQLDatabase, "SQL - prepare - %s", query.data());
70 
71     // Pass the length of the string including the null character to sqlite3_prepare_v2;
72     // this lets SQLite avoid an extra string copy.
73     size_t lengthIncludingNullCharacter = query.length() + 1;
74 
75     const char* tail = 0;
76     int error = sqlite3_prepare_v2(m_database.sqlite3Handle(), query.data(), lengthIncludingNullCharacter, &m_statement, &tail);
77 
78     if (error != SQLITE_OK)
79         WTF_LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", error, query.data(), sqlite3_errmsg(m_database.sqlite3Handle()));
80     else if (tail && *tail)
81         error = SQLITE_ERROR;
82 
83 #ifndef NDEBUG
84     m_isPrepared = error == SQLITE_OK;
85 #endif
86     return error;
87 }
88 
step()89 int SQLiteStatement::step()
90 {
91     ThreadState::SafePointScope scope(ThreadState::HeapPointersOnStack);
92     MutexLocker databaseLock(m_database.databaseMutex());
93     if (m_database.isInterrupted())
94         return SQLITE_INTERRUPT;
95     //ASSERT(m_isPrepared);
96 
97     if (!m_statement)
98         return SQLITE_OK;
99 
100     // The database needs to update its last changes count before each statement
101     // in order to compute properly the lastChanges() return value.
102     m_database.updateLastChangesCount();
103 
104     WTF_LOG(SQLDatabase, "SQL - step - %s", m_query.ascii().data());
105     int error = sqlite3_step(m_statement);
106     if (error != SQLITE_DONE && error != SQLITE_ROW) {
107         WTF_LOG(SQLDatabase, "sqlite3_step failed (%i)\nQuery - %s\nError - %s",
108             error, m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
109     }
110 
111     return error;
112 }
113 
finalize()114 int SQLiteStatement::finalize()
115 {
116 #ifndef NDEBUG
117     m_isPrepared = false;
118 #endif
119     if (!m_statement)
120         return SQLITE_OK;
121     WTF_LOG(SQLDatabase, "SQL - finalize - %s", m_query.ascii().data());
122     int result = sqlite3_finalize(m_statement);
123     m_statement = 0;
124     return result;
125 }
126 
executeCommand()127 bool SQLiteStatement::executeCommand()
128 {
129     if (!m_statement && prepare() != SQLITE_OK)
130         return false;
131     ASSERT(m_isPrepared);
132     if (step() != SQLITE_DONE) {
133         finalize();
134         return false;
135     }
136     finalize();
137     return true;
138 }
139 
bindText(int index,const String & text)140 int SQLiteStatement::bindText(int index, const String& text)
141 {
142     ASSERT(m_isPrepared);
143     ASSERT(index > 0);
144     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
145 
146     // SQLite treats uses zero pointers to represent null strings, which means we need to make sure to map null WTFStrings to zero pointers.
147     ASSERT(!String().charactersWithNullTermination().data());
148     return sqlite3_bind_text16(m_statement, index, text.charactersWithNullTermination().data(), sizeof(UChar) * text.length(), SQLITE_TRANSIENT);
149 }
150 
bindDouble(int index,double number)151 int SQLiteStatement::bindDouble(int index, double number)
152 {
153     ASSERT(m_isPrepared);
154     ASSERT(index > 0);
155     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
156 
157     return sqlite3_bind_double(m_statement, index, number);
158 }
159 
bindNull(int index)160 int SQLiteStatement::bindNull(int index)
161 {
162     ASSERT(m_isPrepared);
163     ASSERT(index > 0);
164     ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
165 
166     return sqlite3_bind_null(m_statement, index);
167 }
168 
bindValue(int index,const SQLValue & value)169 int SQLiteStatement::bindValue(int index, const SQLValue& value)
170 {
171     switch (value.type()) {
172         case SQLValue::StringValue:
173             return bindText(index, value.string());
174         case SQLValue::NumberValue:
175             return bindDouble(index, value.number());
176         case SQLValue::NullValue:
177             return bindNull(index);
178     }
179 
180     ASSERT_NOT_REACHED();
181     return SQLITE_ERROR;
182 }
183 
bindParameterCount() const184 unsigned SQLiteStatement::bindParameterCount() const
185 {
186     ASSERT(m_isPrepared);
187     if (!m_statement)
188         return 0;
189     return sqlite3_bind_parameter_count(m_statement);
190 }
191 
columnCount()192 int SQLiteStatement::columnCount()
193 {
194     ASSERT(m_isPrepared);
195     if (!m_statement)
196         return 0;
197     return sqlite3_data_count(m_statement);
198 }
199 
getColumnName(int col)200 String SQLiteStatement::getColumnName(int col)
201 {
202     ASSERT(col >= 0);
203     if (!m_statement)
204         if (prepareAndStep() != SQLITE_ROW)
205             return String();
206     if (columnCount() <= col)
207         return String();
208     return String(reinterpret_cast<const UChar*>(sqlite3_column_name16(m_statement, col)));
209 }
210 
getColumnValue(int col)211 SQLValue SQLiteStatement::getColumnValue(int col)
212 {
213     ASSERT(col >= 0);
214     if (!m_statement)
215         if (prepareAndStep() != SQLITE_ROW)
216             return SQLValue();
217     if (columnCount() <= col)
218         return SQLValue();
219 
220     // SQLite is typed per value. optional column types are
221     // "(mostly) ignored"
222     sqlite3_value* value = sqlite3_column_value(m_statement, col);
223     switch (sqlite3_value_type(value)) {
224         case SQLITE_INTEGER:    // SQLValue and JS don't represent integers, so use FLOAT -case
225         case SQLITE_FLOAT:
226             return SQLValue(sqlite3_value_double(value));
227         case SQLITE_BLOB:       // SQLValue and JS don't represent blobs, so use TEXT -case
228         case SQLITE_TEXT: {
229             const UChar* string = reinterpret_cast<const UChar*>(sqlite3_value_text16(value));
230             unsigned length = WTF::lengthOfNullTerminatedString(string);
231             return SQLValue(StringImpl::create8BitIfPossible(string, length));
232         }
233         case SQLITE_NULL:
234             return SQLValue();
235         default:
236             break;
237     }
238     ASSERT_NOT_REACHED();
239     return SQLValue();
240 }
241 
getColumnText(int col)242 String SQLiteStatement::getColumnText(int col)
243 {
244     ASSERT(col >= 0);
245     if (!m_statement)
246         if (prepareAndStep() != SQLITE_ROW)
247             return String();
248     if (columnCount() <= col)
249         return String();
250     const UChar* string = reinterpret_cast<const UChar*>(sqlite3_column_text16(m_statement, col));
251     return StringImpl::create8BitIfPossible(string, sqlite3_column_bytes16(m_statement, col) / sizeof(UChar));
252 }
253 
getColumnInt(int col)254 int SQLiteStatement::getColumnInt(int col)
255 {
256     ASSERT(col >= 0);
257     if (!m_statement)
258         if (prepareAndStep() != SQLITE_ROW)
259             return 0;
260     if (columnCount() <= col)
261         return 0;
262     return sqlite3_column_int(m_statement, col);
263 }
264 
getColumnInt64(int col)265 int64_t SQLiteStatement::getColumnInt64(int col)
266 {
267     ASSERT(col >= 0);
268     if (!m_statement)
269         if (prepareAndStep() != SQLITE_ROW)
270             return 0;
271     if (columnCount() <= col)
272         return 0;
273     return sqlite3_column_int64(m_statement, col);
274 }
275 
276 } // namespace WebCore
277