Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(10)

Delta Between Two Patch Sets: gears/database2/connection.cc

Issue 717: Database2Values, argument conversion implemented (Closed) SVN Base: http://google-gears.googlecode.com/svn/contrib/dimitri.glazkov/database2/
Left Patch Set: Removed post-increment Created 3 months ago
Right Patch Set: Variant, multiple-row capability added Created 3 months, 2 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 // Copyright 2008, Google Inc. 1 // Copyright 2008, Google Inc.
2 // 2 //
3 // Redistribution and use in source and binary forms, with or without 3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met: 4 // modification, are permitted provided that the following conditions are met:
5 // 5 //
6 // 1. Redistributions of source code must retain the above copyright notice, 6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer. 7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice, 8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation 9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution. 10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be 11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without 12 // used to endorse or promote products derived from this software without
13 // specific prior written permission. 13 // specific prior written permission.
14 // 14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 25
26 #include "gears/base/common/sqlite_wrapper.h"
27 #include "gears/base/common/string16.h"
28 #include "gears/database2/common.h"
29 #include "gears/database2/connection.h" 26 #include "gears/database2/connection.h"
30 #include "gears/database2/statement.h" 27 #include "gears/database2/statement.h"
31 28
32 // TODO(dimitri.glazkov): implement actual database operations. For now, all 29 // TODO(dimitri.glazkov): implement actual database operations. For now, all
33 // operations pretend to succeed to facilitate in-progress testing 30 // operations pretend to succeed to facilitate in-progress testing
31
34 bool Database2Connection::OpenAndVerifyVersion( 32 bool Database2Connection::OpenAndVerifyVersion(
35 const std::string16 &database_version) { 33 const std::string16 &database_version) {
36 // a quaint rendition of opening the database
37 // only here for testing needs
38 // TODO(dimitri.glazkov): Replace with the proper method implementation
39 int rc = sqlite3_open16(STRING16(L"stubbey.sqlite"), &handle_);
40 if (rc != SQLITE_OK) {
41 return false;
42 }
43 // open database if not already open 34 // open database if not already open
44 // read expected_version (user_version value) 35 // read expected_version (user_version value)
45 // read version from Permissions.db 36 // read version from Permissions.db
46 // if database_version is not an empty value or null, 37 // if database_version is not an empty value or null,
47 if (!database_version.empty()) { 38 if (!database_version.empty()) {
48 // if database_version matches version 39 // if database_version matches version
49 // return true 40 // return true
50 // otherwise, 41 // otherwise,
51 return false; 42 return false;
52 // return true 43 // return true
53 } 44 }
54 return true; 45 return true;
55 } 46 }
56 47
57 bool Database2Connection::Execute(const std::string16 &statement, 48 bool Database2Connection::Execute(const std::string16 &statement,
58 int num_arguments, 49 Database2Values *arguments,
59 Database2Variant *arguments,
60 Database2RowHandlerInterface *row_handler) { 50 Database2RowHandlerInterface *row_handler) {
61 int sqlite_status; 51 // if (bogus_version_) {
62 // This method should not be invoked until database is opened. 52 // set error code to "version mismatch" (error code 2)
63 assert(handle_); 53 // }
64 assert(row_handler); 54 // prepare
65 55 // step, for each row, call row_handler->HandleRow(..);
66 if (bogus_version_) { 56 // if error, set error code and message, return false;
67 SetAndHandleError(kDatabaseVersionMismatch, kInvalidStateError, SQLITE_OK); 57 // return true upon success
68 return false;
69 }
70
71 // prepare statement
72 scoped_sqlite3_stmt_ptr stmt;
73 sqlite_status = sqlite3_prepare16_v2(handle_, statement.c_str(), -1, &stmt,
74 NULL);
75 if (sqlite_status != SQLITE_OK) {
76 SetAndHandleError(kOtherDatabaseError, kPrepareError, sqlite_status);
77 return false;
78 }
79
80 if (stmt.get() == NULL) {
81 error_message_ = GET_INTERNAL_ERROR_MESSAGE();
82 return false;
83 }
84
85 // bind arguments
86 for(int i = 0; i < num_arguments; ++i) {
87 int sql_index = i + 1; // sql parameters are 1-based
88 switch(arguments[i].type) {
89 case JSPARAM_INT: {
90 sqlite_status = sqlite3_bind_int(stmt.get(), sql_index,
91 arguments[i].int_value);
92 break;
93 }
94 case JSPARAM_DOUBLE: {
95 sqlite_status = sqlite3_bind_double(stmt.get(), sql_index,
96 arguments[i].double_value);
97 break;
98 }
99 case JSPARAM_STRING16: {
100 sqlite_status = sqlite3_bind_text16(
101 stmt.get(), sql_index,
102 arguments[i].string_value->c_str(), -1,
103 SQLITE_STATIC);
104 break;
105 }
106 case JSPARAM_NULL: {
107 sqlite_status = sqlite3_bind_null(stmt.get(), sql_index);
108 break;
109 }
110 default: {
111 // This should never occur, because Database2Variant only handles the
112 // four types above by design.
113 assert(false);
114 return false;
115 }
116 }
117 if (sqlite_status != SQLITE_OK) {
118 SetAndHandleError(kOtherDatabaseError, kBindError, sqlite_status);
119 return false;
120 }
121 }
122
123 // get number of columns
124 int column_count = sqlite3_column_count(stmt.get());
125 scoped_array<std::string16> column_names(new std::string16[column_count]);
126
127 // read column names
128 for(int i = 0; i < column_count; ++i) {
129 const void *column_name = sqlite3_column_name16(stmt.get(), i);
130 column_names[i] = std::string16(static_cast<const char16 *>(column_name));
131 }
132
133 // row_handler takes ownership of the column names
134 row_handler->Init(column_count, column_names.release());
135
136 // read values
137 while(true) {
138 sqlite_status = sqlite3_step(stmt.get());
139 if (sqlite_status == SQLITE_DONE) {
140 break;
141 }
142 if (sqlite_status != SQLITE_ROW) {
143 // an error has occured
144 SetAndHandleError(kOtherDatabaseError, kStepError, sqlite_status);
145 return false;
146 }
147 row_handler->HandleNewRow();
148 for (int i = 0; i < column_count; ++i) {
149 switch(sqlite3_column_type(stmt.get(), i)) {
150 case SQLITE_INTEGER: {
151 row_handler->HandleColumnInt(i, sqlite3_column_int(stmt.get(), i));
152 break;
153 }
154 case SQLITE_FLOAT: {
155 row_handler->HandleColumnDouble(i,
156 sqlite3_column_double(stmt.get(), i));
157 break;
158 }
159 case SQLITE_TEXT: {
160 std::string16 value(
161 static_cast<const char16*>(sqlite3_column_text16(stmt.get(), i)));
162 row_handler->HandleColumnString(i, value);
163 break;
164 }
165 case SQLITE_NULL: {
166 row_handler->HandleColumnNull(i);
167 break;
168 }
169 default: {
170 // the only remaining SQLite type would be SQLITE_BLOB, which is not
171 // supported
172 SetAndHandleError(kOtherDatabaseError, kResultSetError, SQLITE_OK);
173 return false;
174 }
175 }
176 }
177 }
178
179 // read last inserted rowid
180 sqlite_int64 rowid = sqlite3_last_insert_rowid(handle_);
181 if ((rowid < JS_INT_MIN) || (rowid > JS_INT_MAX)) {
182 SetAndHandleError(kOtherDatabaseError,
183 kLastRowIdOutOfRangeError, SQLITE_OK);
184 return false;
185 }
186
187 int rows_affected = sqlite3_changes(handle_);
188
189 row_handler->HandleStats(static_cast<int64>(rowid), rows_affected);
190 return true; 58 return true;
191 }
192
193 void Database2Connection::SetAndHandleError(int error_code,
194 const char16 *summary,
195 int sqlite_status) {
196 // TODO(dimitri.glazkov): add poisoning in case of corruption
197 error_code_ = error_code;
198 if (sqlite_status == SQLITE_OK) {
199 // not a SQLite error
200 error_message_ = summary;
201 return;
202 }
203 BuildSqliteErrorString(summary, sqlite_status, handle_, &error_message_);
204 } 59 }
205 60
206 bool Database2Connection::Begin() { 61 bool Database2Connection::Begin() {
207 // execute BEGIN 62 // execute BEGIN
208 // if error, set error code and message, return false 63 // if error, set error code and message, return false
209 // read actual_version, if doesn't match expected_version_, 64 // read actual_version, if doesn't match expected_version_,
210 // set bogus_version_ flag 65 // set bogus_version_ flag
211 // return true upon success 66 // return true upon success
212 return true; 67 return true;
213 } 68 }
214 69
215 void Database2Connection::Rollback() { 70 void Database2Connection::Rollback() {
216 // execute ROLLBACK 71 // execute ROLLBACK
217 // don't remember or handle errors 72 // don't remember or handle errors
218 } 73 }
219 74
220 bool Database2Connection::Commit() { 75 bool Database2Connection::Commit() {
221 // execute COMMIT 76 // execute COMMIT
222 // if error, set error code and message, return false 77 // if error, set error code and message, return false
223 // return true upon success 78 // return true upon success
224 return true; 79 return true;
225 } 80 }
226
227
228 void Database2BufferingRowHandler::Init(int column_count,
229 std::string16 *column_names) {
230 assert(column_count >= 0);
231 // at this time, we only support invoking this method on a new instance
232 assert(column_count_ == 0 && rows_.size() == 0);
233 column_count_ = column_count;
234 column_names_.reset(column_names);
235 }
236
237 void Database2BufferingRowHandler::HandleNewRow() {
238 rows_.push_back(new Database2Variant[column_count_]);
239 }
240
241 bool Database2BufferingRowHandler::HandleColumnInt(int index, int value) {
242 assert(index >=0 && index < column_count_);
243 assert(rows_.size() > 0);
244 Database2Variant *row = rows_.back();
245 row[index].type = JSPARAM_INT;
246 row[index].int_value = value;
247 return true;
248 }
249
250 bool Database2BufferingRowHandler::HandleColumnDouble(int index, double value) {
251 assert(index >=0 && index < column_count_);
252 assert(rows_.size() > 0);
253 Database2Variant *row = rows_.back();
254 row[index].type = JSPARAM_DOUBLE;
255 row[index].double_value = value;
256 return true;
257 }
258
259 bool Database2BufferingRowHandler::HandleColumnString(
260 int index,
261 const std::string16 &value) {
262 assert(index >=0 && index < column_count_);
263 assert(rows_.size() > 0);
264 Database2Variant *row = rows_.back();
265 row[index].type = JSPARAM_STRING16;
266 row[index].string_value = new std::string16(value);
267 return true;
268 }
269
270 bool Database2BufferingRowHandler::HandleColumnNull(int index) {
271 assert(index >=0 && index < column_count_);
272 assert(rows_.size() > 0);
273 Database2Variant *row = rows_.back();
274 row[index].type = JSPARAM_NULL;
275 return true;
276 }
277
278 void Database2BufferingRowHandler::HandleStats(int64 last_insert_rowid,
279 int rows_affected) {
280 last_insert_rowid_ = last_insert_rowid;
281 rows_affected_ = rows_affected;
282 }
283
284 bool Database2BufferingRowHandler::CopyTo(
285 Database2RowHandlerInterface *target) {
286 // TODO(dimitri.glazkov): implement copying contents of this instance into
287 // target
288 return false;
289 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld r305