|
solarpowerlog trunk
|
00001 /* 00002 * IPersistanceStorage.cpp 00003 * 00004 * Created on: Jan 18, 2010 00005 * Author: tobi 00006 */ 00007 00008 #include "IPersistanceStorage.h" 00009 #include "QueryHelper.h" 00010 #include <assert.h> 00011 00012 #include <iostream> 00013 00014 #include "configuration/CConfigHelper.h" 00015 00016 IPersistanceStorage::IPersistanceStorage(std::string &configname, 00017 std::string &table) : 00018 config(configname), table(table) 00019 { 00020 00021 std::string tmp; 00022 session_ready = false; 00023 00024 // get configuration. 00025 CConfigHelper cfg(configname); 00026 CConfigHelper cfg_root("application"); 00027 00028 if (!(cfg.GetConfig("dbi_driver", tmp) || cfg_root.GetConfig("dbi_driver", 00029 tmp))) { 00030 session.driver(tmp); 00031 } 00032 00033 // Check for configuration array. 00034 CConfigHelper dbi_cfg1(configname + ".dbi_db_cfg"); 00035 CConfigHelper dbi_cfg2("application.dbi_db_cfg"); 00036 00037 CConfigHelper &dbi_cfg = dbi_cfg1; 00038 if (!dbi_cfg1.GetConfigArray(0, 0, tmp)) { 00039 dbi_cfg = dbi_cfg2; 00040 } 00041 00042 std::string value; 00043 long numericvalue; 00044 for (int i = 0;; i++) { 00045 if (dbi_cfg.GetConfigArray(i, 0, tmp)) { 00046 if (dbi_cfg.GetConfigArray(i, 1, numericvalue)) { 00047 session.param(tmp, numericvalue); 00048 } else if (dbi_cfg.GetConfigArray(i, 1, value)) { 00049 session.param(tmp, value); 00050 if (tmp == "dbname") 00051 dbname = tmp; 00052 } else { 00053 // FIXME: Not integer nor string.... 00054 // Do error reporting. 00055 continue; 00056 } 00057 00058 } else 00059 break; 00060 } 00061 00062 } 00063 00064 IPersistanceStorage::~IPersistanceStorage() 00065 { 00066 session.close(); 00067 // TODO Auto-generated destructor stub 00068 } 00069 00070 void IPersistanceStorage::CheckAndCreateTable(void) 00071 { 00072 00073 assert(table_spec.size()); 00074 00075 // Check if table exists. 00076 if (!session_ready) { 00077 try { 00078 session.connect(); 00079 session_ready = true; 00080 } catch (...) { 00081 // FIXME: Error reporting 00082 return; 00083 } 00084 } 00085 00086 dbi_conn conn = session.get_dbi_conn(); 00087 dbi_result res = dbi_conn_get_table_list(conn, dbname.c_str(), 00088 table.c_str()); 00089 00090 unsigned int i = dbi_result_get_numfields(res); 00091 if (i == 0 || i == DBI_FIELD_ERROR) { 00092 // Table not there. 00093 std::string query = "CREATE TABLE " + table + " ( "; 00094 for (unsigned int j = 0; j < table_spec.size(); j++) { 00095 if (j) 00096 query += ","; 00097 query += " ? ? "; 00098 } 00099 query += ")"; 00100 session.query(query); 00101 00102 std::map<std::string, dbtypes>::iterator it = table_spec.begin(); 00103 for (it = table_spec.begin(); it != table_spec.end(); it++) { 00104 session.bind((*it).first); 00105 00106 switch ((*it).second) 00107 { 00108 case db_integer: 00109 case db_unsignedinteger: 00110 session.bind("INTEGER"); 00111 break; 00112 00113 case db_longlong: 00114 case db_unsignedlonglong: 00115 session.bind("BIGINT"); 00116 break; 00117 00118 case db_decimal: 00119 session.bind("FLOAT"); 00120 break; 00121 00122 case db_tm: 00123 session.bind("TIMESTAMP"); 00124 break; 00125 00126 case db_string: 00127 session.bind("VARCHAR(255)"); 00128 break; 00129 00130 } 00131 } 00132 00133 // create table syntax done. 00134 try { 00135 session.exec(); 00136 } catch (dbixx::dbixx_error e) { 00137 // FIXME: Error reporting! 00138 cerr << "Query Error " << e.what() << endl; 00139 } 00140 return; 00141 } 00142 00143 // table exists, check if every column is there. 00144 // - First do a query on the table getting (one) result with every table. 00145 // - 2nd iterate over the fieldnames, and check against memorize them (i.e in a list) 00146 // - 3rd find out if any field is missing (iterate over map and check in list if exists) 00147 // - 4th create ALTER TABLE syntax for missing fields. 00148 00149 00150 // The map is quicker in search, so we can live with the memory overhead imposed here. 00151 // as a speed trade-off. 00152 std::map<std::string, dbtypes> missing_columns = table_spec; 00153 00154 conn = session.get_dbi_conn(); 00155 res = dbi_conn_queryf(conn, "SELECT * FROM %s LIMIT 1", table.c_str()); 00156 if (!res) { 00157 // FIXME Error Handling 00158 cerr << "libdbi: SELECT * FROM " << table << " LIMIT 1 returned NULL"; 00159 return; 00160 } 00161 00162 unsigned int num_columns = dbi_result_get_numfields(res); 00163 if (num_columns == 0 || num_columns == DBI_FIELD_ERROR) { 00164 // FIXME Error Handling 00165 cerr << "libdbi: SELECT * FROM " << table 00166 << " LIMIT 1 returned no columns or DBU_FIELD_ERROR"; 00167 num_columns = 0; 00168 } 00169 00170 // 2 and 3 00171 for (unsigned int i = 1; i <= num_columns; i++) { 00172 const char *tmp; 00173 tmp = dbi_result_get_field_name(res, i); 00174 if (missing_columns.erase(std::string(tmp))) { 00175 // FIXME: Here some place of debug code. 00176 cerr << "TABLE CONTAINS ALREADY " << tmp << endl; 00177 } 00178 } 00179 00180 // 4th 00181 if (!missing_columns.empty()) { 00182 std::string query = "ALTER TABLE ? ADD COLUMN "; 00183 if (missing_columns.size() > 1) 00184 query += "("; 00185 std::map<std::string, dbtypes>::iterator it; 00186 for (unsigned int i = 0; i < missing_columns.size(); i++) { 00187 if (i) 00188 query += ","; 00189 query += " ? ?"; 00190 } 00191 session << query; 00192 00193 for (it = missing_columns.begin(); it != missing_columns.end(); it++) { 00194 session.bind((*it).first); 00195 00196 switch ((*it).second) 00197 { 00198 case db_integer: 00199 case db_unsignedinteger: 00200 session.bind("INTEGER"); 00201 break; 00202 00203 case db_longlong: 00204 case db_unsignedlonglong: 00205 session.bind("BIGINT"); 00206 break; 00207 00208 case db_decimal: 00209 session.bind("FLOAT"); 00210 break; 00211 00212 case db_tm: 00213 session.bind("TIMESTAMP"); 00214 break; 00215 00216 case db_string: 00217 session.bind("VARCHAR(255)"); 00218 break; 00219 00220 } 00221 } 00222 00223 if (missing_columns.size() > 1) 00224 query += ")"; 00225 00226 try { 00227 session.exec(); 00228 } catch (dbixx::dbixx_error e) { 00229 // FIXME: Error reporting! 00230 cerr << "Query Error " << e.what() << endl; 00231 } 00232 00233 } 00234 00235 } 00236