MythTV master
dbaccess.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <vector>
3#include <map>
4
7
8#include "cleanup.h"
9#include "dbaccess.h"
10
11namespace
12{
13 template <typename T, typename arg_type>
14 struct call_sort
15 {
16 explicit call_sort(T &c) : m_c(c) {}
17
18 bool operator()(const arg_type &lhs, const arg_type &rhs)
19 {
20 return m_c.sort(lhs, rhs);
21 }
22
23 T &m_c;
24 };
25}
26
28{
29 public:
31 using entry_list = std::vector<entry>;
32
33 private:
34 using entry_map = std::map<int, QString>;
35
36 public:
37 SingleValueImp(QString table_name, QString id_name, QString value_name)
38 : m_tableName(std::move(table_name)), m_idName(std::move(id_name)),
39 m_valueName(std::move(value_name)), m_cleanStub(this)
40 {
41 m_insertSql = QString("INSERT INTO %1 (%2) VALUES (:NAME)")
43 m_fillSql = QString("SELECT %1, %2 FROM %3")
45 m_deleteSql = QString("DELETE FROM %1 WHERE %2 = :ID")
46 .arg(m_tableName, m_idName);
47 }
48
49 virtual ~SingleValueImp() = default;
50
51 mutable QMutex m_mutex;
52
53 void load_data()
54 {
55 QMutexLocker locker(&m_mutex);
56 if (!m_ready)
57 {
59 m_ready = true;
60 }
61 }
62
63 int add(const QString &name)
64 {
65 int id = 0;
66
67 if (!exists(name, &id))
68 {
70 query.prepare(m_insertSql);
71 query.bindValue(":NAME", name);
72 if (query.exec())
73 {
74 if (query.exec("SELECT LAST_INSERT_ID()") && query.next())
75 {
76 id = query.value(0).toInt();
77 m_entries.insert(entry_map::value_type(id, name));
78 m_dirty = true;
79 }
80 else
81 {
82 MythDB::DBError("get last id", query);
83 }
84 }
85 }
86
87 return id;
88 }
89
90 bool get(int id, QString &value)
91 {
92 auto p = m_entries.find(id);
93 if (p != m_entries.end())
94 {
95 value = p->second;
96 return true;
97 }
98 return false;
99 }
100
101 void remove(int id)
102 {
103 auto p = m_entries.find(id);
104 if (p != m_entries.end())
105 {
107 query.prepare(m_deleteSql);
108 query.bindValue(":ID", p->first);
109 if (query.exec())
110 {
111 m_dirty = true;
112 m_entries.erase(p);
113 }
114 }
115 }
116
117 bool exists(int id)
118 {
119 return m_entries.find(id) != m_entries.end();
120 }
121
122 bool exists(const QString &name, int *id = nullptr)
123 {
124 auto p = find(name);
125 if (p != m_entries.end())
126 {
127 if (id)
128 *id = p->first;
129 return true;
130 }
131 return false;
132 }
133
135 {
136 if (m_dirty)
137 {
138 m_dirty = false;
139 m_retEntries.clear();
140
141 for (auto & item : m_entries)
142 {
143 m_retEntries.emplace_back(item.first, item.second);
144 }
145 std::sort(m_retEntries.begin(), m_retEntries.end(),
146 call_sort<SingleValueImp, entry>(*this));
147 }
148
149 return m_retEntries;
150 }
151
152 virtual bool sort(const entry &lhs, const entry &rhs)
153 {
154 return StringUtil::naturalSortCompare(lhs.second, rhs.second);
155 }
156
157 void cleanup()
158 {
159 m_ready = false;
160 m_dirty = true;
161 m_retEntries.clear();
162 m_entries.clear();
163 }
164
165 private:
166 entry_map::iterator find(const QString &name)
167 {
168 for (auto p = m_entries.begin(); p != m_entries.end(); ++p)
169 {
170 if (p->second == name)
171 return p;
172 }
173 return m_entries.end();
174 }
175
177 {
178 m_entries.clear();
179
181
182 if (query.exec(m_fillSql))
183 {
184 while (query.next())
185 {
186 int id = query.value(0).toInt();
187 QString val = query.value(1).toString();
188 m_entries.insert(entry_map::value_type(id, val));
189 }
190 }
191 }
192
193 private:
194 QString m_tableName;
195 QString m_idName;
196 QString m_valueName;
197
198 QString m_insertSql;
199 QString m_fillSql;
200 QString m_deleteSql;
201
202 bool m_ready {false};
203 bool m_dirty {true};
207};
208
210
212{
213 delete m_imp;
214}
215
216int SingleValue::add(const QString &name)
217{
218 return m_imp->add(name);
219}
220
221bool SingleValue::get(int id, QString &category)
222{
223 return m_imp->get(id, category);
224}
225
227{
228 m_imp->remove(id);
229}
230
232{
233 return m_imp->exists(id);
234}
235
236bool SingleValue::exists(const QString &name)
237{
238 return m_imp->exists(name);
239}
240
242{
243 return m_imp->getList();
244}
245
247{
248 m_imp->load_data();
249}
250
252
254{
255 public:
257
258 private:
259 using id_map = std::map<int, entry>;
260
261 public:
262 MultiValueImp(QString table_name, QString id_name,
263 QString value_name) : m_tableName(std::move(table_name)),
264 m_idName(std::move(id_name)), m_valueName(std::move(value_name)),
265 m_cleanStub(this)
266 {
267 m_insertSql = QString("INSERT INTO %1 (%2, %3) VALUES (:ID, :VALUE)")
269 m_fillSql = QString("SELECT %1, %2 FROM %3 ORDER BY %4")
271 }
272
273 mutable QMutex m_mutex;
274
276 {
277 QMutexLocker locker(&m_mutex);
278 if (!m_ready)
279 {
280 fill_from_db();
281 m_ready = true;
282 }
283 }
284
285 void cleanup()
286 {
287 m_ready = false;
288 m_valMap.clear();
289 }
290
291 int add(int id, int value)
292 {
293 bool db_insert = false;
294 auto p = m_valMap.find(id);
295 if (p != m_valMap.end())
296 {
297 entry::values_type &va = p->second.values;
298 auto v = std::find(va.begin(), va.end(), value);
299 if (v == va.end())
300 {
301 va.push_back(value);
302 db_insert = true;
303 }
304 }
305 else
306 {
307 entry e;
308 e.id = id;
309 e.values.push_back(value);
310 m_valMap.insert(id_map::value_type(id, e));
311 db_insert = true;
312 }
313
314 if (db_insert)
315 {
317 query.prepare(m_insertSql);
318 query.bindValue(":ID", id);
319 query.bindValue(":VALUE", value);
320 if (!query.exec())
321 MythDB::DBError("multi value insert", query);
322 }
323
324 return id;
325 }
326
327 bool get(int id, entry &values)
328 {
329 auto p = m_valMap.find(id);
330 if (p != m_valMap.end())
331 {
332 values = p->second;
333 return true;
334 }
335 return false;
336 }
337
338 void remove(int id, int value)
339 {
340 auto p = m_valMap.find(id);
341 if (p != m_valMap.end())
342 {
343 auto vp = std::find(p->second.values.begin(),
344 p->second.values.end(), value);
345 if (vp != p->second.values.end())
346 {
348 QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID AND "
349 "%3 = :VALUE")
351 query.prepare(del_query);
352 query.bindValue(":ID", p->first);
353 query.bindValue(":VALUE", int(*vp));
354 if (!query.exec() || !query.isActive())
355 {
356 MythDB::DBError("multivalue remove", query);
357 }
358 p->second.values.erase(vp);
359 }
360 }
361 }
362
363 void remove(int id)
364 {
365 auto p = m_valMap.find(id);
366 if (p != m_valMap.end())
367 {
369 QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID")
370 .arg(m_tableName, m_idName);
371 query.prepare(del_query);
372 query.bindValue(":ID", p->first);
373 if (!query.exec() || !query.isActive())
374 {
375 MythDB::DBError("multivalue remove", query);
376 }
377 m_valMap.erase(p);
378 }
379 }
380
381 bool exists(int id, int value)
382 {
383 auto p = m_valMap.find(id);
384 if (p != m_valMap.end())
385 {
386 auto vp =
387 std::find(p->second.values.begin(), p->second.values.end(),
388 value);
389 return vp != p->second.values.end();
390 }
391 return false;
392 }
393
394 bool exists(int id)
395 {
396 return m_valMap.find(id) != m_valMap.end();
397 }
398
399 private:
401 {
402 m_valMap.clear();
403
405
406 if (query.exec(m_fillSql) && query.size() > 0)
407 {
408 auto p = m_valMap.end();
409 while (query.next())
410 {
411 int id = query.value(0).toInt();
412 int val = query.value(1).toInt();
413
414 if (p == m_valMap.end() ||
415 (p != m_valMap.end() && p->first != id))
416 {
417 p = m_valMap.find(id);
418 if (p == m_valMap.end())
419 {
420 entry e;
421 e.id = id;
422 p = m_valMap.insert(id_map::value_type(id, e)).first;
423 }
424 }
425 p->second.values.push_back(val);
426 }
427 }
428 }
429
430 private:
432
433 QString m_tableName;
434 QString m_idName;
435 QString m_valueName;
436
437 QString m_insertSql;
438 QString m_fillSql;
439 QString m_idSql;
440
441 bool m_ready {false};
443};
444
446
447int MultiValue::add(int id, int value)
448{
449 return m_imp->add(id, value);
450}
451
452bool MultiValue::get(int id, entry &values)
453{
454 return m_imp->get(id, values);
455}
456
457void MultiValue::remove(int id, int value)
458{
459 m_imp->remove(id, value);
460}
461
463{
464 m_imp->remove(id);
465}
466
467bool MultiValue::exists(int id, int value)
468{
469 return m_imp->exists(id, value);
470}
471
473{
474 return m_imp->exists(id);
475}
476
478{
479 m_imp->load_data();
480}
481
483
485 SingleValue(new SingleValueImp("videocategory", "intid", "category"))
486{
487}
488
490{
491 static VideoCategory s_vc;
492 s_vc.load_data();
493 return s_vc;
494}
495
497
499 SingleValue(new SingleValueImp("videocountry", "intid", "country"))
500{
501}
502
504{
505 static VideoCountry s_vc;
506 s_vc.load_data();
507 return s_vc;
508}
509
511
513 SingleValue(new SingleValueImp("videogenre", "intid", "genre"))
514{
515}
516
518{
519 static VideoGenre s_vg;
520 s_vg.load_data();
521 return s_vg;
522}
523
525
527 SingleValue(new SingleValueImp("videocast", "intid", "cast"))
528{
529}
530
532{
533 static VideoCast s_vc;
534 s_vc.load_data();
535 return s_vc;
536}
537
539
541 MultiValue(new MultiValueImp("videometadatagenre", "idvideo", "idgenre"))
542{
543}
544
546{
547 static VideoGenreMap s_vgm;
548 s_vgm.load_data();
549 return s_vgm;
550}
551
553
555 MultiValue(new MultiValueImp("videometadatacountry", "idvideo",
556 "idcountry"))
557{
558}
559
561{
562 static VideoCountryMap s_vcm;
563 s_vcm.load_data();
564 return s_vcm;
565}
566
568
570 MultiValue(new MultiValueImp("videometadatacast", "idvideo",
571 "idcast"))
572{
573}
574
576{
577 static VideoCastMap s_vcm;
578 s_vcm.load_data();
579 return s_vcm;
580}
581
583
585{
586 public:
590
591 public:
593
595 {
596 file_association ret_fa(fa);
597
598 file_association *existing_fa = nullptr;
600
601 auto p = find(ret_fa.extension);
602 if (p != m_fileAssociations.end())
603 {
604 ret_fa.id = p->id;
605 existing_fa = &(*p);
606
607 query.prepare("UPDATE videotypes SET extension = :EXT, "
608 "playcommand = :PLAYCMD, f_ignore = :IGNORED, "
609 "use_default = :USEDEFAULT WHERE intid = :ID");
610 query.bindValue(":ID", ret_fa.id);
611 }
612 else
613 {
614 query.prepare("INSERT INTO videotypes (extension, playcommand, "
615 "f_ignore, use_default) VALUES "
616 "(:EXT, :PLAYCMD, :IGNORED, :USEDEFAULT)");
617 }
618
619 query.bindValue(":EXT", ret_fa.extension);
620 query.bindValue(":PLAYCMD", ret_fa.playcommand);
621 query.bindValue(":IGNORED", ret_fa.ignore);
622 query.bindValue(":USEDEFAULT", ret_fa.use_default);
623
624 if (query.exec() && query.isActive())
625 {
626 if (!existing_fa)
627 {
628 if (query.exec("SELECT LAST_INSERT_ID()") && query.next())
629 {
630 ret_fa.id = query.value(0).toUInt();
631 m_fileAssociations.push_back(ret_fa);
632 }
633 else
634 {
635 return false;
636 }
637 }
638 else
639 {
640 *existing_fa = ret_fa;
641 }
642
643 fa = ret_fa;
644 return true;
645 }
646
647 return false;
648 }
649
650 bool get(unsigned int id, file_association &val) const
651 {
652 auto p = cfind(id);
653 if (p != m_fileAssociations.end())
654 {
655 val = *p;
656 return true;
657 }
658 return false;
659 }
660
661 bool get(const QString &ext, file_association &val) const
662 {
663 auto p = cfind(ext);
664 if (p != m_fileAssociations.end())
665 {
666 val = *p;
667 return true;
668 }
669 return false;
670 }
671
672 bool remove(unsigned int id)
673 {
674 auto p = find(id);
675 if (p != m_fileAssociations.end())
676 {
678 query.prepare("DELETE FROM videotypes WHERE intid = :ID");
679 query.bindValue(":ID", p->id);
680 if (query.exec())
681 {
682 m_fileAssociations.erase(p);
683 return true;
684 }
685 }
686 return false;
687 }
688
690 {
691 return m_fileAssociations;
692 }
693
695 {
696 for (const auto & fa : m_fileAssociations)
697 ext_ignore.emplace_back(fa.extension, fa.ignore);
698 }
699
700 mutable QMutex m_mutex;
701
703 {
704 QMutexLocker locker(&m_mutex);
705 if (!m_ready)
706 {
707 fill_from_db();
708 m_ready = true;
709 }
710 }
711
712 void cleanup()
713 {
714 m_ready = false;
715 m_fileAssociations.clear();
716 }
717
718 private:
720 {
722 if (query.exec("SELECT intid, extension, playcommand, f_ignore, "
723 "use_default FROM videotypes"))
724 {
725 while (query.next())
726 {
727 file_association fa(query.value(0).toUInt(),
728 query.value(1).toString(),
729 query.value(2).toString(),
730 query.value(3).toBool(),
731 query.value(4).toBool());
732 m_fileAssociations.push_back(fa);
733 }
734 }
735 }
736
737 association_list::iterator find(const QString &ext)
738 {
739 for (auto p = m_fileAssociations.begin();
740 p != m_fileAssociations.end(); ++p)
741 {
742 if (p->extension.length() == ext.length() &&
743 ext.indexOf(p->extension) == 0)
744 {
745 return p;
746 }
747 }
748 return m_fileAssociations.end();
749 }
750
751 association_list::iterator find(unsigned int id)
752 {
753 for (auto p = m_fileAssociations.begin();
754 p != m_fileAssociations.end(); ++p)
755 {
756 if (p->id == id) return p;
757 }
758 return m_fileAssociations.end();
759 }
760
761 association_list::const_iterator cfind(const QString &ext) const
762 {
763 for (auto p = m_fileAssociations.cbegin();
764 p != m_fileAssociations.cend(); ++p)
765 {
766 if (p->extension.length() == ext.length() &&
767 ext.indexOf(p->extension) == 0)
768 {
769 return p;
770 }
771 }
772 return m_fileAssociations.cend();
773 }
774
775 association_list::const_iterator cfind(unsigned int id) const
776 {
777 for (auto p = m_fileAssociations.cbegin();
778 p != m_fileAssociations.cend(); ++p)
779 {
780 if (p->id == id) return p;
781 }
782 return m_fileAssociations.cend();
783 }
784
785 private:
787 bool m_ready {false};
788};
789
790
792{
793 return m_imp->add(fa);
794}
795
796bool FileAssociations::get(unsigned int id, file_association &val) const
797{
798 return m_imp->get(id, val);
799}
800
801bool FileAssociations::get(const QString &ext, file_association &val) const
802{
803 return m_imp->get(ext, val);
804}
805
806bool FileAssociations::remove(unsigned int id)
807{
808 return m_imp->remove(id);
809}
810
812{
813 return m_imp->getList();
814}
815
817{
818 m_imp->getExtensionIgnoreList(ext_ignore);
819}
820
822{
823 m_imp->load_data();
824}
825
827 : m_imp(new FileAssociationsImp)
828{
829}
830
832{
833 delete m_imp;
834}
835
837{
838 static FileAssociations s_fa;
839 s_fa.load_data();
840 return s_fa;
841}
FileAssociationsImp()=default
bool remove(unsigned int id)
Definition: dbaccess.cpp:672
bool get(unsigned int id, file_association &val) const
Definition: dbaccess.cpp:650
association_list::iterator find(unsigned int id)
Definition: dbaccess.cpp:751
association_list::const_iterator cfind(unsigned int id) const
Definition: dbaccess.cpp:775
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:694
FileAssociations::ext_ignore_list ext_ignore_list
Definition: dbaccess.cpp:589
const association_list & getList() const
Definition: dbaccess.cpp:689
bool get(const QString &ext, file_association &val) const
Definition: dbaccess.cpp:661
association_list m_fileAssociations
Definition: dbaccess.cpp:786
FileAssociations::association_list association_list
Definition: dbaccess.cpp:588
bool add(file_association &fa)
Definition: dbaccess.cpp:594
association_list::const_iterator cfind(const QString &ext) const
Definition: dbaccess.cpp:761
association_list::iterator find(const QString &ext)
Definition: dbaccess.cpp:737
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:816
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:155
bool add(file_association &fa)
Definition: dbaccess.cpp:791
bool remove(unsigned int id)
Definition: dbaccess.cpp:806
bool get(unsigned int id, file_association &val) const
Definition: dbaccess.cpp:796
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:836
const association_list & getList() const
Definition: dbaccess.cpp:811
std::vector< file_association > association_list
Definition: dbaccess.h:154
class FileAssociationsImp * m_imp
Definition: dbaccess.h:177
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
int size(void) const
Definition: mythdbcon.h:214
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
int add(int id, int value)
Definition: dbaccess.cpp:291
bool get(int id, entry &values)
Definition: dbaccess.cpp:327
QString m_idName
Definition: dbaccess.cpp:434
QString m_fillSql
Definition: dbaccess.cpp:438
std::map< int, entry > id_map
Definition: dbaccess.cpp:259
void fill_from_db()
Definition: dbaccess.cpp:400
void cleanup()
Definition: dbaccess.cpp:285
bool exists(int id)
Definition: dbaccess.cpp:394
QString m_tableName
Definition: dbaccess.cpp:433
QString m_valueName
Definition: dbaccess.cpp:435
QString m_insertSql
Definition: dbaccess.cpp:437
void load_data()
Definition: dbaccess.cpp:275
bool exists(int id, int value)
Definition: dbaccess.cpp:381
SimpleCleanup< MultiValueImp > m_cleanStub
Definition: dbaccess.cpp:442
void remove(int id)
Definition: dbaccess.cpp:363
id_map m_valMap
Definition: dbaccess.cpp:431
QMutex m_mutex
Definition: dbaccess.cpp:273
MultiValueImp(QString table_name, QString id_name, QString value_name)
Definition: dbaccess.cpp:262
void remove(int id, int value)
Definition: dbaccess.cpp:338
QString m_idSql
Definition: dbaccess.cpp:439
int add(int id, int value)
Definition: dbaccess.cpp:447
bool get(int id, entry &values)
Definition: dbaccess.cpp:452
void load_data()
Definition: dbaccess.cpp:477
MultiValueImp * m_imp
Definition: dbaccess.h:63
bool exists(int id, int value)
Definition: dbaccess.cpp:467
void remove(int id, int value)
Definition: dbaccess.cpp:457
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
void remove(int id)
Definition: dbaccess.cpp:101
entry_map::iterator find(const QString &name)
Definition: dbaccess.cpp:166
void load_data()
Definition: dbaccess.cpp:53
virtual ~SingleValueImp()=default
QString m_insertSql
Definition: dbaccess.cpp:198
SingleValueImp(QString table_name, QString id_name, QString value_name)
Definition: dbaccess.cpp:37
void fill_from_db()
Definition: dbaccess.cpp:176
QString m_valueName
Definition: dbaccess.cpp:196
std::map< int, QString > entry_map
Definition: dbaccess.cpp:34
SingleValue::entry entry
Definition: dbaccess.cpp:30
entry_map m_entries
Definition: dbaccess.cpp:205
entry_list m_retEntries
Definition: dbaccess.cpp:204
int add(const QString &name)
Definition: dbaccess.cpp:63
bool exists(const QString &name, int *id=nullptr)
Definition: dbaccess.cpp:122
QString m_tableName
Definition: dbaccess.cpp:194
std::vector< entry > entry_list
Definition: dbaccess.cpp:31
virtual bool sort(const entry &lhs, const entry &rhs)
Definition: dbaccess.cpp:152
void cleanup()
Definition: dbaccess.cpp:157
QString m_idName
Definition: dbaccess.cpp:195
const entry_list & getList()
Definition: dbaccess.cpp:134
QString m_deleteSql
Definition: dbaccess.cpp:200
SimpleCleanup< SingleValueImp > m_cleanStub
Definition: dbaccess.cpp:206
QString m_fillSql
Definition: dbaccess.cpp:199
bool get(int id, QString &value)
Definition: dbaccess.cpp:90
QMutex m_mutex
Definition: dbaccess.cpp:51
bool exists(int id)
Definition: dbaccess.cpp:117
bool get(int id, QString &category)
Definition: dbaccess.cpp:221
std::pair< int, QString > entry
Definition: dbaccess.h:15
bool exists(int id)
Definition: dbaccess.cpp:231
SingleValueImp * m_imp
Definition: dbaccess.h:33
void remove(int id)
Definition: dbaccess.cpp:226
const entry_list & getList()
Definition: dbaccess.cpp:241
int add(const QString &name)
Definition: dbaccess.cpp:216
virtual ~SingleValue()
Definition: dbaccess.cpp:211
std::vector< entry > entry_list
Definition: dbaccess.h:16
void load_data()
Definition: dbaccess.cpp:246
static VideoCastMap & getCastMap()
Definition: dbaccess.cpp:575
static VideoCast & GetCast()
Definition: dbaccess.cpp:531
static VideoCategory & GetCategory()
Definition: dbaccess.cpp:489
static VideoCountryMap & getCountryMap()
Definition: dbaccess.cpp:560
static VideoCountry & getCountry()
Definition: dbaccess.cpp:503
static VideoGenreMap & getGenreMap()
Definition: dbaccess.cpp:545
static VideoGenre & getGenre()
Definition: dbaccess.cpp:517
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
bool naturalSortCompare(const QString &a, const QString &b, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
naturalCompare as a std::sort compatible function (ignoring the third parameter, which is never used)...
Definition: stringutil.h:57
STL namespace.
std::vector< long > values_type
Definition: dbaccess.h:43
values_type values
Definition: dbaccess.h:44
bool operator()(const arg_type &lhs, const arg_type &rhs)
Definition: dbaccess.cpp:18