• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #ifndef TENSORFLOW_CORE_LIB_DB_SQLITE_H_
16 #define TENSORFLOW_CORE_LIB_DB_SQLITE_H_
17 
18 #include <mutex>
19 
20 #include "sqlite3.h"
21 #include "tensorflow/core/lib/core/refcount.h"
22 #include "tensorflow/core/lib/core/status.h"
23 #include "tensorflow/core/lib/core/stringpiece.h"
24 #include "tensorflow/core/platform/macros.h"
25 #include "tensorflow/core/platform/thread_annotations.h"
26 #include "tensorflow/core/platform/types.h"
27 
28 /// TensorFlow SQLite Veneer
29 ///
30 /// - Memory safety
31 /// - Less boilerplate
32 /// - Removes deprecated stuff
33 /// - Pretends UTF16 doesn't exist
34 /// - Transaction compile-time safety
35 /// - Statically loads our native extensions
36 /// - Error reporting via tensorflow::Status et al.
37 ///
38 /// SQLite>=3.8.2 needs to be supported until April 2019, which is when
39 /// Ubuntu 14.04 LTS becomes EOL.
40 
41 namespace tensorflow {
42 
43 class SqliteLock;
44 class SqliteStatement;
45 class SqliteTransaction;
46 
47 /// \brief SQLite connection object.
48 ///
49 /// The SQLite connection is closed automatically by the destructor.
50 /// Reference counting ensures that happens after its statements are
51 /// destructed.
52 ///
53 /// Instances are reference counted and can be shared between threads.
54 /// This class offers the same thread safety behaviors as the SQLite
55 /// API itself.
56 ///
57 /// This veneer uses auto-commit mode by default, which means a 4ms
58 /// fsync() happens after every write unless a SqliteTransaction is
59 /// used or WAL mode is enabled beforehand.
60 class TF_LOCKABLE Sqlite : public core::RefCounted {
61  public:
62   /// \brief Closes SQLite connection, which can take milliseconds.
63   virtual ~Sqlite();
64 
65   /// \brief Opens SQLite database file.
66   ///
67   /// Most users will want to set flags to SQLITE_OPEN_READWRITE |
68   /// SQLITE_OPEN_CREATE. There are many other open flags; here are
69   /// notes on a few of them:
70   ///
71   /// - SQLITE_OPEN_READONLY: Allowed if no WAL journal is active.
72   /// - SQLITE_OPEN_SHAREDCACHE: Will be ignored because this veneer
73   ///   doesn't support the unlock notify API.
74   /// - SQLITE_OPEN_NOMUTEX: Means access to this connection MUST be
75   ///   serialized by the caller in accordance with the same contracts
76   ///   implemented by this API.
77   ///
78   /// This function sets PRAGMA values from TF_SQLITE_* environment
79   /// variables. See sqlite.cc to learn more.
80   static Status Open(const string& path, int flags, Sqlite** db);
81 
82   /// \brief Creates SQLite statement.
83   ///
84   /// This routine should never fail if sql is valid and does not
85   /// reference tables. When tables are referenced, system calls are
86   /// needed which can take microseconds. When the schema changes, this
87   /// routine will retry automatically and then possibly fail.
88   ///
89   /// The returned statement holds a reference to this object.
90   Status Prepare(const StringPiece& sql, SqliteStatement* stmt);
91   SqliteStatement PrepareOrDie(const StringPiece& sql);
92 
93   /// \brief Returns extended result code of last error.
94   ///
95   /// If the most recent API call was successful, the result is
96   /// undefined. The legacy result code can be obtained by saying
97   /// errcode() & 0xff.
errcode()98   int errcode() const TF_EXCLUSIVE_LOCKS_REQUIRED(this) {
99     return sqlite3_extended_errcode(db_);
100   }
101 
102   /// \brief Returns pointer to current error message state.
errmsg()103   const char* errmsg() const TF_EXCLUSIVE_LOCKS_REQUIRED(this) {
104     return sqlite3_errmsg(db_);
105   }
106 
107   /// \brief Returns rowid assigned to last successful insert.
last_insert_rowid()108   int64_t last_insert_rowid() const TF_EXCLUSIVE_LOCKS_REQUIRED(this) {
109     return sqlite3_last_insert_rowid(db_);
110   }
111 
112   /// \brief Returns number of rows directly changed by last write.
changes()113   int64_t changes() const TF_EXCLUSIVE_LOCKS_REQUIRED(this) {
114     return sqlite3_changes(db_);
115   }
116 
117  private:
118   friend class SqliteLock;
119   friend class SqliteStatement;
120   friend class SqliteTransaction;
121 
Sqlite(sqlite3 * db,sqlite3_stmt * begin,sqlite3_stmt * commit,sqlite3_stmt * rollback)122   Sqlite(sqlite3* db, sqlite3_stmt* begin, sqlite3_stmt* commit,
123          sqlite3_stmt* rollback) noexcept
124       : db_(db), begin_(begin), commit_(commit), rollback_(rollback) {}
125 
126   sqlite3* const db_;
127   sqlite3_stmt* const begin_;
128   sqlite3_stmt* const commit_;
129   sqlite3_stmt* const rollback_;
130   bool is_in_transaction_ = false;
131 
132   TF_DISALLOW_COPY_AND_ASSIGN(Sqlite);
133 };
134 
135 /// \brief SQLite prepared statement.
136 ///
137 /// Instances can only be shared between threads if caller serializes
138 /// access from first Bind*() to *Reset().
139 ///
140 /// When reusing a statement in a loop, be certain to not have jumps
141 /// betwixt Bind*() and *Reset().
142 class SqliteStatement {
143  public:
144   /// \brief Initializes an empty statement to be assigned later.
145   SqliteStatement() noexcept = default;
146 
147   /// \brief Finalizes statement.
148   ///
149   /// This can take milliseconds if it was blocking the Sqlite
150   /// connection object from being freed.
~SqliteStatement()151   ~SqliteStatement() {
152     sqlite3_finalize(stmt_);
153     if (db_ != nullptr) db_->Unref();
154   }
155 
156   /// \brief Returns true if statement is initialized.
157   explicit operator bool() const { return stmt_ != nullptr; }
158 
159   /// \brief Returns SQL text from when this query was prepared.
sql()160   const char* sql() const { return sqlite3_sql(stmt_); }
161 
162   /// \brief Number of bytes bound since last *Reset().
size()163   uint64 size() { return size_; }
164 
165   /// \brief Executes query for fetching arbitrary rows.
166   ///
167   /// `is_done` will always be set to true unless SQLITE_ROW is
168   /// returned by the underlying API. If status() is already in an
169   /// error state, then this method is a no-op and the existing status
170   /// is returned.
171   ///
172   /// The OrDie version returns `!is_done` which, if true, indicates a
173   /// row is available.
174   ///
175   /// This statement should be Reset() or destructed when finished with
176   /// the result.
177   Status Step(bool* is_done);
178   bool StepOrDie() TF_MUST_USE_RESULT;
179 
180   /// \brief Executes query when only one row is desired.
181   ///
182   /// If a row isn't returned, an internal error Status is returned
183   /// that won't be reflected in the connection error state.
184   ///
185   /// This statement should be Reset() or destructed when finished with
186   /// the result.
187   Status StepOnce();
188   const SqliteStatement& StepOnceOrDie();
189 
190   /// \brief Executes query, ensures zero rows returned, then Reset().
191   ///
192   /// If a row is returned, an internal error Status is returned that
193   /// won't be reflected in the connection error state.
194   Status StepAndReset();
195   void StepAndResetOrDie();
196 
197   /// \brief Resets statement so it can be executed again.
198   ///
199   /// Implementation note: This method diverges from canonical API
200   /// behavior by calling sqlite3_clear_bindings() in addition to
201   /// sqlite3_reset(). That makes the veneer safer; we haven't found a
202   /// super compelling reason yet to call them independently.
203   void Reset();
204 
205   /// \brief Binds signed 64-bit integer to 1-indexed query parameter.
BindInt(int parameter,int64_t value)206   void BindInt(int parameter, int64_t value) {
207     Update(sqlite3_bind_int64(stmt_, parameter, value), parameter);
208     size_ += sizeof(int64_t);
209   }
BindInt(const char * parameter,int64_t value)210   void BindInt(const char* parameter, int64_t value) {
211     BindInt(GetParameterIndex(parameter), value);
212   }
213 
214   /// \brief Binds double to 1-indexed query parameter.
BindDouble(int parameter,double value)215   void BindDouble(int parameter, double value) {
216     Update(sqlite3_bind_double(stmt_, parameter, value), parameter);
217     size_ += sizeof(double);
218   }
BindDouble(const char * parameter,double value)219   void BindDouble(const char* parameter, double value) {
220     BindDouble(GetParameterIndex(parameter), value);
221   }
222 
223   /// \brief Copies UTF-8 text to 1-indexed query parameter.
224   ///
225   /// If NUL characters are present, they will still go in the DB and
226   /// be successfully retrieved by ColumnString(); however, the
227   /// behavior of these values with SQLite functions is undefined.
228   ///
229   /// When using the unsafe methods, the data must not be changed or
230   /// freed until this statement is Reset() or finalized.
BindText(int parameter,const StringPiece & text)231   void BindText(int parameter, const StringPiece& text) {
232     Update(sqlite3_bind_text64(stmt_, parameter, text.data(), text.size(),
233                                SQLITE_TRANSIENT, SQLITE_UTF8),
234            parameter);
235     size_ += text.size();
236   }
BindText(const char * parameter,const StringPiece & text)237   void BindText(const char* parameter, const StringPiece& text) {
238     BindText(GetParameterIndex(parameter), text);
239   }
BindTextUnsafe(int parameter,const StringPiece & text)240   void BindTextUnsafe(int parameter, const StringPiece& text) {
241     Update(sqlite3_bind_text64(stmt_, parameter, text.data(), text.size(),
242                                SQLITE_STATIC, SQLITE_UTF8),
243            parameter);
244     size_ += text.size();
245   }
BindTextUnsafe(const char * parameter,const StringPiece & text)246   void BindTextUnsafe(const char* parameter, const StringPiece& text) {
247     BindTextUnsafe(GetParameterIndex(parameter), text);
248   }
249 
250   /// \brief Copies binary data to 1-indexed query parameter.
251   ///
252   /// When using the unsafe methods, the data must not be changed or
253   /// freed until this statement is Reset() or finalized.
BindBlob(int parameter,const StringPiece & blob)254   void BindBlob(int parameter, const StringPiece& blob) {
255     Update(sqlite3_bind_blob64(stmt_, parameter, blob.data(), blob.size(),
256                                SQLITE_TRANSIENT),
257            parameter);
258     size_ += blob.size();
259   }
BindBlob(const char * parameter,const StringPiece & blob)260   void BindBlob(const char* parameter, const StringPiece& blob) {
261     BindBlob(GetParameterIndex(parameter), blob);
262   }
BindBlobUnsafe(int parameter,const StringPiece & blob)263   void BindBlobUnsafe(int parameter, const StringPiece& blob) {
264     Update(sqlite3_bind_blob64(stmt_, parameter, blob.data(), blob.size(),
265                                SQLITE_STATIC),
266            parameter);
267     size_ += blob.size();
268   }
BindBlobUnsafe(const char * parameter,const StringPiece & text)269   void BindBlobUnsafe(const char* parameter, const StringPiece& text) {
270     BindBlobUnsafe(GetParameterIndex(parameter), text);
271   }
272 
273   /// \brief Returns number of columns in result set.
ColumnCount()274   int ColumnCount() const TF_MUST_USE_RESULT {
275     return sqlite3_column_count(stmt_);
276   }
277 
278   /// \brief Returns type of 0-indexed column value in row data.
279   ///
280   /// Please note that SQLite is dynamically typed and the type of a
281   /// particular column can vary from row to row.
ColumnType(int column)282   int ColumnType(int column) const TF_MUST_USE_RESULT {
283     return sqlite3_column_type(stmt_, column);
284   }
285 
286   /// \brief Returns 0-indexed column from row result coerced as an integer.
ColumnInt(int column)287   int64_t ColumnInt(int column) const TF_MUST_USE_RESULT {
288     return sqlite3_column_int64(stmt_, column);
289   }
290 
291   /// \brief Returns 0-indexed column from row result coerced as a double.
ColumnDouble(int column)292   double ColumnDouble(int column) const TF_MUST_USE_RESULT {
293     return sqlite3_column_double(stmt_, column);
294   }
295 
296   /// \brief Copies 0-indexed column from row result coerced as a string.
297   ///
298   /// NULL values are returned as empty string. This method should be
299   /// used for both BLOB and TEXT columns. See also: ColumnType().
ColumnString(int column)300   string ColumnString(int column) const TF_MUST_USE_RESULT {
301     auto data = sqlite3_column_blob(stmt_, column);
302     if (data == nullptr) return "";
303     return {static_cast<const char*>(data),
304             static_cast<size_t>(ColumnSize(column))};
305   }
306 
307   /// \brief Returns pointer to binary data at 0-indexed column.
308   ///
309   /// Empty values are returned as NULL. The returned memory will no
310   /// longer be valid the next time Step() or Reset() is called. No NUL
311   /// terminator is added.
ColumnStringUnsafe(int column)312   StringPiece ColumnStringUnsafe(int column) const TF_MUST_USE_RESULT {
313     return {static_cast<const char*>(sqlite3_column_blob(stmt_, column)),
314             static_cast<size_t>(ColumnSize(column))};
315   }
316 
317   /// \brief Returns number of bytes stored at 0-indexed column.
ColumnSize(int column)318   int ColumnSize(int column) const TF_MUST_USE_RESULT {
319     return sqlite3_column_bytes(stmt_, column);
320   }
321 
322   /// \brief Move constructor, after which <other> is reset to empty.
SqliteStatement(SqliteStatement && other)323   SqliteStatement(SqliteStatement&& other) noexcept
324       : db_(other.db_), stmt_(other.stmt_), bind_error_(other.bind_error_) {
325     other.db_ = nullptr;
326     other.stmt_ = nullptr;
327     other.bind_error_ = SQLITE_OK;
328   }
329 
330   /// \brief Move assignment, after which <other> is reset to empty.
331   SqliteStatement& operator=(SqliteStatement&& other) noexcept {
332     if (&other != this) {
333       if (db_ != nullptr) db_->Unref();
334       if (stmt_ != nullptr) sqlite3_finalize(stmt_);
335       db_ = other.db_;
336       stmt_ = other.stmt_;
337       bind_error_ = other.bind_error_;
338       size_ = other.size_;
339       other.db_ = nullptr;
340       other.stmt_ = nullptr;
341       other.bind_error_ = SQLITE_OK;
342       other.size_ = 0;
343     }
344     return *this;
345   }
346 
347  private:
348   friend class Sqlite;
349 
SqliteStatement(Sqlite * db,sqlite3_stmt * stmt)350   SqliteStatement(Sqlite* db, sqlite3_stmt* stmt) noexcept
351       : db_(db), stmt_(stmt) {
352     db_->Ref();
353   }
354 
Update(int rc,int parameter)355   void Update(int rc, int parameter) {
356     // Binding strings can fail if they exceed length limit.
357     if (TF_PREDICT_FALSE(rc != SQLITE_OK)) {
358       if (bind_error_ == SQLITE_OK) {
359         bind_error_ = rc;
360         bind_error_parameter_ = parameter;
361       }
362     }
363   }
364 
GetParameterIndex(const char * parameter)365   int GetParameterIndex(const char* parameter) {
366     int index = sqlite3_bind_parameter_index(stmt_, parameter);
367     DCHECK(index > 0);  // OK to compile away since it'll fail again
368     return index;
369   }
370 
371   Sqlite* db_ = nullptr;
372   sqlite3_stmt* stmt_ = nullptr;
373   int bind_error_ = SQLITE_OK;
374   int bind_error_parameter_ = 0;
375   uint64 size_ = 0;
376 
377   TF_DISALLOW_COPY_AND_ASSIGN(SqliteStatement);
378 };
379 
380 /// \brief Reentrant SQLite connection object lock
381 ///
382 /// This is a no-op if SQLITE_OPEN_NOMUTEX was used.
383 class TF_SCOPED_LOCKABLE SqliteLock {
384  public:
SqliteLock(Sqlite & db)385   explicit SqliteLock(Sqlite& db) TF_EXCLUSIVE_LOCK_FUNCTION(db)
386       : mutex_(sqlite3_db_mutex(db.db_)) {
387     sqlite3_mutex_enter(mutex_);
388   }
SqliteLock(Sqlite & db,std::try_to_lock_t)389   SqliteLock(Sqlite& db, std::try_to_lock_t) TF_EXCLUSIVE_LOCK_FUNCTION(db)
390       : mutex_(sqlite3_db_mutex(db.db_)) {
391     if (TF_PREDICT_FALSE(sqlite3_mutex_try(mutex_) != SQLITE_OK)) {
392       is_locked_ = false;
393     }
394   }
TF_UNLOCK_FUNCTION()395   ~SqliteLock() TF_UNLOCK_FUNCTION() {
396     if (is_locked_) sqlite3_mutex_leave(mutex_);
397   }
398   explicit operator bool() const { return is_locked_; }
399 
400  private:
401   sqlite3_mutex* const mutex_;
402   bool is_locked_ = true;
403   TF_DISALLOW_COPY_AND_ASSIGN(SqliteLock);
404 };
405 #define SqliteLock(x) static_assert(0, "sqlite_lock_decl_missing_name");
406 
407 /// \brief SQLite transaction scope.
408 ///
409 /// This class acquires an exclusive lock on the connection object (if
410 /// mutexes weren't disabled) and runs BEGIN / ROLLBACK automatically.
411 /// Unlike SqliteLock this scope is non-reentrant. To avoid program
412 /// crashes, business logic should use the TF_EXCLUSIVE_LOCK_FUNCTION and
413 /// TF_LOCKS_EXCLUDED annotations as much as possible.
414 class TF_SCOPED_LOCKABLE SqliteTransaction {
415  public:
416   /// \brief Locks db and begins deferred transaction.
417   ///
418   /// This will crash if a transaction is already active.
419   explicit SqliteTransaction(Sqlite& db) TF_EXCLUSIVE_LOCK_FUNCTION(db);
420 
421   /// \brief Runs ROLLBACK and unlocks.
422   ~SqliteTransaction() TF_UNLOCK_FUNCTION();
423 
424   /// \brief Commits transaction.
425   ///
426   /// If this is successful, a new transaction will be started, which
427   /// is rolled back when exiting the scope.
428   Status Commit();
429 
430  private:
431   void Begin();
432   Sqlite* const db_;
433 
434   TF_DISALLOW_COPY_AND_ASSIGN(SqliteTransaction);
435 };
436 
437 #define SQLITE_EXCLUSIVE_TRANSACTIONS_REQUIRED(...) \
438   TF_EXCLUSIVE_LOCKS_REQUIRED(__VA_ARGS__)
439 #define SQLITE_TRANSACTIONS_EXCLUDED(...) TF_LOCKS_EXCLUDED(__VA_ARGS__)
440 
PrepareOrDie(const StringPiece & sql)441 inline SqliteStatement Sqlite::PrepareOrDie(const StringPiece& sql) {
442   SqliteStatement stmt;
443   TF_CHECK_OK(Prepare(sql, &stmt));
444   return stmt;
445 }
446 
447 }  // namespace tensorflow
448 
449 #endif  // TENSORFLOW_CORE_LIB_DB_SQLITE_H_
450