COOPY » Guide  version 0.6.5
/home/paulfitz/cvs/coopy_scm/coopy/src/libremotesql/RemoteSqlSheet.cpp
Go to the documentation of this file.
00001 #include <coopy/RemoteSqlSheet.h>
00002 #include <coopy/RemoteSqlTextBook.h>
00003 #include <coopy/Dbg.h>
00004 #include <coopy/MergeOutputSqlDiff.h>
00005 
00006 #include <sqlxx.h>
00007 #include <strutilsxx.h>
00008 
00009 #include <algorithm>
00010 
00011 using namespace std;
00012 using namespace coopy::store;
00013 using namespace coopy::store::remotesql;
00014 using namespace coopy::cmp;
00015 using namespace sqlxx;
00016 
00017 #define SQL_CONNECTION(x) (*((CSQL*)((x)->getSqlInterface())))
00018 
00019 RemoteSqlSheet::RemoteSqlSheet(RemoteSqlTextBook *owner, const char *name) {
00020   implementation = NULL;
00021   w = h = 0;
00022   book = owner;
00023   this->name = name;
00024   schema = new RemoteSqlSheetSchema;
00025   COOPY_MEMORY(schema);
00026   schema->sheet = this;
00027 
00029   // Check columns
00030   
00031   CSQL& SQL = SQL_CONNECTION(book);
00032 
00033   {
00034     string query = string("SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, EXTRA, COLUMN_KEY FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=")+quote(name) + " AND TABLE_SCHEMA=" + quote(book->getDatabaseName());
00035     dbg_printf("Query is %s\n", query.c_str());
00036     CSQLResult *result = SQL.openQuery(query);
00037     if (result==NULL) return;
00038     while (result->fetch()) {
00039       //printf("Got %s\n", result->get(0).c_str());
00040       col2sql.push_back(result->get(0));
00041       col2type.push_back(result->get(1));
00042       col2nullable.push_back(result->get(2)=="YES");
00043       col2autoinc.push_back(result->get(3)=="auto_increment");
00044       w++;
00045     }
00046     SQL.closeQuery(result);
00047   }
00048 
00049   {
00050     string query = string("SELECT k.column_name FROM information_schema.table_constraints t JOIN information_schema.key_column_usage k USING(constraint_name,table_schema,table_name) WHERE t.constraint_type='PRIMARY KEY' AND t.table_schema=") + quote(book->getDatabaseName()) + " AND t.table_name=" + quote(name);
00051     dbg_printf("Query is %s\n", query.c_str());
00052     CSQLResult *result = SQL.openQuery(query);
00053     if (result==NULL) return;
00054     map<string,int> pks;
00055     while (result->fetch()) {
00056       //printf("Got %s\n", result->get(0).c_str());
00057       pks[result->get(0)] = 1;
00058     }
00059     SQL.closeQuery(result);
00060     for (int i=0; i<(int)col2sql.size(); i++) {
00061       col2pk.push_back(pks.find(col2sql[i])!=pks.end());
00062       //printf("Primary key? %s %d\n", col2sql[i].c_str(), (bool)col2pk[i]);
00063     }
00064   }
00065 
00066   /*
00067   {
00068     string query = string("SELECT * FROM ")+name;
00069     //printf("Query is %s\n", query.c_str());
00070     CSQLResult *result = SQL.openQuery(query);
00071     SQL.closeQuery(result);
00072   }
00073   */
00074 
00076   // Check rows
00077 
00078   {
00079     string query = string("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ") + quote(book->getDatabaseName()) + " AND TABLE_NAME = " + quote(name) + " AND COLUMN_KEY = 'PRI'";
00080     dbg_printf("Query is %s\n", query.c_str());
00081     CSQLResult *result = SQL.openQuery(query);
00082     while (result->fetch()) {
00083       //printf("Got %s\n", result->get(0).c_str());
00084       keys.push_back(result->get(0));
00085       //h++;
00086     }
00087   }
00088 
00089   if (keys.size()==0) {
00090     keys = col2sql;
00091   }
00092 
00093   string key_list = "";
00094   for (vector<string>::iterator it=keys.begin(); it!=keys.end(); it++) {
00095     int at = find(col2sql.begin(),col2sql.end(),*it)-col2sql.begin();
00096     key_cols.push_back(at);
00097     if (key_list!="") key_list += ", ";
00098     key_list += *it;
00099   }
00100   int k = (int)keys.size();
00101 
00102   cache.resize(w,0,"");
00103   cacheFlag.resize(w,0,0);
00104 
00105   if (key_list.length()==0) {
00106     fprintf(stderr,"mysql table is unexpectedly empty\n");
00107     return;
00108   }
00109 
00110   {
00111     string query = string("SELECT * FROM ") + name + " ORDER BY " + key_list;
00112     dbg_printf("Query is %s\n", query.c_str());
00113     CSQLResult *result = SQL.openQuery(query);
00114     while (result->fetch()) {
00115       vector<string> accum;
00116       cache.reheight(h+1);
00117       cacheFlag.reheight(h+1);
00118       for (int i=0; i<w; i++) {
00119         //printf("Got %d,%d:\n", i, h);
00120         //printf("Got %d,%d %s\n", i, h, result->get(i).c_str());
00121         if (result->isNull(i)) {
00122           cacheFlag.cell(i,h) = 1;
00123         }
00124         cache.cell(i,h) = result->get(i);
00125       }
00126       for (int i=0; i<k; i++) {
00127         //printf("Got %s\n", result->get(i).c_str());
00128         accum.push_back(result->get(key_cols[i]));
00129       }
00130       row2sql.push_back(accum);
00131       h++;
00132     }
00133     SQL.closeQuery(result);
00134   }
00135 }
00136 
00137 RemoteSqlSheet::~RemoteSqlSheet() {
00138   if (schema!=NULL) delete schema;
00139   schema = NULL;
00140 }
00141 
00142 SheetSchema *RemoteSqlSheet::getSchema() const {
00143   return schema;
00144 }
00145 
00146 
00147 std::string RemoteSqlSheet::cellString(int x, int y) const {
00148   bool tmp;
00149   return cellString(x,y,tmp);
00150 }
00151 
00152 std::string RemoteSqlSheet::cellString(int x, int y, bool& escaped) const {
00153   escaped = false;
00154   const unsigned char *f = cacheFlag.pcell_const(x,y);
00155   if (f!=NULL) {
00156     escaped = true;
00157     return "NULL";
00158   }
00159   const string *c = cache.pcell_const(x,y);
00160   if (c!=NULL) {
00161     return *c;
00162   }
00163 
00164   // starting with a COMPLETELY brain-dead implementation
00165 
00166   CSQL& SQL = SQL_CONNECTION(book);
00167 
00168   string query = string("SELECT * FROM ") + name + " WHERE ";
00169   const vector<string>& idx = row2sql[y];
00170   for (int i=0; i<(int)keys.size(); i++) {
00171     if (i!=0) {
00172       query += " AND ";
00173     }
00174     query += keys[i];
00175     query += " = ";
00176     query += quote(idx[i]);
00177   }
00178   //printf("<%d/%d> Query %s\n", x, y, query.c_str());
00179   string out;
00180   CSQLResult *result = SQL.openQuery(query);
00181   if (result==NULL) return "";
00182   if (result->fetch()) {
00183     out = result->get(x);
00184   }
00185   SQL.closeQuery(result);
00186   return out;
00187 }
00188 
00189 bool RemoteSqlSheet::cellString(int x, int y, const std::string& str, bool escaped) {
00190   // starting with a COMPLETELY brain-dead implementation
00191 
00192   cache.cell(x,y) = str;
00193   if (escaped) {
00194     cacheFlag.cell(x,y) = true;
00195   } else {
00196     cacheFlag.remove(x,y);
00197   }
00198 
00199   CSQL& SQL = SQL_CONNECTION(book);
00200 
00201   string query = string("UPDATE ") + name + " SET " +
00202     col2sql[x] + " = " +
00203     (escaped?"NULL":quote(str)) +
00204     " WHERE ";
00205   //printf("Making query %s\n", query.c_str());
00206   const vector<string>& idx = row2sql[y];
00207   bool index_change = false;
00208   for (int i=0; i<(int)keys.size(); i++) {
00209     //printf("Making query %s\n", query.c_str());
00210     if (key_cols[i]==x) {
00211       index_change = true;
00212     }
00213     if (i!=0) {
00214       query += " AND ";
00215     }
00216     query += keys[i];
00217     query += " = ";
00218     query += quote(idx[i]);
00219   }
00220   if (index_change) {
00221     printf("Mysql code can't deal with change in primary key yet\n");
00222     exit(1);
00223   }
00224   //printf("<%d/%d> Query %s\n", x, y, query.c_str());
00225   SQL.execQuery(query);
00226   return true;
00227 }
00228 
00229 
00230 ColumnRef RemoteSqlSheet::moveColumn(const ColumnRef& src, 
00231                                      const ColumnRef& base) {
00232   return ColumnRef();
00233 }
00234 
00235 bool RemoteSqlSheet::deleteColumn(const ColumnRef& column) {
00236   return false;
00237 }
00238 
00239 ColumnRef RemoteSqlSheet::insertColumn(const ColumnRef& base) {
00240   return ColumnRef();
00241 }
00242 
00243 ColumnRef RemoteSqlSheet::insertColumn(const ColumnRef& base, 
00244                                        const ColumnInfo& info) {
00245   return ColumnRef();
00246 }
00247 
00248 bool RemoteSqlSheet::modifyColumn(const ColumnRef& base, 
00249                                   const ColumnInfo& info) {
00250   return false;
00251 }
00252 
00253 RowRef RemoteSqlSheet::insertRow(const RowRef& base) {
00254   return RowRef();
00255 }
00256 
00257 bool RemoteSqlSheet::deleteRow(const RowRef& src) {
00258   return false;
00259 }
00260 
00261 
00262 bool RemoteSqlSheet::applyRowCache(const RowCache& cache, int row,
00263                                    SheetCell *result) {
00264   CSQL& SQL = SQL_CONNECTION(book);
00265 
00266   RowChange rc;
00267   for (int i=0; i<(int)cache.flags.size(); i++) {
00268     if (cache.flags[i]) {
00269       rc.val[col2sql[i]] = cache.cells[i];
00270     }
00271   }
00272   SqlText text = MergeOutputSqlDiff::getText(rc,name.c_str());
00273 
00274   string query = string("INSERT INTO ") + text.name + " (" + text.val_columns + ") VALUES (" + text.val_values + ")";
00275   string out;
00276   CSQLResult *result2 = SQL.openQuery(query);
00277   if (result2==NULL) return false;
00278   SQL.closeQuery(result2);
00279 
00280   static bool warned = false;
00281   if (!warned) {
00282     fprintf(stderr,"Warning: remote SQL insertions are currently incomplete\n");
00283     warned = true;
00284   }
00285 
00286   h++;
00287   return true;
00288 }
00289 
00290 
00291 bool RemoteSqlSheet::deleteData(int offset) {
00292   if (offset!=0) DataSheet::deleteData(offset);
00293 
00294   cache.clear();
00295   cacheFlag.clear();
00296   h = 0;
00297 
00298   CSQL& SQL = SQL_CONNECTION(book);
00299 
00300   string query = string("DELETE FROM ") + name + " WHERE 1";
00301   dbg_printf("Query is %s\n", query.c_str());
00302   CSQLResult *result = SQL.openQuery(query);
00303   if (result==NULL) return false;
00304   SQL.closeQuery(result);
00305   return true;
00306 }
00307 
00308 
00309 bool RemoteSqlSheet::beginTransaction() {
00310   CSQL& SQL = SQL_CONNECTION(book);
00311   dbg_printf("START TRANSACTION\n");
00312   SQL.execQuery("START TRANSACTION");
00313   return true;
00314 }
00315 
00316 bool RemoteSqlSheet::endTransaction() {
00317   CSQL& SQL = SQL_CONNECTION(book);
00318   dbg_printf("COMMIT\n");
00319   return true;
00320 }
00321 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines