/*------------------------------------------------------------------------ * (The MIT License) * * Copyright (c) 2008-2011 Rhomobile, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * http://rhomobile.com *------------------------------------------------------------------------*/ #pragma once #include "DBResult.h" #include "DBAttrManager.h" #include "logging/RhoLog.h" #include "common/IRhoCrypt.h" namespace rho{ namespace common{ class CRubyMutex { int m_nLockCount; unsigned long m_valThread, m_valMutex; boolean m_bIgnore; public: CRubyMutex(boolean bIgnore); ~CRubyMutex(); void create(); boolean isMainRubyThread(); void Lock(); void Unlock(); void close(); }; } namespace db{ class CDBAdapter { sqlite3* m_dbHandle; String m_strDbPath, m_strDbVer, m_strDbVerPath; String m_strDbPartition; Hashtable m_mapStatements; common::CRubyMutex m_mxRuby; common::CMutex m_mxDB; boolean m_bUIWaitDB; int m_nTransactionCounter; CDBAttrManager m_attrMgr; static HashtablePtr m_mapDBPartitions; common::CAutoPtr m_ptrCrypt; String m_strCryptKey; struct CDBVersion { String m_strRhoVer; String m_strAppVer; boolean m_bEncrypted; boolean isRhoVerChanged(CDBVersion& dbNewVer) { return m_strRhoVer.compare(dbNewVer.m_strRhoVer) != 0; } boolean isAppVerChanged(CDBVersion& dbNewVer) { return m_strAppVer.compare(dbNewVer.m_strAppVer) != 0; } boolean isDbFormatChanged(CDBVersion& dbNewVer) { return m_bEncrypted != dbNewVer.m_bEncrypted;// || //m_bSqlite != dbNewVer.m_bSqlite; } void fromFile(const String& strFilePath);//throws Exception void toFile(const String& strFilePath)const;//throws Exception CDBVersion() : m_bEncrypted(false){} CDBVersion( String strRhoVer, String strAppVer ) { m_strRhoVer = strRhoVer; m_strAppVer = strAppVer; } }; static const char* USER_PARTITION_NAME(){return "user";} public: DEFINE_LOGCLASS; CDBAdapter(const char* szDBPartition, boolean bNoRubyLock) : m_dbHandle(0), m_strDbPath(""), m_strDbPartition(szDBPartition), m_mxRuby(bNoRubyLock), m_bUIWaitDB(false), m_nTransactionCounter(0) {} ~CDBAdapter(void){} void open (String strDbPath, String strVer, boolean bTemp); void close(boolean bCloseRubyMutex = true); sqlite3* getDbHandle(){ return m_dbHandle; } CDBAttrManager& getAttrMgr(){ return m_attrMgr; } boolean isUIWaitDB()const{ return m_bUIWaitDB; } void Lock(); void Unlock(); boolean isInsideTransaction(){ return m_nTransactionCounter > 0; } const String& getDBPath(){ return m_strDbPath; } common::IRhoCrypt* getCrypt(){ return m_ptrCrypt; } void setCryptKey(String& strKey){ m_strCryptKey = strKey; } static HashtablePtr& getDBPartitions(){ return m_mapDBPartitions; } static void closeAll(); static void initAttrManager(); static boolean isAnyInsideTransaction(); static CDBAdapter& getUserDB(); static CDBAdapter& getDBByHandle(sqlite3* db); static CDBAdapter& getDB(const char* szPartition); static Vector getDBAllPartitionNames(); //static void destroy_tables_allpartitions(const rho::Vector& arIncludeTables, const rho::Vector& arExcludeTables); boolean isTableExist(String strTableName); int prepareSqlStatement(const char* szSql, int nByte, sqlite3_stmt **ppStmt); void bind(sqlite3_stmt* st, int nPos, int val) { sqlite3_bind_int(st, nPos, val); } void bind(sqlite3_stmt* st, int nPos, const String& val) { sqlite3_bind_text(st, nPos, val.c_str(), -1, SQLITE_TRANSIENT); } void bind(sqlite3_stmt* st, int nPos, const char* val) { sqlite3_bind_text(st, nPos, val, -1, SQLITE_TRANSIENT); } void bind(sqlite3_stmt* st, int nPos, uint64 val) { sqlite3_bind_int64(st, nPos, val); } void bind(sqlite3_stmt* st, int nPos, sqlite_int64 val) { sqlite3_bind_int64(st, nPos, val); } void bind(sqlite3_stmt* st, int nPos, unsigned long val) { sqlite3_bind_int(st, nPos, static_cast(val)); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); bind(res->getStatement(), 6, p6); return executeStatement(res, szSt); } DBResultPtr executeSQLReportNonUniqueEx( const char* szSt, Vector& arValues ); template DBResultPtr executeSQLReportNonUnique( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); res->setReportNonUnique(true); return executeStatement(res, szSt); } template DBResultPtr executeSQLReportNonUnique( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); bind(res->getStatement(), 6, p6); bind(res->getStatement(), 7, p7); res->setReportNonUnique(true); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); bind(res->getStatement(), 6, p6); bind(res->getStatement(), 7, p7); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); bind(res->getStatement(), 6, p6); bind(res->getStatement(), 7, p7); bind(res->getStatement(), 8, p8); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9 ) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); bind(res->getStatement(), 2, p2); bind(res->getStatement(), 3, p3); bind(res->getStatement(), 4, p4); bind(res->getStatement(), 5, p5); bind(res->getStatement(), 6, p6); bind(res->getStatement(), 7, p7); bind(res->getStatement(), 8, p8); bind(res->getStatement(), 9, p9); return executeStatement(res, szSt); } template DBResultPtr executeSQL( const char* szSt, T1 p1) { DBResultPtr res = prepareStatement(szSt); if ( res->getStatement() == null ) return res; bind(res->getStatement(), 1, p1); return executeStatement(res, szSt); } DBResultPtr executeSQLEx( const char* szSt, Vector& arValues); DBResultPtr executeSQL( const char* szSt); void executeBatch(const char* szSql, CDBError& error); void startTransaction(); void endTransaction(); void rollback(); void destroy_tables(const rho::Vector& arIncludeTables, const rho::Vector& arExcludeTables); void setBulkSyncDB(String fDataName, String strCryptKey); void createTrigger(const String& strSQL); void dropTrigger(const String& strName); virtual DBResultPtr prepareStatement( const char* szSt ); DBResultPtr executeStatement(common::CAutoPtr& res, const char* szSt); void updateAllAttribChanges(); private: void checkDBVersion(String& strVer); void createSchema(); void createTriggers(); boolean checkDbError(int rc); boolean checkDbErrorEx(int rc, rho::db::CDBResult& res); sqlite3_stmt* createInsertStatement(IDBResult& res, const String& tableName, CDBAdapter& db, String& strInsert); boolean migrateDB(const CDBVersion& dbVer, const CDBVersion& dbNewVer); void copyTable(String tableName, CDBAdapter& dbFrom, CDBAdapter& dbTo); void copyChangedValues(CDBAdapter& db); }; } } #ifdef __cplusplus extern "C" { #endif //__cplusplus void rho_db_init_attr_manager(); int rho_db_open(const char* szDBPath, const char* szDBPartition, void** ppDB); #ifdef __cplusplus }; #endif //__cplusplus