Chunk is purely a wrapper class, any 'state variables', like 'characters in room...
[UnsignedByte.git] / src / DAL / SqliteMgr.cpp
blobde58a13142ba7b2af96bec41a5b7f336d77bf4e2
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 "SavableManager.h"
22 #include "SavableManagers.h"
23 #include "SelectionMask.h"
24 #include "TableImpl.h"
25 #include "FieldImpl.h"
26 #include "KeyImpl.h"
27 #include "KeyValue.h"
28 #include "Join.h"
30 #include "SqliteMgr.h"
31 #include "DatabaseMgr.h"
32 #include "Statements.h"
33 #include "StatementStrings.h"
34 #include "Assert.h"
36 SqliteMgr::SqliteMgr()
38 m_db = DatabaseMgr::Get()->DB();
39 m_odb = m_db->grabdb();
41 Assert(m_db);
42 Assert(m_odb);
45 SqliteMgr::~SqliteMgr()
47 m_db->freedb(m_odb);
50 void SqliteMgr::doInsert(SavableManager* bindable)
52 Assert(bindable);
54 TableImpl* table = bindable->getTable().get();
55 Assert(table);
57 sqlite3_stmt* insert = getInsertStmt(table);
58 Assert(insert);
60 sqlite3_reset(insert);
62 if(table->primarykeysize() > 1)
63 bindable->bindKeys(m_odb->db, insert);
65 doStatement(insert);
67 if(table->primarykeysize() == 1)
68 bindable->parseInsert(m_odb->db);
70 commit(table);
73 void SqliteMgr::doErase(SavableManager* bindable)
75 Assert(bindable);
77 TableImpl* table = bindable->getTable().get();
78 Assert(table);
80 sqlite3_stmt* erase = getEraseStmt(table);
81 Assert(erase);
83 sqlite3_reset(erase);
85 bindable->bindKeys(m_odb->db, erase);
86 doStatement(erase);
88 commit(table);
91 void SqliteMgr::doUpdate(SavableManager* bindable)
93 Assert(bindable);
95 TableImpl* table = bindable->getTable().get();
96 Assert(table);
98 // This table doesn't have any properties, it need not be updated.
99 if(table->size() <= table->primarykeysize())
100 return;
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::doSelectMulti(SelectionMask* mask)
159 Assert(mask);
161 sqlite3_stmt* selectMulti = getSelectMultiStmt(mask, false);
162 Assert(selectMulti);
164 sqlite3_reset(selectMulti);
166 mask->bindSelectMulti(m_odb->db, selectMulti);
168 bool good = true;
169 for(int i = 0; good; i++)
171 good = doStatement(selectMulti);
172 if(good)
173 mask->parseRow(selectMulti);
176 sqlite3_finalize(selectMulti);
179 void SqliteMgr::doCount(SelectionMask* mask)
181 Assert(mask);
183 sqlite3_stmt* count = getSelectMultiStmt(mask, true);
184 Assert(count);
186 sqlite3_reset(count);
188 mask->bindSelectMulti(m_odb->db, count);
190 bool good = doStatement(count);
192 if(good)
193 mask->parseCount(count);
195 sqlite3_finalize(count);
198 void SqliteMgr::commit(TableImpl* table)
200 Assert(table);
201 m_statements.clear();
204 bool SqliteMgr::doStatement(sqlite3_stmt* stmt)
206 Assert(stmt);
208 int rc = sqlite3_step(stmt);
210 switch(rc) {
211 case SQLITE_DONE:
212 return false;
213 case SQLITE_ROW:
214 return true;
217 throw SqliteError(m_odb->db);
220 StatementsPtr SqliteMgr::getStatements(TableImpl* table)
222 Assert(table);
224 StatementsPtr statements = m_statements[table];
225 if(statements)
226 return statements;
228 statements = StatementsPtr(new Statements());
230 m_statements[table] = statements;
231 return statements;
234 StatementStringsPtr SqliteMgr::getStatementStrings(TableImpl* table)
236 Assert(table);
238 StatementStringsPtr statements = m_statementstrings[table];
239 if(statements)
240 return statements;
242 statements = StatementStringsPtr(new StatementStrings());
244 m_statementstrings[table] = statements;
245 return statements;
248 sqlite3_stmt* SqliteMgr::getInsertStmt(TableImpl* table)
250 Assert(table);
252 StatementsPtr statements = getStatements(table);
253 sqlite3_stmt* statement = statements->getInsert();
254 if(statement)
255 return statement;
257 std::string sql;
259 StatementStringsPtr statementstrings = getStatementStrings(table);
260 cstring statementstring = statementstrings->getInsert();
262 if(statementstring.size() != 0)
264 sql = statementstring;
266 else
268 sql.append("INSERT INTO ");
269 sql.append(table->getName());
270 sql.append(" (");
271 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
273 FieldImplPtr field = *it;
274 Assert(field);
276 if(!field->isPrimaryKey())
277 continue;
279 if(it != table->begin())
280 sql.append(", ");
282 sql.append(field->getName());
284 sql.append(") VALUES(");
285 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
287 FieldImplPtr field = *it;
288 Assert(field);
290 if(!field->isPrimaryKey())
291 continue;
293 if(it != table->begin())
294 sql.append(", ");
296 if(table->primarykeysize() == 1)
297 sql.append("NULL");
298 else
299 sql.append("?");
301 sql.append(");");
303 statementstrings->setInsert(sql);
306 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
308 if(errorcode != SQLITE_OK)
309 throw SqliteError(m_odb->db, sql);
311 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
313 statements->setInsert(statement);
314 return statement;
317 sqlite3_stmt* SqliteMgr::getEraseStmt(TableImpl* table)
319 StatementsPtr statements = getStatements(table);
320 sqlite3_stmt* statement = statements->getErase();
321 if(statement)
322 return statement;
324 std::string sql;
326 StatementStringsPtr statementstrings = getStatementStrings(table);
327 cstring statementstring = statementstrings->getErase();
329 if(statementstring.size() != 0)
331 sql = statementstring;
333 else
335 sql.append("DELETE FROM ");
336 sql.append(table->getName());
337 sql.append(" WHERE ");
338 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
340 FieldImplPtr field = *it;
341 Assert(field);
343 if(!field->isPrimaryKey())
344 continue;
346 if(it != table->begin())
347 sql.append(", ");
349 sql.append(field->getName());
350 sql.append("=?");
352 sql.append(";");
354 statementstrings->setErase(sql);
357 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
359 if(errorcode != SQLITE_OK)
360 throw SqliteError(m_odb->db, sql);
362 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
364 statements->setErase(statement);
365 return statement;
368 sqlite3_stmt* SqliteMgr::getUpdateStmt(TableImpl* table)
370 StatementsPtr statements = getStatements(table);
371 sqlite3_stmt* statement = statements->getUpdate();
372 if(statement)
373 return statement;
375 std::string sql;
377 StatementStringsPtr statementstrings = getStatementStrings(table);
378 cstring statementstring = statementstrings->getUpdate();
380 if(statementstring.size() != 0)
382 sql = statementstring;
384 else
386 sql.append("UPDATE ");
387 sql.append(table->getName());
388 sql.append(" SET ");
390 bool comspace = false;
391 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
393 FieldImplPtr field = *it;
394 Assert(field);
396 if(field->isPrimaryKey())
397 continue;
399 if(comspace)
400 sql.append(", ");
402 sql.append(field->getName());
403 sql.append("=?");
405 comspace = true;
407 sql.append(" WHERE ");
408 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
410 FieldImplPtr field = *it;
411 Assert(field);
413 if(!field->isPrimaryKey())
414 continue;
416 if(it != table->begin())
417 sql.append(" AND ");
419 sql.append(field->getName());
420 sql.append("=?");
422 sql.append(";");
424 statementstrings->setUpdate(sql);
427 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
429 if(errorcode != SQLITE_OK)
430 throw SqliteError(m_odb->db, sql);
432 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
434 statements->setUpdate(statement);
435 return statement;
438 sqlite3_stmt* SqliteMgr::getSelectStmt(TableImpl* table)
440 StatementsPtr statements = getStatements(table);
441 sqlite3_stmt* statement = statements->getSelect();
442 if(statement)
443 return statement;
445 std::string sql;
447 StatementStringsPtr statementstrings = getStatementStrings(table);
448 cstring statementstring = statementstrings->getSelect();
450 if(statementstring.size() != 0)
452 sql = statementstring;
454 else
456 sql.append("SELECT ");
458 bool comspace = false;
459 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
461 FieldImplPtr field = *it;
462 Assert(field);
464 if(field->isPrimaryKey())
465 continue;
467 if(comspace)
468 sql.append(", ");
470 sql.append(field->getName());
471 comspace = true;
475 * Prevent queries in the form "SELECT FROM ....", this is for tables that consist of only primary keys.
477 if(table->primarykeysize() == table->size())
478 sql.append("*");
480 sql.append(" FROM ");
481 sql.append(table->getName());
482 sql.append(" WHERE ");
484 bool andspace = false;
485 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
487 FieldImplPtr field = *it;
488 Assert(field);
490 if(!field->isPrimaryKey())
491 continue;
493 if(andspace)
494 sql.append(" AND ");
496 sql.append(field->getName());
497 sql.append("=?");
498 andspace = true;
500 sql.append(";");
502 statementstrings->setSelect(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, sql);
510 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
512 statements->setSelect(statement);
513 return statement;
516 sqlite3_stmt* SqliteMgr::getLookupStmt(TableImpl* table, FieldPtr lookupfield)
518 StatementsPtr statements = getStatements(table);
519 sqlite3_stmt* statement = statements->getLookup(lookupfield);
520 if(statement)
521 return statement;
523 std::string sql;
525 StatementStringsPtr statementstrings = getStatementStrings(table);
526 cstring statementstring = statementstrings->getLookup(lookupfield);
528 if(statementstring.size() != 0)
530 sql = statementstring;
532 else
534 sql.append("SELECT ");
535 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
537 FieldImplPtr field = *it;
538 Assert(field);
540 if(it != table->begin())
541 sql.append(", ");
543 sql.append(field->getName());
545 sql.append(" FROM ");
546 sql.append(table->getName());
547 sql.append(" WHERE ");
548 sql.append(lookupfield->getName());
549 sql.append("=?");
550 sql.append(";");
552 statementstrings->setLookup(lookupfield, sql);
555 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
557 if(errorcode != SQLITE_OK)
558 throw SqliteError(m_odb->db, sql);
560 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
562 statements->setLookup(lookupfield, statement);
563 return statement;
566 sqlite3_stmt* SqliteMgr::getSelectMultiStmt(SelectionMask* mask, bool count)
568 Assert(mask);
570 std::string sql;
571 sqlite3_stmt* statement;
573 TableImplPtr table = mask->getTable();
574 Assert(table);
576 sql.append("SELECT ");
578 if(count) {
579 sql.append("COUNT(*)");
581 else
583 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
585 FieldImplPtr field = *it;
586 Assert(field);
588 if(it != table->begin())
589 sql.append(", ");
591 sql.append(field->getTable()->getName());
592 sql.append(".");
593 sql.append(field->getName());
597 sql.append(" FROM ");
598 sql.append(table->getName());
601 * Allow for queries that retreive data from foreigh tables "SELECT a, b, c, FROM Table INNER JOIN Other ON tableid = fkTable WHERE d = 5;"
603 for(Joins::const_iterator it = mask->joinsbegin(); it != mask->joinsend(); it++)
605 JoinPtr join = *it;
606 sql.append(" INNER JOIN ");
607 sql.append(join->getJoinTable()->getName());
608 sql.append(" ON ");
609 sql.append(join->getNativeKey()->getName());
610 sql.append(" = ");
611 sql.append(join->getForeignKey()->getName());
615 * Prevent queries in the form "SELECT a, b, c FROM table WHERE ;", this is for the unmasked selection.
617 if(mask->size())
618 sql.append(" WHERE ");
620 for(Strings::const_iterator it = mask->begin(); it != mask->end(); it++)
622 if(it != mask->begin())
623 sql.append(" AND ");
625 sql.append(*it);
626 sql.append("=?");
628 sql.append(";");
630 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
632 if(errorcode != SQLITE_OK)
633 throw SqliteError(m_odb->db, sql);
635 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
637 return statement;
640 bool SqliteMgr::databasePopulated()
642 std::string sql("SELECT * FROM SQLITE_MASTER;");
644 sqlite3_stmt* statement;
645 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
647 if(errorcode != SQLITE_OK)
648 throw SqliteError(m_odb->db, sql);
650 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
652 bool populated = doStatement(statement);
653 sqlite3_finalize(statement);
655 return populated;
658 bool SqliteMgr::tableValid(TableImplPtr table)
660 Assert(table);
662 std::string sql = tableQuery(table);
664 sqlite3_stmt* statement;
665 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
667 if(errorcode != SQLITE_OK)
668 throw SqliteError(m_odb->db, sql);
670 bool success = doStatement(statement);
671 sqlite3_finalize(statement);
673 return success;
676 void SqliteMgr::initTable(TableImplPtr table)
678 Assert(table);
680 std::string sql = SqliteMgr::Get()->creationQuery(table);
682 sqlite3_stmt* statement;
683 int errorcode = sqlite3_prepare_v2(m_odb->db, sql.c_str(), (int)sql.size(), &statement, &m_leftover);
685 if(errorcode != SQLITE_OK)
686 throw SqliteError(m_odb->db, sql);
688 Assert(m_leftover == NULL || strlen(m_leftover) == 0);
689 doStatement(statement);
690 sqlite3_finalize(statement);
692 return;
695 std::string SqliteMgr::tableQuery(TableImplPtr table) const
697 Assert(table);
699 std::string result;
700 result.append("SELECT type FROM sqlite_master WHERE tbl_name='");
701 result.append(table->getName());
702 result.append("' and sql='");
704 result.append(creationQuery(table, true));
706 result.append("';");
708 return result;
712 "CREATE TABLE IF NOT EXISTS %s("
713 "%s INTEGER PRIMARY KEY AUTOINCREMENT"
714 ",versiontext TEXT"
715 ",grantgroup INTEGER RESTRAINT grantgroup DEFAULT 1"
716 ");",
718 std::string SqliteMgr::creationQuery(TableImplPtr table, bool verify) const
720 Assert(table);
722 std::string result;
724 if(verify)
725 result.append("CREATE TABLE ");
726 else
727 result.append("CREATE TABLE IF NOT EXISTS ");
729 result.append(table->getName());
730 result.append("(");
732 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
734 FieldImplPtr field = *it;
735 Assert(field);
737 bool psk = (field->isPrimaryKey() && table->primarykeysize() == 1);
739 if(it != table->begin())
740 result.append(", ");
742 result.append(field->getName());
744 if(field->isText()) {
745 result.append(" TEXT");
747 else
749 result.append(" INTEGER");
751 if(psk)
752 result.append(" PRIMARY KEY AUTOINCREMENT");
755 if(field->isLookup() && !psk)
757 result.append(" RESTRAINT ");
758 result.append(field->getName());
759 result.append(" UNIQUE");
762 std::string defaultvalue = field->getDefaultValue();
764 if(defaultvalue.size() != 0)
766 Assert(!field->isLookup());
767 Assert(!psk);
769 result.append(" RESTRAINT ");
770 result.append(field->getName());
771 result.append(" DEFAULT ");
773 if(field->isText())
774 result.append("'");
776 result.append(defaultvalue);
778 if(field->isText())
779 result.append("'");
783 if(table->primarykeysize() > 1)
785 result.append(", PRIMARY KEY(");
787 bool comspace = false;
788 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
790 FieldImplPtr field = *it;
791 Assert(field);
793 if(!field->isPrimaryKey())
794 continue;
796 if(comspace)
797 result.append(", ");
799 result.append(field->getName());
800 comspace = true;
802 result.append(")");
805 result.append(")");
807 if(!verify)
808 result.append(";");
810 return result;
813 std::string SqliteMgr::creationString(FieldImplPtr field) const
815 Assert(field);
817 std::string result = field->getName();
819 if(field->isText())
820 result.append(" TEXT");
821 else
822 result.append(" INTEGER");
824 if(field->getDefaultValue().size() != 0)
826 result.append(" RESTRAINT ");
827 result.append(field->getName());
828 result.append(" DEFAULT ");
830 if(field->isText())
831 result.append("'");
832 result.append(field->getDefaultValue());
833 if(field->isText())
834 result.append("'");
837 return result;