| // Copyright 2012 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef SQL_STATEMENT_H_ | |
| #define SQL_STATEMENT_H_ | |
| #include <stdint.h> | |
| #include <optional> | |
| #include <string> | |
| #include <string_view> | |
| #include <vector> | |
| #include "base/component_export.h" | |
| #include "base/containers/span.h" | |
| #include "base/dcheck_is_on.h" | |
| #include "base/memory/scoped_refptr.h" | |
| #include "base/sequence_checker.h" | |
| #include "base/thread_annotations.h" | |
| #include "base/time/time.h" | |
| #include "sql/database.h" | |
| namespace base { | |
| class RefCountedMemory; | |
| } // namespace base | |
| namespace sql { | |
| enum class SqliteResultCode : int; | |
| // Possible return values from ColumnType in a statement. These should match | |
| // the values in sqlite3.h. | |
| enum class ColumnType { | |
| kInteger = 1, | |
| kFloat = 2, | |
| kText = 3, | |
| kBlob = 4, | |
| kNull = 5, | |
| }; | |
| // Compiles and executes SQL statements. | |
| // | |
| // This class is not thread-safe. An instance must be accessed from a single | |
| // sequence. This is enforced in DCHECK-enabled builds. | |
| // | |
| // Normal usage: | |
| // sql::Statement s(connection_.GetUniqueStatement(...)); | |
| // s.BindInt(0, a); | |
| // if (s.Step()) | |
| // return s.ColumnString(0); | |
| // | |
| // If there are errors getting the statement, the statement will be inert; no | |
| // mutating or database-access methods will work. If you need to check for | |
| // validity, use: | |
| // if (!s.is_valid()) | |
| // return false; | |
| // | |
| // Step() and Run() just return true to signal success. If you want to handle | |
| // specific errors such as database corruption, install an error handler in | |
| // in the connection object using set_error_delegate(). | |
| class COMPONENT_EXPORT(SQL) Statement { | |
| public: | |
| // Utility function that returns what //sql code encodes the 'time' value as | |
| // in a database when using BindTime | |
| static int64_t TimeToSqlValue(base::Time time); | |
| // Creates an uninitialized statement. The statement will be invalid until | |
| // you initialize it via Assign. | |
| Statement(); | |
| explicit Statement(scoped_refptr<Database::StatementRef> ref); | |
| Statement(const Statement&) = delete; | |
| Statement& operator=(const Statement&) = delete; | |
| Statement(Statement&&) = delete; | |
| Statement& operator=(Statement&&) = delete; | |
| ~Statement(); | |
| // Initializes this object with the given statement, which may or may not | |
| // be valid. Use is_valid() to check if it's OK. | |
| void Assign(scoped_refptr<Database::StatementRef> ref); | |
| // Resets the statement to an uninitialized state corresponding to | |
| // the default constructor, releasing the StatementRef. | |
| void Clear(); | |
| // Returns true if the statement can be executed. All functions can still | |
| // be used if the statement is invalid, but they will return failure or some | |
| // default value. This is because the statement can become invalid in the | |
| // middle of executing a command if there is a serious error and the database | |
| // has to be reset. | |
| bool is_valid() const { | |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); | |
| return ref_->is_valid(); | |
| } | |
| // Running ------------------------------------------------------------------- | |
| // Executes the statement, returning true on success. This is like Step but | |
| // for when there is no output, like an INSERT statement. | |
| bool Run(); | |
| // Executes the statement, returning true if there is a row of data returned. | |
| // You can keep calling Step() until it returns false to iterate through all | |
| // the rows in your result set. | |
| // | |
| // When Step returns false, the result is either that there is no more data | |
| // or there is an error. This makes it most convenient for loop usage. If you | |
| // need to disambiguate these cases, use Succeeded(). | |
| // | |
| // Typical example: | |
| // while (s.Step()) { | |
| // ... | |
| // } | |
| // return s.Succeeded(); | |
| bool Step(); | |
| // Resets the statement to its initial condition. This includes any current | |
| // result row, and also the bound variables if the |clear_bound_vars| is true. | |
| void Reset(bool clear_bound_vars); | |
| // Returns true if the last executed thing in this statement succeeded. If | |
| // there was no last executed thing or the statement is invalid, this will | |
| // return false. | |
| bool Succeeded() const; | |
| // Binding ------------------------------------------------------------------- | |
| // These all take a 0-based parameter index and return true on success. | |
| // strings there may be out of memory. | |
| void BindNull(int param_index); | |
| void BindBool(int param_index, bool val); | |
| void BindInt(int param_index, int val); | |
| void BindInt(int param_index, | |
| int64_t val) = delete; // Call BindInt64() instead. | |
| void BindInt64(int param_index, int64_t val); | |
| void BindDouble(int param_index, double val); | |
| void BindCString(int param_index, const char* val); | |
| void BindString(int param_index, std::string_view val); | |
| // If you need to store (potentially invalid) UTF-16 strings losslessly, | |
| // store them as BLOBs instead. `BindBlob()` has an overload for this purpose. | |
| void BindString16(int param_index, std::u16string_view value); | |
| // Binds a blob to the statement. | |
| void BindBlob(int param_index, scoped_refptr<base::RefCountedMemory> blob); | |
| // Convenience overloads for `BindBlob()`. | |
| void BindBlob(int param_index, std::string blob); | |
| void BindBlob(int param_index, std::u16string blob); | |
| void BindBlob(int param_index, std::vector<uint8_t> blob); | |
| void BindBlob(int param_index, base::span<const uint8_t> value); | |
| // Reserves `size` bytes of space for a blob. The actual bytes should be set | |
| // via a `StreamingBlobHandle`. This method will assert if `size` is too big | |
| // for the database, which by default means > 1GB. | |
| void BindBlobForStreaming(int param_index, uint64_t size); | |
| // Serializes a `base::Time` in full fidelity (the number of microseconds | |
| // since the Windows epic in UTC). This form of binding is preferred over | |
| // `t.ToInternalValue()` or `t.ToDeltaSinceWindowsEpoch().InMicroseconds()`. | |
| // | |
| // Legacy serializations of `base::Time` via other ways, such as `ToTimeT()` | |
| // or `InMillisecondsSinceUnixEpoch()`, require a database migration to be | |
| // converted to this (recommended) serialization method. | |
| void BindTime(int param_index, base::Time time); | |
| // Serializes a `base::TimeDelta` in full fidelity (a number of microseconds). | |
| // This form of binding is preferred over `d.ToInternalValue()` or | |
| // `d.InMicroseconds()`. | |
| void BindTimeDelta(int param_index, base::TimeDelta delta); | |
| // Retrieving ---------------------------------------------------------------- | |
| // Returns the number of output columns in the result. | |
| int ColumnCount() const; | |
| // Returns the type associated with the given column. | |
| // | |
| // Watch out: the type may be undefined if you've done something to cause a | |
| // "type conversion." This means requesting the value of a column of a type | |
| // where that type is not the native type. For safety, call ColumnType only | |
| // on a column before getting the value out in any way. | |
| ColumnType GetColumnType(int col); | |
| // Returns the value at `column_index` (zero-based) in the current result set | |
| // produced by a successful call to `Step()`. `column_index` must be less than | |
| // the number of columns in the result set. Must only be called following a | |
| // successful call to `Step()`. | |
| bool ColumnBool(int column_index); | |
| int ColumnInt(int column_index); | |
| int64_t ColumnInt64(int column_index); | |
| double ColumnDouble(int column_index); | |
| std::string ColumnString(int column_index); | |
| // If you need to store and retrieve (potentially invalid) UTF-16 strings | |
| // losslessly, store them as BLOBs instead. They may be retrieved with | |
| // `ColumnBlobAsString16()`. | |
| std::u16string ColumnString16(int column_index); | |
| // Returns a string view pointing to a buffer containing the string data. | |
| // | |
| // This can be used to avoid allocating a temporary string when the value is | |
| // immediately passed to a function accepting a string view. Otherwise, the | |
| // string view's contents should be copied to a caller-owned buffer | |
| // immediately. Any method call on the `Statement` may invalidate the string | |
| // view. | |
| // | |
| // The string view will be empty (and may have a null data) if the underlying | |
| // string is empty. Code that needs to distinguish between empty strings and | |
| // NULL should call `GetColumnType()` before calling `ColumnStringView()`. | |
| std::string_view ColumnStringView(int column_index); | |
| // Deserializes a `base::Time` in full fidelity (the number of microseconds | |
| // since the Windows epoch in UTC). This form of retrieval is preferred over | |
| // `base::Time::FromInternalValue(ColumnInt64(column_index))` or | |
| // `base::Time::FromDeltaSinceWindowsEpoch( | |
| // base::Microseconds(ColumnInt64(column_index)))`. | |
| base::Time ColumnTime(int column_index); | |
| // Deserializes a `base::TimeDelta` in full fidelity (a number of | |
| // microseconds). This form of retrieval is preferred over | |
| // `base::TimeDelta::FromInternalValue(ColumnInt64(column_index))` or | |
| // `base::Microseconds(ColumnInt64(column_index))`. | |
| base::TimeDelta ColumnTimeDelta(int column_index); | |
| // Returns a span pointing to a buffer containing the blob data. | |
| // | |
| // The span's contents should be copied to a caller-owned buffer immediately. | |
| // Any method call on the Statement may invalidate the span. | |
| // | |
| // The span will be empty (and may have a null data) if the underlying blob is | |
| // empty. Code that needs to distinguish between empty blobs and NULL should | |
| // call GetColumnType() before calling ColumnBlob(). | |
| // | |
| // If you need to store and retrieve potentially invalid UTF-16 strings | |
| // losslessly, store them as BLOBs. They may be retrieved with | |
| // `ColumnBlobAsString16()`. | |
| base::span<const uint8_t> ColumnBlob(int column_index); | |
| // These convenience methods convert BLOB column data to various C++ types. | |
| std::string ColumnBlobAsString(int column_index); | |
| std::vector<uint8_t> ColumnBlobAsVector(int column_index); | |
| // This will return false if the underlying blob does not have an even | |
| // number of bytes. Otherwise, it will return true and copy the contents of | |
| // the blob to `result`. It does no validation on the contents of the blob. | |
| std::optional<std::u16string> ColumnBlobAsString16(int column_index); | |
| // Diagnostics -------------------------------------------------------------- | |
| // Returns the original text of a SQL statement WITHOUT any bound values. | |
| // Intended for logging in case of failures. Note that DOES NOT return any | |
| // bound values, because that would cause a privacy / PII issue for logging. | |
| std::string GetSQLStatement(); | |
| private: | |
| friend class Database; | |
| // Checks SQLite result codes and handles any errors. | |
| // | |
| // Returns `sqlite_result_code`. This gives callers the convenience of writing | |
| // "return CheckSqliteResultCode(sqlite_result_code)" and gives the compiler | |
| // the opportunity of doing tail call optimization (TCO) on the code above. | |
| // | |
| // This method reports error codes to the associated Database, and updates | |
| // internal state to reflect whether the statement succeeded or not. | |
| SqliteResultCode CheckSqliteResultCode(SqliteResultCode sqlite_result_code); | |
| // Should be called by all mutating methods to check that the statement is | |
| // valid. Returns true if the statement is valid. DCHECKS and returns false | |
| // if it is not. | |
| // The reason for this is to handle two specific cases in which a Statement | |
| // may be invalid. The first case is that the programmer made an SQL error. | |
| // Those cases need to be DCHECKed so that we are guaranteed to find them | |
| // before release. The second case is that the computer has an error (probably | |
| // out of disk space) which is prohibiting the correct operation of the | |
| // database. Our testing apparatus should not exhibit this defect, but release | |
| // situations may. Therefore, the code is handling disjoint situations in | |
| // release and test. In test, we're ensuring correct SQL. In release, we're | |
| // ensuring that contracts are honored in error edge cases. | |
| bool CheckValid() const; | |
| // Crashes the process if `this` is not in a state that allows reading from | |
| // columns (i.e. `Step()` was called and succeeded), and specifically the | |
| // given column. | |
| void CheckCanReadColumn(int column_index) const; | |
| // Helper for Run() and Step(), calls sqlite3_step() and returns the checked | |
| // value from it. | |
| SqliteResultCode StepInternal(); | |
| // Retrieve and log the count of VM steps required to execute the query. | |
| void ReportQueryExecutionMetrics() const; | |
| // Runs some basic sanity checks and frees memory previously associated with | |
| // `param_index`, if any. Should be called when a parameter is about to be | |
| // bound regardless of its type. | |
| void WillBindParameter(int param_index) | |
| VALID_CONTEXT_REQUIRED(sequence_checker_); | |
| // The actual sqlite statement. This may be unique to us, or it may be cached | |
| // by the Database, which is why it's ref-counted. This pointer is | |
| // guaranteed non-null. | |
| scoped_refptr<Database::StatementRef> ref_ | |
| GUARDED_BY_CONTEXT(sequence_checker_); | |
| // The result code for the last `Run()` or `Step()`. | |
| std::optional<SqliteResultCode> last_sqlite_result_code_ | |
| GUARDED_BY_CONTEXT(sequence_checker_); | |
| #if DCHECK_IS_ON() | |
| // Used to DCHECK() that Bind*() is called before Step() or Run() are called. | |
| bool step_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false; | |
| bool run_called_ GUARDED_BY_CONTEXT(sequence_checker_) = false; | |
| #endif // DCHECK_IS_ON() | |
| std::optional<base::TimeDelta> time_spent_stepping_ = std::nullopt; | |
| SEQUENCE_CHECKER(sequence_checker_); | |
| }; | |
| } // namespace sql | |
| #endif // SQL_STATEMENT_H_ |