More support for foreign keys, but still not perfect.
[UnsignedByte.git] / UnsignedByte / Resource / SqliteMgr.cpp
blob8e5234c43a2b779c815428beafed7e98dd36aac9
1 /***************************************************************************
2 * Copyright (C) 2008 by Sverre Rabbelier *
3 * sverre@rabbelier.nl *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "FieldDef.h"
22 #include "TableDef.h"
23 #include "SavableManager.h"
24 #include "SelectionMask.h"
25 #include "TableImpl.h"
26 #include "FieldImpl.h"
27 #include "KeyDef.h"
28 #include "Key.h"
29 #include "ForeignKey.h"
30 #include "Join.h"
32 #include "SqliteMgr.h"
33 #include "DatabaseMgr.h"
34 #include "Actor.h"
35 #include "Statements.h"
36 #include "StatementStrings.h"
37 #include "Exceptions.h"
38 #include "Assert.h"
40 SqliteMgr::SqliteMgr()
42 m_db = DatabaseMgr::Get()->DB();
43 m_odb = m_db->grabdb();
45 Assert(m_db);
46 Assert(m_odb);
49 SqliteMgr::~SqliteMgr()
51 m_db->freedb(m_odb);
54 void SqliteMgr::doInsert(SavableManager* bindable)
56 Assert(bindable);
58 TableImpl* table = bindable->getTable().get();
59 Assert(table);
61 sqlite3_stmt* insert = getInsertStmt(table);
62 Assert(insert);
64 sqlite3_reset(insert);
66 if(!table->hasSingularPrimaryKey())
67 bindable->bindKeys(m_odb->db, insert);
69 doStatement(insert);
71 if(table->hasSingularPrimaryKey())
72 bindable->parseInsert(m_odb->db);
74 commit(table);
77 void SqliteMgr::doErase(SavableManager* bindable)
79 Assert(bindable);
81 TableImpl* table = bindable->getTable().get();
82 Assert(table);
84 sqlite3_stmt* erase = getEraseStmt(table);
85 Assert(erase);
87 sqlite3_reset(erase);
89 bindable->bindKeys(m_odb->db, erase);
90 doStatement(erase);
92 commit(table);
95 void SqliteMgr::doUpdate(SavableManager* bindable)
97 Assert(bindable);
99 TableImpl* table = bindable->getTable().get();
100 Assert(table);
102 sqlite3_stmt* update = getUpdateStmt(table);
103 Assert(update);
105 sqlite3_reset(update);
107 bindable->bindUpdate(m_odb->db, update);
108 doStatement(update);
110 commit(table);
113 void SqliteMgr::doSelect(SavableManager* bindable)
115 Assert(bindable);
117 TableImpl* table = bindable->getTable().get();
118 Assert(table);
120 sqlite3_stmt* select = getSelectStmt(table);
121 Assert(select);
123 sqlite3_reset(select);
125 bindable->bindKeys(m_odb->db, select);
126 bool row = doStatement(select);
127 if(row)
128 bindable->parseSelect(select);
129 else
130 throw RowNotFoundException("SqliteMgr::doSelect(), no row.");
133 void SqliteMgr::doLookup(SavableManager* bindable, FieldPtr field)
135 Assert(bindable);
136 Assert(field);
138 TableImpl* table = bindable->getTable().get();
139 Assert(table);
141 sqlite3_stmt* lookup = getLookupStmt(table, field);
142 Assert(lookup);
144 sqlite3_reset(lookup);
146 bindable->bindLookup(m_odb->db, lookup);
147 bool row = doStatement(lookup);
148 if(row)
150 bindable->parseLookup(lookup);
151 doSelect(bindable);
153 else
154 throw RowNotFoundException("SqliteMgr::doLookup(), no row.");
157 void SqliteMgr::doForEach(TableImpl* table, Actor& act)
159 Assert(table);
161 sqlite3_stmt* forEach = getForEachStmt(table);
162 Assert(forEach);
164 sqlite3_reset(forEach);
166 bool good = true;
167 for(int i = 0; good; i++)
169 good = doStatement(forEach);
170 if(good)
171 act.parseRow(forEach, table);
175 void SqliteMgr::doSelectMulti(SelectionMask* mask)
177 Assert(mask);
179 sqlite3_stmt* selectMulti = getSelectMultiStmt(mask);
180 Assert(selectMulti);
182 sqlite3_reset(selectMulti);
184 mask->bindSelectMulti(m_odb->db, selectMulti);
186 bool good = true;
187 for(int i = 0; good; i++)
189 good = doStatement(selectMulti);
190 if(good)
191 mask->parseRow(selectMulti);
194 sqlite3_finalize(selectMulti);
197 void SqliteMgr::commit(TableImpl* table)
199 Assert(table);
201 //StatementsPtr statements = getStatements(table);
202 //statements->commit();
203 table->modify();
204 m_statements.clear();
208 bool SqliteMgr::doStatement(sqlite3_stmt* stmt)
210 Assert(stmt);
212 int rc = sqlite3_step(stmt);
214 switch(rc) {
215 case SQLITE_DONE:
216 return false;
217 case SQLITE_ROW:
218 return true;
221 throw SqliteError(m_odb->db);
224 StatementsPtr SqliteMgr::getStatements(TableImpl* table)
226 Assert(table);
228 StatementsPtr statements = m_statements[table];
229 if(statements)
230 return statements;
232 statements = StatementsPtr(new Statements());
234 m_statements[table] = statements;
235 return statements;
238 StatementStringsPtr SqliteMgr::getStatementStrings(TableImpl* table)
240 Assert(table);
242 StatementStringsPtr statements = m_statementstrings[table];
243 if(statements)
244 return statements;
246 statements = StatementStringsPtr(new StatementStrings());
248 m_statementstrings[table] = statements;
249 return statements;
252 sqlite3_stmt* SqliteMgr::getInsertStmt(TableImpl* table)
254 Assert(table);
256 StatementsPtr statements = getStatements(table);
257 sqlite3_stmt* statement = statements->getInsert();
258 if(statement)
259 return statement;
261 std::string sql;
263 StatementStringsPtr statementstrings = getStatementStrings(table);
264 cstring statementstring = statementstrings->getInsert();
266 if(statementstring.size() != 0)
268 sql = statementstring;
270 else
272 sql.append("INSERT INTO ");
273 sql.append(table->tableName());
274 sql.append(" (");
275 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
277 if(it != table->keybegin())
278 sql.append(", ");
280 sql.append(it->first);
282 sql.append(") VALUES(");
283 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
285 if(it != table->keybegin())
286 sql.append(", ");
288 if(table->hasSingularPrimaryKey())
289 sql.append("NULL");
290 else
291 sql.append("?");
293 sql.append(");");
295 statementstrings->setInsert(sql);
298 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
300 if(errorcode != SQLITE_OK)
301 throw SqliteError(m_odb->db);
303 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
305 statements->setInsert(statement);
306 return statement;
309 sqlite3_stmt* SqliteMgr::getEraseStmt(TableImpl* table)
311 StatementsPtr statements = getStatements(table);
312 sqlite3_stmt* statement = statements->getErase();
313 if(statement)
314 return statement;
316 std::string sql;
318 StatementStringsPtr statementstrings = getStatementStrings(table);
319 cstring statementstring = statementstrings->getErase();
321 if(statementstring.size() != 0)
323 sql = statementstring;
325 else
327 sql.append("DELETE ");
328 sql.append(table->tableName());
329 sql.append(" WHERE ");
330 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
332 if(it != table->keybegin())
333 sql.append(", ");
335 sql.append(it->first);
336 sql.append("=?");
338 sql.append(";");
340 statementstrings->setErase(sql);
343 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
345 if(errorcode != SQLITE_OK)
346 throw SqliteError(m_odb->db);
348 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
350 statements->setErase(statement);
351 return statement;
354 sqlite3_stmt* SqliteMgr::getUpdateStmt(TableImpl* table)
356 StatementsPtr statements = getStatements(table);
357 sqlite3_stmt* statement = statements->getUpdate();
358 if(statement)
359 return statement;
361 std::string sql;
363 StatementStringsPtr statementstrings = getStatementStrings(table);
364 cstring statementstring = statementstrings->getUpdate();
366 if(statementstring.size() != 0)
368 sql = statementstring;
370 else
372 sql.append("UPDATE ");
373 sql.append(table->tableName());
374 sql.append(" SET ");
375 for(FieldDefVector::const_iterator it = table->defbegin(); it != table->defend(); it++)
377 if(it != table->defbegin())
378 sql.append(", ");
380 sql.append((*it)->getName());
381 sql.append("=?");
383 sql.append(" WHERE ");
384 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
386 if(it != table->keybegin())
387 sql.append(", ");
389 sql.append(it->first);
390 sql.append("=?");
392 sql.append(";");
394 statementstrings->setUpdate(sql);
397 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
399 if(errorcode != SQLITE_OK)
400 throw SqliteError(m_odb->db);
402 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
404 statements->setUpdate(statement);
405 return statement;
408 sqlite3_stmt* SqliteMgr::getSelectStmt(TableImpl* table)
410 StatementsPtr statements = getStatements(table);
411 sqlite3_stmt* statement = statements->getSelect();
412 if(statement)
413 return statement;
415 std::string sql;
417 StatementStringsPtr statementstrings = getStatementStrings(table);
418 cstring statementstring = statementstrings->getSelect();
420 if(statementstring.size() != 0)
422 sql = statementstring;
424 else
426 sql.append("SELECT ");
427 for(FieldDefVector::const_iterator it = table->defbegin(); it != table->defend(); it++)
429 if(it != table->defbegin())
430 sql.append(", ");
432 sql.append((*it)->getName());
436 * Prevent queries in the form "SELECT FROM ....", this is for tables that consist of only primary keys.
438 if(!table->defsize())
439 sql.append("*");
441 sql.append(" FROM ");
442 sql.append(table->tableName());
443 sql.append(" WHERE ");
445 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
447 if(it != table->keybegin())
448 sql.append(" AND ");
450 sql.append(it->first);
451 sql.append("=?");
453 sql.append(";");
455 statementstrings->setSelect(sql);
458 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
460 if(errorcode != SQLITE_OK)
461 throw SqliteError(m_odb->db);
463 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
465 statements->setSelect(statement);
466 return statement;
469 sqlite3_stmt* SqliteMgr::getLookupStmt(TableImpl* table, FieldPtr field)
471 StatementsPtr statements = getStatements(table);
472 sqlite3_stmt* statement = statements->getLookup(field);
473 if(statement)
474 return statement;
476 std::string sql;
478 StatementStringsPtr statementstrings = getStatementStrings(table);
479 cstring statementstring = statementstrings->getLookup(field);
481 if(statementstring.size() != 0)
483 sql = statementstring;
485 else
487 sql.append("SELECT ");
488 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
490 if(it != table->keybegin())
491 sql.append(", ");
493 sql.append(it->first);
495 sql.append(" FROM ");
496 sql.append(table->tableName());
497 sql.append(" WHERE ");
498 sql.append(field->getName());
499 sql.append("=?");
500 sql.append(";");
502 statementstrings->setLookup(field, sql);
505 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
507 if(errorcode != SQLITE_OK)
508 throw SqliteError(m_odb->db);
510 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
512 statements->setLookup(field, statement);
513 return statement;
516 sqlite3_stmt* SqliteMgr::getForEachStmt(TableImpl* table)
518 StatementsPtr statements = getStatements(table);
519 sqlite3_stmt* statement = statements->getForEach();
520 if(statement)
521 return statement;
523 std::string sql;
525 StatementStringsPtr statementstrings = getStatementStrings(table);
526 cstring statementstring = statementstrings->getForEach();
528 if(statementstring.size() != 0)
530 sql = statementstring;
532 else
534 sql.append("SELECT ");
535 bool comspace = false;
536 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
538 if(comspace)
539 sql.append(", ");
541 sql.append(it->first);
542 comspace = true;
544 for(FieldDefVector::const_iterator it = table->defbegin(); it != table->defend(); it++)
546 if(comspace)
547 sql.append(", ");
549 sql.append((*it)->getName());
550 comspace = true;
553 sql.append(" FROM ");
554 sql.append(table->tableName());
555 sql.append(";");
557 statementstrings->setForEach(sql);
560 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
562 if(errorcode != SQLITE_OK)
563 throw SqliteError(m_odb->db);
565 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
567 statements->setForEach(statement);
568 return statement;
571 sqlite3_stmt* SqliteMgr::getSelectMultiStmt(SelectionMask* mask)
573 Assert(mask);
575 std::string sql;
576 sqlite3_stmt* statement;
578 TableImplPtr table = mask->getTable();
579 Assert(table);
581 sql.append("SELECT ");
582 bool comspace = false;
583 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
585 if(comspace)
586 sql.append(", ");
588 sql.append(it->first);
589 comspace = true;
591 for(FieldDefVector::const_iterator it = table->defbegin(); it != table->defend(); it++)
593 if(comspace)
594 sql.append(", ");
596 sql.append((*it)->getName());
597 comspace = true;
601 * Prevent queries in the form "SELECT FROM ....", this is for tables that consist of only primary keys.
603 if(!table->defsize())
604 sql.append("*");
606 sql.append(" FROM ");
607 sql.append(table->tableName());
610 * Allow for queries that retreive data from foreigh tables "SELECT a, b, c, FROM Table INNER JOIN Other ON tableid = fkTable WHERE d = 5;"
612 for(Joins::const_iterator it = mask->joinsbegin(); it != mask->joinsend(); it++)
614 JoinPtr join = *it;
615 sql.append(" INNER JOIN ");
616 sql.append(join->getJoinTable()->tableName());
617 sql.append(" ON ");
618 sql.append(join->getNativeKey()->getName());
619 sql.append(" = ");
620 sql.append(join->getForeignKey()->getName());
624 * Prevent queries in the form "SELECT a, b, c FROM table WHERE ;", this is for the unmasked selection.
626 if(mask->size())
627 sql.append(" WHERE ");
629 for(Strings::const_iterator it = mask->begin(); it != mask->end(); it++)
631 if(it != mask->begin())
632 sql.append(" AND ");
634 sql.append(*it);
635 sql.append("=?");
637 sql.append(";");
639 printf("SQL: '%s'.\n", sql.c_str());
641 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
643 if(errorcode != SQLITE_OK)
644 throw SqliteError(m_odb->db);
646 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
648 return statement;
652 std::string SqliteMgr::tableQuery(TableDefPtr table) const
654 Assert(table);
656 std::string result;
657 result.append("SELECT type FROM sqlite_master WHERE tbl_name='");
658 result.append(table->tableName());
659 result.append("' and sql='");
661 result.append(creationQuery(table, true));
663 result.append("';");
665 return result;
669 "CREATE TABLE IF NOT EXISTS %s("
670 "%s INTEGER PRIMARY KEY AUTOINCREMENT"
671 ",versiontext TEXT"
672 ",grantgroup INTEGER RESTRAINT grantgroup DEFAULT 1"
673 ");",
675 std::string SqliteMgr::creationQuery(TableDefPtr table, bool verify) const
677 Assert(table);
679 std::string result;
681 if(verify)
682 result.append("CREATE TABLE ");
683 else
684 result.append("CREATE TABLE IF NOT EXISTS ");
686 result.append(table->tableName());
687 result.append("(");
689 bool comma = false;
691 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
693 if(table->hasSingularPrimaryKey() && it == table->keybegin())
695 result.append(it->first);
696 result.append(" INTEGER PRIMARY KEY AUTOINCREMENT, ");
697 continue;
700 if(comma)
701 result.append(", ");
703 result.append(it->first);
704 result.append(" INTEGER");
705 comma = true;
708 for(FieldDefVector::const_iterator it = table->defbegin(); it != table->defend(); it++)
710 if(comma)
711 result.append(", ");
713 result.append(creationString(*it));
714 comma = true;
717 if(!table->hasSingularPrimaryKey())
719 result.append(", PRIMARY KEY(");
720 for(TableMap::const_iterator it = table->keybegin(); it != table->keyend(); it++)
722 if(it != table->keybegin())
723 result.append(", ");
725 result.append(it->first);
727 result.append(")");
730 if(verify)
731 result.append(")");
732 else
733 result.append(");");
735 return result;
738 std::string SqliteMgr::creationString(FieldDefPtr field) const
740 Assert(field);
742 std::string result = field->getName();
744 if(field->isText())
745 result.append(" TEXT");
746 else
747 result.append(" INTEGER");
749 if(field->getDefaultValue().size() != 0)
751 result.append(" RESTRAINT ");
752 result.append(field->getName());
753 result.append(" DEFAULT ");
755 if(field->isText())
756 result.append("'");
757 result.append(field->getDefaultValue());
758 if(field->isText())
759 result.append("'");
762 return result;