COOPY » Guide
version 0.6.5
|
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