solarpowerlog trunk
/home/tobi/workspace/solarpowerlog/src/interfaces/PersistanceStorage/IPersistanceStorage.cpp
Go to the documentation of this file.
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