#include #include #include #include #include #include /* for threading */ #include #include #include #include #include "SDDAS_types.h" #include "ant.h" #include "sqlite3.h" #include "mainSQLiteWrap.h" #include "libdbSQLite.h" #include "local.h" /* Definitions */ #define DEFAULT_DB_NAME "sddas" static const int MAX_ATTEMPTS = 5; // These are defined in sqliteCommon.c extern "C" { void create_between_times (sqlite3 *sql); } struct query_data { int num_cols; int num_rows; int row_cursor; bool storedQuery; char **result; }; /* local object variables */ static sqlite3 *_SQL; static std::string _dbName = ""; static SDDAS_BOOL SQLite_local = sTrue; static SDDAS_BOOL _isReadOnly; /* Must be protected by mutexes */ static std::map _resMap; static pthread_mutex_t _sqlite_mutex = PTHREAD_MUTEX_INITIALIZER; static void ClearErrorString () { SetErrorString (""); } static void CommonErrorString (const char *prefix, char *errMsg) { char error [1024]; bool doFree = false; memset (error, 0, sizeof (error)); if (errMsg == NULL) { errMsg = (char *) sqlite3_errmsg (_SQL); } else doFree = true; snprintf (error, 1024, "SQLite DB ERROR: %s - %s!", prefix, errMsg); if (doFree == true) sqlite3_free (errMsg); SetErrorString (error); } static const char *SQLiteDBName (const char *filename) { const char *dbName; if (filename == NULL) { if ((dbName = GetEnv ("SDDAS_DB_NAME")) == NULL) { if (_dbName.empty ()) dbName = DEFAULT_DB_NAME; else dbName = _dbName.c_str (); } } else { dbName = filename; } return (dbName); } static const char *SQLiteDBFileName (const char* filename) { const char *dBNAME = SQLiteDBName (filename); static char DBName [255]; sprintf (DBName, "%s/%s.db3", GetEnv ("SDDAS_DATA"), dBNAME); return DBName; } SDDAS_BOOL SQLite_dbIsLocal () { return SQLite_local; } SDDAS_BOOL SQLite_TestDBIntegrity () { srand (time (NULL)); int rc = sqlite3_busy_timeout (_SQL, rand () % 20 + 1); /* wait a random amount of time if the database is locked! */ assert (rc == 0); SDDAS_BOOL ret_val = sTrue; create_between_times (_SQL); return (ret_val); } SDDAS_BOOL SQLite_dbCreate (const char *dbName) { int rc; std::string dbFilename = SQLiteDBFileName (dbName); make_directory_for_filename (dbFilename.c_str ()); rc = sqlite3_open (dbFilename.c_str (), &_SQL); if (rc != SQLITE_OK) { sqlite3_close (_SQL); _SQL = NULL; CommonErrorString ("Can not open database - sqlite3_open", NULL); return (sFalse); } _dbName = dbName; rc = sqlite3_enable_shared_cache (false); if (rc != SQLITE_OK) { sqlite3_close (_SQL); _SQL = NULL; CommonErrorString ("Can not share database - sqlite3_enable_shared_cache", NULL); return (sFalse); } srand (time (NULL)); rc = sqlite3_busy_timeout (_SQL, rand () % 20 + 1); /* wait a random amount of time if the database is locked! */ assert (rc == 0); return (SQLite_TestDBIntegrity()); } void SQLite_dbSetDatabaseName (const char *dbName) { _dbName = dbName; } const char *SQLite_dbGetDatabaseName () { if (_dbName == "") _dbName = SQLiteDBName (NULL); return _dbName.c_str (); } SDDAS_BOOL SQLite_dbIsReadOnly (const char *tablename) { return (_isReadOnly); } SDDAS_BOOL SQLite_dbInitializeMsg () { /* If _SQL is not NULL, assume the data base is opened! */ if (_SQL == NULL) { /* Create our structure */ assert (sqlite3_threadsafe () == 1); std::string dbFilename = SQLiteDBFileName (NULL); if (access (dbFilename.c_str (), F_OK) == 0) { // check to see if file exists if (access (dbFilename.c_str (), W_OK) == 0) _isReadOnly = sFalse; else _isReadOnly = sTrue; sqlite3_open (dbFilename.c_str (), &_SQL); if (_SQL == NULL) { CommonErrorString ("Can not open IDFS database - sqlite3_open", NULL); return (sFalse); } } else { CommonErrorString ("Cannot find database file!", NULL); return sFalse; } return (SQLite_TestDBIntegrity ()); } /* All is well if it gets this far */ return (sTrue); } void SQLite_dbInitialize () { if (SQLite_dbInitializeMsg () == sFalse) { printf ("SQLite_dbInitialize: %s\n", GetErrorString ()); printf ("\nCheck to make sure SDDAS_DATA is set correctly and that the file (%s.db3) is readable!\n"\ "If you need to create a SQLite database, use the catalog or run \"sqlite_db_create; sqlite_db_init\"\n", SQLiteDBName (NULL)); exit (-1); } } void SQLite_dbClose () { if (_SQL != NULL) { sqlite3_close (_SQL); // sqlite3_shutdown (); _SQL = NULL; pthread_mutex_lock (&_sqlite_mutex); _resMap.clear(); pthread_mutex_unlock (&_sqlite_mutex); } } SDDAS_BOOL SQLite_dbPack() { char *errMsg; if (sqlite3_exec (_SQL, "VACUUM", NULL, NULL, &errMsg) != SQLITE_OK) { CommonErrorString ("SQLite_dbPack - vacuum", errMsg); return sFalse; } return sTrue; } char *SQLite_dbFieldName(void *result, int i) { return ( (char*)(sqlite3_column_name ((sqlite3_stmt *) result, i)) ); } void *SQLite_dbQuery (const char *query_str) { int rc; const char *zTail; sqlite3_stmt *ppStmt; query_data data; assert (_SQL != NULL); // printf ("query_str = %s\n", query_str); rc = sqlite3_prepare_v2 (_SQL, query_str, -1, &ppStmt, &zTail); if ((rc != SQLITE_OK) || (ppStmt == NULL)) { CommonErrorString ("SQLite_dbQuery - sqlite3_prepare_v2", NULL); return (NULL); } else ClearErrorString (); data.storedQuery = false; data.result = NULL; pthread_mutex_lock (&_sqlite_mutex); // printf ("query = %s\n", query_str); _resMap[(void*)ppStmt] = data; pthread_mutex_unlock (&_sqlite_mutex); return ((void *) ppStmt); } void *SQLite_dbQueryStore (const char *query_str) { int rc; char **storedValue = NULL; char *errMsg; query_data data; assert (_SQL != NULL); // printf ("store query_str = %s\n", query_str); int numAttempts = 0; do { pthread_mutex_lock (&_sqlite_mutex); if ((rc = sqlite3_get_table (_SQL, query_str, &data.result, &data.num_rows, &data.num_cols, &errMsg)) != SQLITE_OK) { ++numAttempts; CommonErrorString ("SQLite_dbQueryStore - sqlite3_get_table", errMsg); pthread_mutex_unlock (&_sqlite_mutex); } else ClearErrorString (); } while ((rc != SQLITE_OK) && (numAttempts < MAX_ATTEMPTS)); if ((rc != SQLITE_OK) && (numAttempts == MAX_ATTEMPTS)) return (NULL); data.storedQuery = true; data.row_cursor = data.num_cols; storedValue = (char**) (calloc (data.num_cols, sizeof (char *))); _resMap[(void*)storedValue] = data; pthread_mutex_unlock (&_sqlite_mutex); return ((void *) storedValue); } int SQLite_dbQueryExec (const char *query_str) { int rc = 0; char *errMsg; // printf ("query_str = %s\n", query_str); int numAttempts = 0; do { if ((rc = sqlite3_exec (_SQL, query_str, NULL, NULL, &errMsg)) != SQLITE_OK) { CommonErrorString ("SQLite_dbQueryExec - sqlite3_exec", errMsg); ++numAttempts; rc = 0; } else { rc = 1; ClearErrorString (); } } while ((rc == 0) && (numAttempts < MAX_ATTEMPTS)); return (rc); } unsigned int SQLite_dbBadQuery () { return ((unsigned int) sqlite3_errcode (_SQL)); } void SQLite_dbFreeResult (void *result) { int rc; char **azValue = (char **)result; // printf ("freeResult\n"); pthread_mutex_lock (&_sqlite_mutex); if (_resMap[result].storedQuery == true) { sqlite3_free_table (_resMap[result].result); _resMap[result].storedQuery = false; _resMap[result].result = NULL; free (azValue); } else { if (_resMap[result].result != NULL) { for (int i = 0; i < _resMap[result].num_cols; i++) { free ((char *) _resMap[result].result [i]); } free (_resMap[result].result); _resMap[result].result = NULL; } if ((rc = sqlite3_finalize ((sqlite3_stmt *)result)) != SQLITE_OK) { CommonErrorString ("SQLite_dbFreeResult - sqlite3_finalize", NULL); } else ClearErrorString (); } pthread_mutex_unlock (&_sqlite_mutex); } void *SQLite_dbFetchRow (void *result) { int rc, i, num_cols; char **storedValue = (char **)result; void *ret_val = NULL; // If someone called dbQueryStore, we have a query already // Otherwise, we need to look at the result if (_resMap[result].storedQuery == false) { rc = sqlite3_step ((sqlite3_stmt *)result); if ((rc != SQLITE_ROW) && (rc != SQLITE_DONE)) { CommonErrorString ("SQLite_dbFetchRow - sqlite3_step", NULL); // pthread_mutex_unlock (&_sqlite_mutex); return (NULL); } if (_resMap[result].result != NULL) { for (i = 0; i < _resMap[result].num_cols; i++) { free ((char *) _resMap[result].result [i]); } free (_resMap[result].result); _resMap[result].result = NULL; } _resMap[result].result = NULL; if (rc == SQLITE_DONE) { // pthread_mutex_unlock (&_sqlite_mutex); return (NULL); } num_cols = sqlite3_data_count ((sqlite3_stmt *) result); _resMap[result].num_cols = num_cols; _resMap [result].result = (char**) malloc (num_cols * sizeof (char *)); for (i = 0; i < num_cols; i++) { if((sqlite3_column_text ((sqlite3_stmt *) result, i)) != NULL) _resMap [result].result [i] = strdup((const char*)sqlite3_column_text ((sqlite3_stmt *) result, i)); else _resMap [result].result [i] = strdup(""); } ret_val = (void *)(_resMap [result].result); } else { if (_resMap[result].num_cols > 0) { if (_resMap[result].row_cursor / _resMap[result].num_cols <= _resMap[result].num_rows) { for (rc = 0; rc < _resMap[result].num_cols; rc++) { storedValue [rc] = (_resMap[result].result [_resMap[result].row_cursor + rc]); } ret_val = (void *)storedValue; _resMap[result].row_cursor += _resMap[result].num_cols; } } } return ret_val; } int SQLite_dbNumberRows (void *result) { if (_resMap[result].storedQuery == true) return (_resMap[result].num_rows); else { int rc, ret_val = 0; rc = sqlite3_step ((sqlite3_stmt *)result); while ((rc == SQLITE_BUSY) || (rc == SQLITE_ROW)) { if (rc == SQLITE_ROW) ret_val++; rc = sqlite3_step ((sqlite3_stmt *)result); } rc = sqlite3_reset ((sqlite3_stmt *)result); return (ret_val); } } int SQLite_dbNumberFields (void *result) { if (_resMap[result].storedQuery == true) return (_resMap[result].num_cols); else return (sqlite3_column_count ((sqlite3_stmt *)result)); } SDDAS_BOOL SQLite_dbInitializeRemoteMsg (const char *host, const char *user, const char *passwd, const char *db, const unsigned int port) { SQLite_local = sFalse; return (sFalse); } SDDAS_BOOL SQLite_dbConnected () { if (_SQL == NULL) return sFalse; else return sTrue; } SDDAS_BOOL SQLite_dbTableExists (const char *table_name) { char query_str [1024]; void *result; void *row = NULL; snprintf (query_str, 1024, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'", table_name); if ((result = SQLite_dbQuery (query_str)) != NULL) { row = SQLite_dbFetchRow (result); SQLite_dbFreeResult (result); } return (row != NULL ? sTrue : sFalse); }