MythTV  0.26-pre
dbaccess.cpp
Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <vector>
00003 #include <map>
00004 
00005 #include "mythdb.h"
00006 #include "cleanup.h"
00007 #include "dbaccess.h"
00008 
00009 namespace
00010 {
00011     template <typename T, typename arg_type>
00012     struct call_sort
00013     {
00014         call_sort(T &c) : m_c(c) {}
00015 
00016         bool operator()(const arg_type &lhs, const arg_type &rhs)
00017         {
00018             return m_c.sort(lhs, rhs);
00019         }
00020 
00021         T &m_c;
00022     };
00023 }
00024 
00025 class SingleValueImp
00026 {
00027   public:
00028     typedef SingleValue::entry entry;
00029     typedef std::vector<entry> entry_list;
00030 
00031   private:
00032     typedef std::map<int, QString> entry_map;
00033 
00034   public:
00035     SingleValueImp(const QString &table_name, const QString &id_name,
00036                    const QString &value_name) : m_table_name(table_name),
00037         m_id_name(id_name), m_value_name(value_name), m_ready(false),
00038         m_dirty(true), m_clean_stub(this)
00039     {
00040         m_insert_sql = QString("INSERT INTO %1 (%2) VALUES (:NAME)")
00041                 .arg(m_table_name).arg(m_value_name);
00042         m_fill_sql = QString("SELECT %1, %2 FROM %3").arg(m_id_name)
00043                 .arg(m_value_name).arg(m_table_name);
00044         m_delete_sql = QString("DELETE FROM %1 WHERE %2 = :ID")
00045                 .arg(m_table_name).arg(m_id_name);
00046     }
00047 
00048     virtual ~SingleValueImp() {}
00049 
00050     void load_data()
00051     {
00052         if (!m_ready)
00053         {
00054             fill_from_db();
00055             m_ready = true;
00056         }
00057     }
00058 
00059     int add(const QString &name)
00060     {
00061         int id = 0;
00062 
00063         if (!exists(name, &id))
00064         {
00065             MSqlQuery query(MSqlQuery::InitCon());
00066             query.prepare(m_insert_sql);
00067             query.bindValue(":NAME", name);
00068             if (query.exec())
00069             {
00070                 if (query.exec("SELECT LAST_INSERT_ID()") && query.next())
00071                 {
00072                     id = query.value(0).toInt();
00073                     m_entries.insert(entry_map::value_type(id, name));
00074                     m_dirty = true;
00075                 }
00076                 else
00077                     MythDB::DBError("get last id", query);
00078             }
00079         }
00080 
00081         return id;
00082     }
00083 
00084     bool get(int id, QString &value)
00085     {
00086         entry_map::const_iterator p = m_entries.find(id);
00087         if (p != m_entries.end())
00088         {
00089             value = p->second;
00090             return true;
00091         }
00092         return false;
00093     }
00094 
00095     void remove(int id)
00096     {
00097         entry_map::iterator p = m_entries.find(id);
00098         if (p != m_entries.end())
00099         {
00100             MSqlQuery query(MSqlQuery::InitCon());
00101             query.prepare(m_delete_sql);
00102             query.bindValue(":ID", p->first);
00103             if (query.exec())
00104             {
00105                 m_dirty = true;
00106                 m_entries.erase(p);
00107             }
00108         }
00109     }
00110 
00111     bool exists(int id)
00112     {
00113         return m_entries.find(id) != m_entries.end();
00114     }
00115 
00116     bool exists(const QString &name, int *id = 0)
00117     {
00118         entry_map::const_iterator p = find(name);
00119         if (p != m_entries.end())
00120         {
00121             if (id)
00122                 *id = p->first;
00123             return true;
00124         }
00125         return false;
00126     }
00127 
00128     const entry_list &getList()
00129     {
00130         if (m_dirty)
00131         {
00132             m_dirty = false;
00133             m_ret_entries.clear();
00134 
00135             for (entry_map::const_iterator p = m_entries.begin();
00136                     p != m_entries.end(); ++p)
00137             {
00138                 m_ret_entries.push_back(entry_list::value_type(p->first,
00139                                         p->second));
00140             }
00141             std::sort(m_ret_entries.begin(), m_ret_entries.end(),
00142                       call_sort<SingleValueImp, entry>(*this));
00143         }
00144 
00145         return m_ret_entries;
00146     }
00147 
00148     virtual bool sort(const entry &lhs, const entry &rhs)
00149     {
00150         return QString::localeAwareCompare(lhs.second, rhs.second) < 0;
00151     }
00152 
00153     void cleanup()
00154     {
00155         m_ready = false;
00156         m_dirty = true;
00157         m_ret_entries.clear();
00158         m_entries.clear();
00159     }
00160 
00161   private:
00162     entry_map::iterator find(const QString &name)
00163     {
00164         for (entry_map::iterator p = m_entries.begin();
00165              p != m_entries.end(); ++p)
00166         {
00167             if (p->second == name)
00168                 return p;
00169         }
00170         return m_entries.end();
00171     }
00172 
00173     void fill_from_db()
00174     {
00175         m_entries.clear();
00176 
00177         MSqlQuery query(MSqlQuery::InitCon());
00178 
00179         if (query.exec(m_fill_sql))
00180         {
00181             while (query.next())
00182             {
00183                 int id = query.value(0).toInt();
00184                 QString val = query.value(1).toString();
00185                 m_entries.insert(entry_map::value_type(id, val));
00186             }
00187         }
00188     }
00189 
00190   private:
00191     QString m_table_name;
00192     QString m_id_name;
00193     QString m_value_name;
00194 
00195     QString m_insert_sql;
00196     QString m_fill_sql;
00197     QString m_delete_sql;
00198 
00199     bool m_ready;
00200     bool m_dirty;
00201     entry_list m_ret_entries;
00202     entry_map m_entries;
00203     SimpleCleanup<SingleValueImp> m_clean_stub;
00204 };
00205 
00207 
00208 SingleValue::SingleValue(SingleValueImp *imp) : m_imp(imp)
00209 {
00210 }
00211 
00212 SingleValue::~SingleValue()
00213 {
00214     delete m_imp;
00215 }
00216 
00217 int SingleValue::add(const QString &name)
00218 {
00219     return m_imp->add(name);
00220 }
00221 
00222 bool SingleValue::get(int id, QString &category)
00223 {
00224     return m_imp->get(id, category);
00225 }
00226 
00227 void SingleValue::remove(int id)
00228 {
00229     m_imp->remove(id);
00230 }
00231 
00232 bool SingleValue::exists(int id)
00233 {
00234     return m_imp->exists(id);
00235 }
00236 
00237 bool SingleValue::exists(const QString &name)
00238 {
00239     return m_imp->exists(name);
00240 }
00241 
00242 const SingleValue::entry_list &SingleValue::getList()
00243 {
00244     return m_imp->getList();
00245 }
00246 
00247 void SingleValue::load_data()
00248 {
00249     m_imp->load_data();
00250 }
00251 
00253 
00254 class MultiValueImp
00255 {
00256   public:
00257     typedef MultiValue::entry entry;
00258 
00259   private:
00260     typedef std::map<int, entry> id_map;
00261 
00262   public:
00263     MultiValueImp(const QString &table_name, const QString &id_name,
00264                   const QString &value_name) : m_table_name(table_name),
00265         m_id_name(id_name), m_value_name(value_name), m_ready(false),
00266         m_clean_stub(this)
00267     {
00268         m_insert_sql = QString("INSERT INTO %1 (%2, %3) VALUES (:ID, :VALUE)")
00269                 .arg(m_table_name).arg(m_id_name).arg(m_value_name);
00270         m_fill_sql = QString("SELECT %1, %2 FROM %3 ORDER BY %4").arg(m_id_name)
00271                 .arg(m_value_name).arg(m_table_name).arg(m_id_name);
00272     }
00273 
00274     void load_data()
00275     {
00276         if (!m_ready)
00277         {
00278             fill_from_db();
00279             m_ready = true;
00280         }
00281     }
00282 
00283     void cleanup()
00284     {
00285         m_ready = false;
00286         m_val_map.clear();
00287     }
00288 
00289     int add(int id, int value)
00290     {
00291         bool db_insert = false;
00292         id_map::iterator p = m_val_map.find(id);
00293         if (p != m_val_map.end())
00294         {
00295             entry::values_type &va = p->second.values;
00296             entry::values_type::iterator v =
00297                     std::find(va.begin(), va.end(), value);
00298             if (v == va.end())
00299             {
00300                 va.push_back(value);
00301                 db_insert = true;
00302             }
00303         }
00304         else
00305         {
00306             entry e;
00307             e.id = id;
00308             e.values.push_back(value);
00309             m_val_map.insert(id_map::value_type(id, e));
00310             db_insert = true;
00311         }
00312 
00313         if (db_insert)
00314         {
00315             MSqlQuery query(MSqlQuery::InitCon());
00316             query.prepare(m_insert_sql);
00317             query.bindValue(":ID", id);
00318             query.bindValue(":VALUE", value);
00319             if (!query.exec())
00320                 MythDB::DBError("multi value insert", query);
00321         }
00322 
00323         return id;
00324     }
00325 
00326     bool get(int id, entry &values)
00327     {
00328         id_map::iterator p = m_val_map.find(id);
00329         if (p != m_val_map.end())
00330         {
00331             values = p->second;
00332             return true;
00333         }
00334         return false;
00335     }
00336 
00337     void remove(int id, int value)
00338     {
00339         id_map::iterator p = m_val_map.find(id);
00340         if (p != m_val_map.end())
00341         {
00342             entry::values_type::iterator vp =
00343                     std::find(p->second.values.begin(), p->second.values.end(),
00344                               value);
00345             if (vp != p->second.values.end())
00346             {
00347                 MSqlQuery query(MSqlQuery::InitCon());
00348                 QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID AND "
00349                                             "%3 = :VALUE")
00350                         .arg(m_table_name).arg(m_id_name).arg(m_value_name);
00351                 query.prepare(del_query);
00352                 query.bindValue(":ID", p->first);
00353                 query.bindValue(":VALUE", int(*vp));
00354                 if (!query.exec() || !query.isActive())
00355                 {
00356                     MythDB::DBError("multivalue remove", query);
00357                 }
00358                 p->second.values.erase(vp);
00359             }
00360         }
00361     }
00362 
00363     void remove(int id)
00364     {
00365         id_map::iterator p = m_val_map.find(id);
00366         if (p != m_val_map.end())
00367         {
00368             MSqlQuery query(MSqlQuery::InitCon());
00369             QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID")
00370                     .arg(m_table_name).arg(m_id_name);
00371             query.prepare(del_query);
00372             query.bindValue(":ID", p->first);
00373             if (!query.exec() || !query.isActive())
00374             {
00375                 MythDB::DBError("multivalue remove", query);
00376             }
00377             m_val_map.erase(p);
00378         }
00379     }
00380 
00381     bool exists(int id, int value)
00382     {
00383         id_map::iterator p = m_val_map.find(id);
00384         if (p != m_val_map.end())
00385         {
00386             entry::values_type::iterator vp =
00387                     std::find(p->second.values.begin(), p->second.values.end(),
00388                               value);
00389             return vp != p->second.values.end();
00390         }
00391         return false;
00392     }
00393 
00394     bool exists(int id)
00395     {
00396         return m_val_map.find(id) != m_val_map.end();
00397     }
00398 
00399   private:
00400     void fill_from_db()
00401     {
00402         m_val_map.clear();
00403 
00404         MSqlQuery query(MSqlQuery::InitCon());
00405 
00406         if (query.exec(m_fill_sql) && query.size() > 0)
00407         {
00408             id_map::iterator p = m_val_map.end();
00409             while (query.next())
00410             {
00411                 int id = query.value(0).toInt();
00412                 int val = query.value(1).toInt();
00413 
00414                 if (p == m_val_map.end() ||
00415                         (p != m_val_map.end() && p->first != id))
00416                 {
00417                     p = m_val_map.find(id);
00418                     if (p == m_val_map.end())
00419                     {
00420                         entry e;
00421                         e.id = id;
00422                         p = m_val_map.insert(id_map::value_type(id, e)).first;
00423                     }
00424                 }
00425                 p->second.values.push_back(val);
00426             }
00427         }
00428     }
00429 
00430   private:
00431     id_map m_val_map;
00432 
00433     QString m_table_name;
00434     QString m_id_name;
00435     QString m_value_name;
00436 
00437     QString m_insert_sql;
00438     QString m_fill_sql;
00439     QString m_id_sql;
00440 
00441     bool m_ready;
00442     SimpleCleanup<MultiValueImp> m_clean_stub;
00443 };
00444 
00446 
00447 MultiValue::MultiValue(MultiValueImp *imp) : m_imp(imp)
00448 {
00449 }
00450 
00451 MultiValue::~MultiValue()
00452 {
00453 }
00454 
00455 int MultiValue::add(int id, int value)
00456 {
00457     return m_imp->add(id, value);
00458 }
00459 
00460 bool MultiValue::get(int id, entry &values)
00461 {
00462     return m_imp->get(id, values);
00463 }
00464 
00465 void MultiValue::remove(int id, int value)
00466 {
00467     m_imp->remove(id, value);
00468 }
00469 
00470 void MultiValue::remove(int id)
00471 {
00472     m_imp->remove(id);
00473 }
00474 
00475 bool MultiValue::exists(int id, int value)
00476 {
00477     return m_imp->exists(id, value);
00478 }
00479 
00480 bool MultiValue::exists(int id)
00481 {
00482     return m_imp->exists(id);
00483 }
00484 
00485 void MultiValue::load_data()
00486 {
00487     m_imp->load_data();
00488 }
00489 
00491 
00492 VideoCategory::VideoCategory() :
00493     SingleValue(new SingleValueImp("videocategory", "intid", "category"))
00494 {
00495 }
00496 
00497 VideoCategory::~VideoCategory()
00498 {
00499 }
00500 
00501 VideoCategory &VideoCategory::GetCategory()
00502 {
00503     static VideoCategory vc;
00504     vc.load_data();
00505     return vc;
00506 }
00507 
00509 
00510 VideoCountry::VideoCountry() :
00511     SingleValue(new SingleValueImp("videocountry", "intid", "country"))
00512 {
00513 }
00514 
00515 VideoCountry::~VideoCountry()
00516 {
00517 }
00518 
00519 VideoCountry &VideoCountry::getCountry()
00520 {
00521     static VideoCountry vc;
00522     vc.load_data();
00523     return vc;
00524 }
00525 
00527 
00528 VideoGenre::VideoGenre() :
00529     SingleValue(new SingleValueImp("videogenre", "intid", "genre"))
00530 {
00531 }
00532 
00533 VideoGenre::~VideoGenre()
00534 {
00535 }
00536 
00537 VideoGenre &VideoGenre::getGenre()
00538 {
00539     static VideoGenre vg;
00540     vg.load_data();
00541     return vg;
00542 }
00543 
00545 
00546 VideoCast::VideoCast() :
00547     SingleValue(new SingleValueImp("videocast", "intid", "cast"))
00548 {
00549 }
00550 
00551 VideoCast::~VideoCast()
00552 {
00553 }
00554 
00555 VideoCast &VideoCast::GetCast()
00556 {
00557     static VideoCast vc;
00558     vc.load_data();
00559     return vc;
00560 }
00561 
00563 
00564 VideoGenreMap::VideoGenreMap() :
00565     MultiValue(new MultiValueImp("videometadatagenre", "idvideo", "idgenre"))
00566 {
00567 }
00568 
00569 VideoGenreMap::~VideoGenreMap()
00570 {
00571 }
00572 
00573 VideoGenreMap &VideoGenreMap::getGenreMap()
00574 {
00575     static VideoGenreMap vgm;
00576     vgm.load_data();
00577     return vgm;
00578 }
00579 
00581 
00582 VideoCountryMap::VideoCountryMap() :
00583     MultiValue(new MultiValueImp("videometadatacountry", "idvideo",
00584                                  "idcountry"))
00585 {
00586 }
00587 
00588 VideoCountryMap::~VideoCountryMap()
00589 {
00590 }
00591 
00592 VideoCountryMap &VideoCountryMap::getCountryMap()
00593 {
00594     static VideoCountryMap vcm;
00595     vcm.load_data();
00596     return vcm;
00597 }
00598 
00600 
00601 VideoCastMap::VideoCastMap() :
00602     MultiValue(new MultiValueImp("videometadatacast", "idvideo",
00603                                  "idcast"))
00604 {
00605 }
00606 
00607 VideoCastMap::~VideoCastMap()
00608 {
00609 }
00610 
00611 VideoCastMap &VideoCastMap::getCastMap()
00612 {
00613     static VideoCastMap vcm;
00614     vcm.load_data();
00615     return vcm;
00616 }
00617 
00619 
00620 class FileAssociationsImp
00621 {
00622   public:
00623     typedef FileAssociations::file_association file_association;
00624     typedef FileAssociations::association_list association_list;
00625     typedef FileAssociations::ext_ignore_list ext_ignore_list;
00626 
00627   public:
00628     FileAssociationsImp() : m_ready(false) {}
00629 
00630     bool add(file_association &fa)
00631     {
00632         file_association ret_fa(fa);
00633 
00634         file_association *existing_fa = 0;
00635         MSqlQuery query(MSqlQuery::InitCon());
00636 
00637         association_list::iterator p = find(ret_fa.extension);
00638         if (p != m_file_associations.end())
00639         {
00640             ret_fa.id = p->id;
00641             existing_fa = &(*p);
00642 
00643             query.prepare("UPDATE videotypes SET extension = :EXT, "
00644                           "playcommand = :PLAYCMD, f_ignore = :IGNORED, "
00645                           "use_default = :USEDEFAULT WHERE intid = :ID");
00646             query.bindValue(":ID", ret_fa.id);
00647         }
00648         else
00649             query.prepare("INSERT INTO videotypes (extension, playcommand, "
00650                           "f_ignore, use_default) VALUES "
00651                           "(:EXT, :PLAYCMD, :IGNORED, :USEDEFAULT)");
00652 
00653         query.bindValue(":EXT", ret_fa.extension);
00654         query.bindValue(":PLAYCMD", ret_fa.playcommand);
00655         query.bindValue(":IGNORED", ret_fa.ignore);
00656         query.bindValue(":USEDEFAULT", ret_fa.use_default);
00657 
00658         if (query.exec() && query.isActive())
00659         {
00660             if (!existing_fa)
00661             {
00662                 if (query.exec("SELECT LAST_INSERT_ID()") && query.next())
00663                 {
00664                     ret_fa.id = query.value(0).toUInt();
00665                     m_file_associations.push_back(ret_fa);
00666                 }
00667                 else
00668                     return false;
00669             }
00670             else
00671                 *existing_fa = ret_fa;
00672 
00673             fa = ret_fa;
00674             return true;
00675         }
00676 
00677         return false;
00678     }
00679 
00680     bool get(unsigned int id, file_association &val) const
00681     {
00682         association_list::const_iterator p = find(id);
00683         if (p != m_file_associations.end())
00684         {
00685             val = *p;
00686             return true;
00687         }
00688         return false;
00689     }
00690 
00691     bool get(const QString &ext, file_association &val) const
00692     {
00693         association_list::const_iterator p = find(ext);
00694         if (p != m_file_associations.end())
00695         {
00696             val = *p;
00697             return true;
00698         }
00699         return false;
00700     }
00701 
00702     bool remove(unsigned int id)
00703     {
00704         association_list::iterator p = find(id);
00705         if (p != m_file_associations.end())
00706         {
00707             MSqlQuery query(MSqlQuery::InitCon());
00708             query.prepare("DELETE FROM videotypes WHERE intid = :ID");
00709             query.bindValue(":ID", p->id);
00710             if (query.exec())
00711             {
00712                 m_file_associations.erase(p);
00713                 return true;
00714             }
00715         }
00716         return false;
00717     }
00718 
00719     const association_list &getList() const
00720     {
00721         return m_file_associations;
00722     }
00723 
00724     void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
00725     {
00726         for (association_list::const_iterator p = m_file_associations.begin();
00727              p != m_file_associations.end(); ++p)
00728         {
00729             ext_ignore.push_back(std::make_pair(p->extension, p->ignore));
00730         }
00731     }
00732 
00733     void load_data()
00734     {
00735         if (!m_ready)
00736         {
00737             fill_from_db();
00738             m_ready = true;
00739         }
00740     }
00741 
00742     void cleanup()
00743     {
00744         m_ready = false;
00745         m_file_associations.clear();
00746     }
00747 
00748   private:
00749     void fill_from_db()
00750     {
00751         MSqlQuery query(MSqlQuery::InitCon());
00752         if (query.exec("SELECT intid, extension, playcommand, f_ignore, "
00753                        "use_default FROM videotypes"))
00754         {
00755             while (query.next())
00756             {
00757                 file_association fa(query.value(0).toUInt(),
00758                                     query.value(1).toString(),
00759                                     query.value(2).toString(),
00760                                     query.value(3).toBool(),
00761                                     query.value(4).toBool());
00762                 m_file_associations.push_back(fa);
00763             }
00764         }
00765     }
00766 
00767     association_list::iterator find(const QString &ext)
00768     {
00769         for (association_list::iterator p = m_file_associations.begin();
00770              p != m_file_associations.end(); ++p)
00771         {
00772             if (p->extension.length() == ext.length() &&
00773                 ext.indexOf(p->extension) == 0)
00774             {
00775                 return p;
00776             }
00777         }
00778         return m_file_associations.end();
00779     }
00780 
00781     association_list::iterator find(unsigned int id)
00782     {
00783         for (association_list::iterator p = m_file_associations.begin();
00784              p != m_file_associations.end(); ++p)
00785         {
00786             if (p->id == id) return p;
00787         }
00788         return m_file_associations.end();
00789     }
00790 
00791     association_list::const_iterator find(const QString &ext) const
00792     {
00793         for (association_list::const_iterator p = m_file_associations.begin();
00794              p != m_file_associations.end(); ++p)
00795         {
00796             if (p->extension.length() == ext.length() &&
00797                 ext.indexOf(p->extension) == 0)
00798             {
00799                 return p;
00800             }
00801         }
00802         return m_file_associations.end();
00803     }
00804 
00805     association_list::const_iterator find(unsigned int id) const
00806     {
00807         for (association_list::const_iterator p = m_file_associations.begin();
00808              p != m_file_associations.end(); ++p)
00809         {
00810             if (p->id == id) return p;
00811         }
00812         return m_file_associations.end();
00813     }
00814 
00815   private:
00816     association_list m_file_associations;
00817     bool m_ready;
00818 };
00819 
00820 
00821 FileAssociations::file_association::file_association() : id(0), ignore(false),
00822     use_default(false)
00823 {
00824 }
00825 
00826 FileAssociations::file_association::file_association(unsigned int l_id,
00827                                                      const QString &ext,
00828                                                      const QString &playcmd,
00829                                                      bool l_ignore,
00830                                                      bool l_use_default) :
00831     id(l_id), extension(ext), playcommand(playcmd), ignore(l_ignore),
00832     use_default(l_use_default)
00833 {
00834 }
00835 
00836 bool FileAssociations::add(file_association &fa)
00837 {
00838     return m_imp->add(fa);
00839 }
00840 
00841 bool FileAssociations::get(unsigned int id, file_association &val) const
00842 {
00843     return m_imp->get(id, val);
00844 }
00845 
00846 bool FileAssociations::get(const QString &ext, file_association &val) const
00847 {
00848     return m_imp->get(ext, val);
00849 }
00850 
00851 bool FileAssociations::remove(unsigned int id)
00852 {
00853     return m_imp->remove(id);
00854 }
00855 
00856 const FileAssociations::association_list &FileAssociations::getList() const
00857 {
00858     return m_imp->getList();
00859 }
00860 
00861 void FileAssociations::getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
00862 {
00863     return m_imp->getExtensionIgnoreList(ext_ignore);
00864 }
00865 
00866 void FileAssociations::load_data()
00867 {
00868     m_imp->load_data();
00869 }
00870 
00871 FileAssociations::FileAssociations()
00872 {
00873     m_imp = new FileAssociationsImp;
00874 }
00875 
00876 FileAssociations::~FileAssociations()
00877 {
00878     delete m_imp;
00879 }
00880 
00881 FileAssociations &FileAssociations::getFileAssociation()
00882 {
00883     static FileAssociations fa;
00884     fa.load_data();
00885     return fa;
00886 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends