// SQLite Database #include "db/db_sqlite3.h" #include static const char kNULL[] = "\0\0\0"; namespace ndb { ////////////////////////////////////////////////////////////////////////////// // SQLiteDB SQLiteDB::SQLiteDB() { sqlite3_ = NULL; } SQLiteDB::SQLiteDB(SQLiteDB& src) { sqlite3_ = src.sqlite3_; src.sqlite3_ = NULL; } SQLiteDB::~SQLiteDB() { Interrupt(); Close(); } SQLiteDB& SQLiteDB::operator=(SQLiteDB& src) { Interrupt(); Close(); sqlite3_ = src.sqlite3_; src.sqlite3_ = NULL; return *this; } bool SQLiteDB::Open(int flags) { return Open(":memory:", "", flags); } bool SQLiteDB::Open(const char* filename, const std::string &key, int flags/* = modeReadWrite|modeCreate|modeSerialized*/) { Interrupt(); Close(); if (filename == NULL) return false; int r = sqlite3_open_v2(filename, &sqlite3_, flags, NULL); if (r != SQLITE_OK) { Close(); } else { if (key.length()) { if( SQLITE_OK != sqlite3_key(sqlite3_,key.c_str(),(int)key.length())) r = sqlite3_rekey(sqlite3_,key.c_str(),(int)key.length()); } } return r == SQLITE_OK; } bool SQLiteDB::Close() { if (sqlite3_ == NULL) return true; /* * If sqlite3_close() is called on a database connection that still has * outstanding prepared statements or BLOB handles, then it returns SQLITE_BUSY */ if (SQLITE_OK != sqlite3_close(sqlite3_)) return false; sqlite3_ = NULL; return true; } bool SQLiteDB::Compact() { if (SQLITE_OK != Query("VACUUM")) return false; return true; } bool SQLiteDB::IsValid() const { return sqlite3_ != NULL; } int SQLiteDB::GetLastErrorCode() const { if (sqlite3_ == NULL) return SQLITE_OK; return sqlite3_errcode(sqlite3_); } int SQLiteDB::GetLastExtendedErrorCode() const { if (sqlite3_ == NULL) return SQLITE_OK; return sqlite3_extended_errcode(sqlite3_); } const char* SQLiteDB::GetLastErrorMessage() const { assert(sqlite3_); if (sqlite3_ == NULL) return kNULL; return sqlite3_errmsg(sqlite3_); } int SQLiteDB::GetChanges() const { assert(sqlite3_); if (sqlite3_ == NULL) return -1; return sqlite3_changes(sqlite3_); } int SQLiteDB::GetTotalChanges() const { assert(sqlite3_); if (sqlite3_ == NULL) return -1; return sqlite3_total_changes(sqlite3_); } bool SQLiteDB::DoesTableExist(const char* table_name) const { return DoesTableOrIndexExist(table_name, "table"); } bool SQLiteDB::DoesIndexExist(const char* index_name) const { return DoesTableOrIndexExist(index_name, "index"); } bool SQLiteDB::DoesTableOrIndexExist( const char* name, const char* type) const { SQLiteStatement stat; Query(stat, "SELECT name FROM sqlite_master WHERE type=? AND name=?"); if (!stat.IsValid()) return false; // Bind is 1 based stat.BindText(1, type); stat.BindText(2, name); return stat.NextRow() == SQLITE_ROW; } bool SQLiteDB::DoesColumnExist( const char* table_name, const char* column_name) const { std::string sql("PRAGMA TABLE_INFO("); sql.append(table_name); sql.append(")"); SQLiteStatement stat; Query(stat, sql.c_str(), (int)sql.size()); if (!stat.IsValid()) return false; while (stat.NextRow() == SQLITE_ROW) { if (!strcmp(stat.GetTextField(1), column_name)) return true; } return false; } sqlite3_int64 SQLiteDB::GetLastInsertRowId() const { assert(sqlite3_); if (sqlite3_ == NULL) return -1; return sqlite3_last_insert_rowid(sqlite3_); } int SQLiteDB::Query(SQLiteStatement& statement, const char* sql_text, int length) const { statement.Finalize(); if (!sqlite3_ || !sql_text) return SQLITE_MISUSE; /* * SQLite documents say: * If the caller knows that the supplied string is nul-terminated, * then there is a small performance advantage to be gained by passing an nByte parameter * that is equal to the number of bytes in the input string including the nul-terminator bytes. */ if (length < 0) length = (int)strlen(sql_text) + 1; return sqlite3_prepare_v2(sqlite3_, sql_text, length, &statement.stmt_, NULL); } int SQLiteDB::Query(const char* sql_text, SQLiteQueryDelegate delegate, void* param) const { if (!sqlite3_ || !sql_text) return SQLITE_MISUSE; return sqlite3_exec(sqlite3_, sql_text, delegate, param, NULL); } int SQLiteDB::Query(const char* sql_text, SQLiteResultTable& table) const { if (!sqlite3_ || !sql_text) return SQLITE_MISUSE; // 先清空结果表 table.Free(); int r = sqlite3_get_table(sqlite3_, sql_text, &table.result_column_, &table.row_, &table.col_, NULL); if (r == SQLITE_OK) table.result_ = table.result_column_ + table.col_; return r; } void SQLiteDB::Interrupt() { if (!sqlite3_) return; sqlite3_interrupt(sqlite3_); } int SQLiteDB::SetBusyTimeout(int ms) { if (!sqlite3_) return SQLITE_MISUSE; return sqlite3_busy_timeout(sqlite3_, ms); } int SQLiteDB::GetVersion() { return sqlite3_libversion_number(); } ////////////////////////////////////////////////////////////////////////////// // SQLiteResultTable SQLiteResultTable::SQLiteResultTable() { Reset(); } SQLiteResultTable::SQLiteResultTable(SQLiteResultTable& src) { row_ = src.row_; col_ = src.col_; result_ = src.result_; result_column_ = src.result_column_; src.Reset(); } SQLiteResultTable::~SQLiteResultTable() { Free(); } SQLiteResultTable& SQLiteResultTable::operator=(SQLiteResultTable& src) { row_ = src.row_; col_ = src.col_; result_ = src.result_; result_column_ = src.result_column_; src.Reset(); return *this; } void SQLiteResultTable::Free() { if (result_column_ != NULL) { sqlite3_free_table(result_column_); Reset(); } } void SQLiteResultTable::Reset() { row_ = 0; col_ = 0; result_ = NULL; result_column_ = NULL; } bool SQLiteResultTable::IsEmpty() const { return result_column_ == 0; } int SQLiteResultTable::GetRowCount() const { return row_; } int SQLiteResultTable::GetColumnCount() const { return col_; } const char* SQLiteResultTable::GetValue(int row, int col) const { if (!result_ || row >= row_ || col >= col_ || row < 0 || col < 0) { return 0; } return result_[row * col_ + col]; } const char** const SQLiteResultTable::operator[](int row) const { // 为了效率,这里不检查越界,就像STL那样 return (const char**)result_ + row * col_; } const char* SQLiteResultTable::GetColumnName(int col) const { if (!result_column_ || col < 0 || col >= col_) return 0; return result_column_[col]; } ////////////////////////////////////////////////////////////////////////////// // SQLiteStatement SQLiteStatement::SQLiteStatement() { stmt_ = NULL; eof_ = true; } SQLiteStatement::SQLiteStatement(SQLiteStatement& src) { stmt_ = src.stmt_; eof_ = src.eof_; src.stmt_ = NULL; src.eof_ = true; } SQLiteStatement::~SQLiteStatement() { Finalize(); } SQLiteStatement& SQLiteStatement::operator=(SQLiteStatement& src) { Finalize(); stmt_ = src.stmt_; eof_ = src.eof_; src.stmt_ = NULL; src.eof_ = true; return *this; } int SQLiteStatement::Finalize() { int r = SQLITE_OK; if (stmt_ != NULL) { r = sqlite3_finalize(stmt_); if (r == SQLITE_OK) { stmt_ = NULL; eof_ = true; } } return r; } int SQLiteStatement::Rewind() { int r = SQLITE_MISUSE; if (stmt_ != NULL) { r = sqlite3_reset(stmt_); if (SQLITE_OK == r) { eof_ = false; return SQLITE_OK; } } return r; } int SQLiteStatement::NextRow() { if (stmt_ == NULL) return SQLITE_MISUSE; int r = sqlite3_step(stmt_); if (r == SQLITE_DONE) eof_ = true; return r; } bool SQLiteStatement::IsEof() { return eof_; } bool SQLiteStatement::IsNullField(int col) { return GetFieldValue(col) != NULL; } const void* SQLiteStatement::GetBlobField(int col) { if (stmt_ == NULL) return NULL; return sqlite3_column_blob(stmt_, col); } int SQLiteStatement::GetBytesField(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_bytes(stmt_, col); } int SQLiteStatement::GetBytes16Field(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_bytes16(stmt_, col); } double SQLiteStatement::GetDoubleField(int col) { if (stmt_ == NULL) return 0.0; return sqlite3_column_double(stmt_, col); } int SQLiteStatement::GetIntField(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_int(stmt_, col); } sqlite3_int64 SQLiteStatement::GetInt64Field(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_int64(stmt_, col); } const char* SQLiteStatement::GetTextField(int col) { if (stmt_ == NULL) return NULL; return (const char*)sqlite3_column_text(stmt_, col); } const void* SQLiteStatement::GetText16Field(int col) { if (stmt_ == NULL) return NULL; return sqlite3_column_text16(stmt_, col); } int SQLiteStatement::GetTypeField(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_type(stmt_, col); } sqlite3_value* SQLiteStatement::GetFieldValue(int col) { if (stmt_ == NULL) return NULL; return sqlite3_column_value(stmt_, col); } int SQLiteStatement::GetFieldBytes(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_bytes(stmt_, col); } int SQLiteStatement::GetFieldBytes16(int col) { if (stmt_ == NULL) return 0; return sqlite3_column_bytes16(stmt_, col); } int SQLiteStatement::BindBlob(int index, const void* data, int size_in_bytes) { if (stmt_ != NULL) return sqlite3_bind_blob(stmt_, index, data, size_in_bytes, SQLITE_STATIC); return SQLITE_MISUSE; } int SQLiteStatement::BindDouble(int index, double data) { if (stmt_ != NULL) return sqlite3_bind_double(stmt_, index, data); return SQLITE_MISUSE; } int SQLiteStatement::BindInt(int index, int data) { if (stmt_ != NULL) return sqlite3_bind_int(stmt_, index, data); return SQLITE_MISUSE; } int SQLiteStatement::BindInt64(int index, int64_t data) { if (stmt_ != NULL) return sqlite3_bind_int64(stmt_, index, data); return SQLITE_MISUSE; } int SQLiteStatement::BindNull(int index) { if (stmt_ != NULL) return sqlite3_bind_null(stmt_, index); return SQLITE_MISUSE; } int SQLiteStatement::BindText(int index, const char* data) { return BindText(index, data, (int)strlen(data)); } int SQLiteStatement::BindText(int index, const char* data, int size_in_bytes) { if (stmt_ != NULL) return sqlite3_bind_text(stmt_, index, data, size_in_bytes, SQLITE_STATIC); return SQLITE_MISUSE; } int SQLiteStatement::BindText16(int index, const wchar_t* data) { return BindText16(index, data, (int)wcslen(data) * sizeof(wchar_t)); } int SQLiteStatement::BindText16(int index, const wchar_t* data, int size_in_bytes) { if (stmt_ != NULL) return sqlite3_bind_text16(stmt_, index, data, size_in_bytes, SQLITE_STATIC); return SQLITE_MISUSE; } int SQLiteStatement::BindValue(int index, const sqlite3_value* data) { if (stmt_ != NULL && data != NULL) return sqlite3_bind_value(stmt_, index, data); return SQLITE_MISUSE; } int SQLiteStatement::BindZeroBlob(int index, int size) { if (stmt_ != NULL) return sqlite3_bind_zeroblob(stmt_, index, size); return SQLITE_MISUSE; } ////////////////////////////////////////////////////////////////////////////// // SQLiteAutoTransaction SQLiteAutoTransaction::SQLiteAutoTransaction(SQLiteDB* db) : db_(db), need_commit_(false) { Begin(); } SQLiteAutoTransaction::~SQLiteAutoTransaction() { if (need_commit_) Commit(); } bool SQLiteAutoTransaction::Begin() { bool result = false; if (db_ && !need_commit_) { if (db_->Query("BEGIN") == SQLITE_OK) result = true; need_commit_ = true; } return result; } bool SQLiteAutoTransaction::Commit() { bool result = 0; if (db_ != NULL) { if (db_->Query("END") == SQLITE_OK) result = true; need_commit_ = false; } return result; } bool SQLiteAutoTransaction::Rollback() { bool result = false; if (db_ != NULL) { if (db_->Query("ROLLBACK") == SQLITE_OK) result = true; need_commit_ = false; } return result; } } // namespace ndb