1
// Copyright 2008, Google Inc.
3
// Redistribution and use in source and binary forms, with or without
4
// modification, are permitted provided that the following conditions are met:
6
// 1. Redistributions of source code must retain the above copyright notice,
7
// this list of conditions and the following disclaimer.
8
// 2. Redistributions in binary form must reproduce the above copyright notice,
9
// this list of conditions and the following disclaimer in the documentation
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
12
// used to endorse or promote products derived from this software without
13
// specific prior written permission.
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
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
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,
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
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#include "gears/base/common/position_table.h"
28
// Macros for use in SQL statements.
29
#define POSITION L"Position"
33
static const char *kCreateTableVersion1Statement =
34
"CREATE TABLE Position ("
35
" Name TEXT PRIMARY KEY, "
36
" Latitude DOUBLE NOT NULL, "
37
" Longitude DOUBLE NOT NULL, "
38
" Altitude INTEGER NOT NULL, "
39
" Accuracy INTEGER NOT NULL, "
40
" AltitudeAccuracy INTEGER NOT NULL, "
41
" Timestamp INT64 NOT NULL, "
42
" StreetNumber TEXT NOT NULL, "
43
" Street TEXT NOT NULL, "
44
" Premises TEXT NOT NULL, "
45
" City TEXT NOT NULL, "
46
" County TEXT NOT NULL, "
47
" Region TEXT NOT NULL, "
48
" Country TEXT NOT NULL, "
49
" CountryCode TEXT NOT NULL, "
50
" PostalCode TEXT NOT NULL, "
51
" ErrorCode INTEGER NOT NULL, "
52
" ErrorMessage TEXT NOT NULL "
55
PositionTable::PositionTable(SQLDatabase *db) : db_(db) {
58
bool PositionTable::CreateTableLatestVersion() {
59
return CreateVersion1();
62
bool PositionTable::SetPosition(const std::string16 &name,
63
const Position &position) {
64
// Local helper macro.
65
#define LOG_BIND_ERROR(name) \
66
LOG(("PositionTable::SetPosition unable to bind " name ": %d.\n", \
67
db_->GetErrorCode()));
69
SQLTransaction transaction(db_, "PositionTable::SetPosition");
70
if (!transaction.Begin()) {
74
const char16 *sql = STRING16(L"REPLACE INTO " POSITION L" "
75
L"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
76
L"?, ?, ?, ?, ?, ?)");
78
SQLStatement statement;
79
if (SQLITE_OK != statement.prepare16(db_, sql)) {
80
LOG(("PositionTable::SetPosition unable to prepare: %d.\n",
81
db_->GetErrorCode()));
85
if (SQLITE_OK != statement.bind_text16(0, name.c_str())) {
86
LOG_BIND_ERROR("name");
89
if (SQLITE_OK != statement.bind_double(1, position.latitude)) {
90
LOG_BIND_ERROR("latitude");
93
if (SQLITE_OK != statement.bind_double(2, position.longitude)) {
94
LOG_BIND_ERROR("longitude");
97
// The Altitude, Accuracy and AltitudeAccuracy columns have type INTEGER, but
98
// we can safely store and extract floating point values because SQLite uses
99
// type affinity. See http://www.sqlite.org/datatype3.html#affinity.
100
if (SQLITE_OK != statement.bind_double(3, position.altitude)) {
101
LOG_BIND_ERROR("altitude");
104
if (SQLITE_OK != statement.bind_double(4, position.accuracy)) {
105
LOG_BIND_ERROR("accuracy");
108
if (SQLITE_OK != statement.bind_double(5, position.altitude_accuracy)) {
109
LOG_BIND_ERROR("altitude accuracy");
112
if (SQLITE_OK != statement.bind_int64(6, position.timestamp)) {
113
LOG_BIND_ERROR("timestamp");
117
statement.bind_text16(7, position.address.street_number.c_str())) {
118
LOG_BIND_ERROR("street number");
121
if (SQLITE_OK != statement.bind_text16(8, position.address.street.c_str())) {
122
LOG_BIND_ERROR("street");
126
statement.bind_text16(9, position.address.premises.c_str())) {
127
LOG_BIND_ERROR("premises");
130
if (SQLITE_OK != statement.bind_text16(10, position.address.city.c_str())) {
131
LOG_BIND_ERROR("city");
134
if (SQLITE_OK != statement.bind_text16(11, position.address.county.c_str())) {
135
LOG_BIND_ERROR("county");
138
if (SQLITE_OK != statement.bind_text16(12, position.address.region.c_str())) {
139
LOG_BIND_ERROR("region");
143
statement.bind_text16(13, position.address.country.c_str())) {
144
LOG_BIND_ERROR("country");
148
statement.bind_text16(14, position.address.country_code.c_str())) {
149
LOG_BIND_ERROR("country code");
153
statement.bind_text16(15, position.address.postal_code.c_str())) {
154
LOG_BIND_ERROR("postal code");
157
if (SQLITE_OK != statement.bind_int(16, position.error_code)) {
158
LOG_BIND_ERROR("error code");
161
if (SQLITE_OK != statement.bind_text16(17, position.error_message.c_str())) {
162
LOG_BIND_ERROR("error message");
167
if (SQLITE_DONE != statement.step()) {
168
LOG(("PositionTable::SetPosition unable to step: %d.\n",
169
db_->GetErrorCode()));
173
return transaction.Commit();
176
bool PositionTable::GetPosition(const std::string16 &name,
177
Position *position) {
180
const char16 *sql = STRING16(L"SELECT * "
181
L"FROM " POSITION L" "
182
L"WHERE " NAME L" = ? ");
184
SQLStatement statement;
185
if (SQLITE_OK != statement.prepare16(db_, sql)) {
186
LOG(("PositionTable::GetPosition unable to prepare: %d.\n",
187
db_->GetErrorCode()));
191
if (SQLITE_OK != statement.bind_text16(0, name.c_str())) {
192
LOG(("PositionTable::GetPosition unable to bind name: %d.\n",
193
db_->GetErrorCode()));
197
int rc = statement.step();
198
if (SQLITE_DONE == rc) {
200
} else if (SQLITE_ROW != rc) {
201
LOG(("PositionTable::GetPosition results error: %d.\n",
202
db_->GetErrorCode()));
206
// Skip Name at index 0.
207
position->latitude = statement.column_double(1);
208
position->longitude = statement.column_double(2);
209
// The Altitude, Accuracy and AltitudeAccuracy columns have type INTEGER, but
210
// we can safely store and extract floating point values because SQLite uses
211
// type affinity. See http://www.sqlite.org/datatype3.html#affinity.
212
position->altitude = statement.column_double(3);
213
position->accuracy = statement.column_double(4);
214
position->altitude_accuracy = statement.column_double(5);
215
position->timestamp = statement.column_int64(6);
216
position->address.street_number = statement.column_text16_safe(7);
217
position->address.street = statement.column_text16_safe(8);
218
position->address.premises = statement.column_text16_safe(9);
219
position->address.city = statement.column_text16_safe(10);
220
position->address.county = statement.column_text16_safe(11);
221
position->address.region = statement.column_text16_safe(12);
222
position->address.country = statement.column_text16_safe(13);
223
position->address.country_code = statement.column_text16_safe(14);
224
position->address.postal_code = statement.column_text16_safe(15);
225
int error_code = statement.column_int(16);
226
position->error_message = statement.column_text16_safe(17);
228
switch (error_code) {
229
case Position::ERROR_CODE_POSITION_UNAVAILABLE:
230
position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE;
232
case Position::ERROR_CODE_TIMEOUT:
233
position->error_code = Position::ERROR_CODE_TIMEOUT;
236
// Note that in previous versions, error_code was set to kint32min to
238
position->error_code = Position::ERROR_CODE_NONE;
244
bool PositionTable::DeletePosition(const std::string16 &name) {
245
const char16 *sql = STRING16(L"DELETE FROM " POSITION L" "
246
L"WHERE " NAME L" = ?");
248
SQLStatement statement;
249
if (SQLITE_OK != statement.prepare16(db_, sql)) {
250
LOG(("PositionTable::DeletePosition unable to prepare: %d.\n",
251
db_->GetErrorCode()));
255
if (SQLITE_OK != statement.bind_text16(0, name.c_str())) {
256
LOG(("PositionTable::DeletePosition unable to bind name: %d.\n",
257
db_->GetErrorCode()));
261
if (SQLITE_DONE != statement.step()) {
262
LOG(("PositionTable::DeletePosition unable to step: %d.\n",
263
db_->GetErrorCode()));
270
bool PositionTable::CreateVersion1() {
271
SQLTransaction transaction(db_, "PositionTable::CreateVersion1");
272
if (!transaction.Begin()) {
276
if (SQLITE_OK != db_->Execute(kCreateTableVersion1Statement)) {
277
LOG(("PositionTable::CreateVersion1 unable to execute %d.\n",
278
db_->GetErrorCode()));
282
return transaction.Commit();