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.contains(id);
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::ranges::sort(m_retEntries,
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#ifdef __cpp_lib_ranges_contains
299 if (!std::ranges::contains(va, value))
300#else
301 auto v = std::ranges::find(va, value);
302 if (v == va.end())
303#endif
304 {
305 va.push_back(value);
306 db_insert = true;
307 }
308 }
309 else
310 {
311 entry e;
312 e.id = id;
313 e.values.push_back(value);
314 m_valMap.insert(id_map::value_type(id, e));
315 db_insert = true;
316 }
317
318 if (db_insert)
319 {
321 query.prepare(m_insertSql);
322 query.bindValue(":ID", id);
323 query.bindValue(":VALUE", value);
324 if (!query.exec())
325 MythDB::DBError("multi value insert", query);
326 }
327
328 return id;
329 }
330
331 bool get(int id, entry &values)
332 {
333 auto p = m_valMap.find(id);
334 if (p != m_valMap.end())
335 {
336 values = p->second;
337 return true;
338 }
339 return false;
340 }
341
342 void remove(int id, int value)
343 {
344 auto p = m_valMap.find(id);
345 if (p != m_valMap.end())
346 {
347 auto vp = std::find(p->second.values.begin(),
348 p->second.values.end(), value);
349 if (vp != p->second.values.end())
350 {
352 QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID AND "
353 "%3 = :VALUE")
355 query.prepare(del_query);
356 query.bindValue(":ID", p->first);
357 query.bindValue(":VALUE", int(*vp));
358 if (!query.exec() || !query.isActive())
359 {
360 MythDB::DBError("multivalue remove", query);
361 }
362 p->second.values.erase(vp);
363 }
364 }
365 }
366
367 void remove(int id)
368 {
369 auto p = m_valMap.find(id);
370 if (p != m_valMap.end())
371 {
373 QString del_query = QString("DELETE FROM %1 WHERE %2 = :ID")
374 .arg(m_tableName, m_idName);
375 query.prepare(del_query);
376 query.bindValue(":ID", p->first);
377 if (!query.exec() || !query.isActive())
378 {
379 MythDB::DBError("multivalue remove", query);
380 }
381 m_valMap.erase(p);
382 }
383 }
384
385 bool exists(int id, int value)
386 {
387 auto p = m_valMap.find(id);
388 if (p != m_valMap.end())
389 {
390 auto vp =
391 std::find(p->second.values.begin(), p->second.values.end(),
392 value);
393 return vp != p->second.values.end();
394 }
395 return false;
396 }
397
398 bool exists(int id)
399 {
400 return m_valMap.contains(id);
401 }
402
403 private:
405 {
406 m_valMap.clear();
407
409
410 if (query.exec(m_fillSql) && query.size() > 0)
411 {
412 auto p = m_valMap.end();
413 while (query.next())
414 {
415 int id = query.value(0).toInt();
416 int val = query.value(1).toInt();
417
418 if (p == m_valMap.end() ||
419 (p != m_valMap.end() && p->first != id))
420 {
421 p = m_valMap.find(id);
422 if (p == m_valMap.end())
423 {
424 entry e;
425 e.id = id;
426 p = m_valMap.insert(id_map::value_type(id, e)).first;
427 }
428 }
429 p->second.values.push_back(val);
430 }
431 }
432 }
433
434 private:
436
437 QString m_tableName;
438 QString m_idName;
439 QString m_valueName;
440
441 QString m_insertSql;
442 QString m_fillSql;
443 QString m_idSql;
444
445 bool m_ready {false};
447};
448
450
451int MultiValue::add(int id, int value)
452{
453 return m_imp->add(id, value);
454}
455
456bool MultiValue::get(int id, entry &values)
457{
458 return m_imp->get(id, values);
459}
460
461void MultiValue::remove(int id, int value)
462{
463 m_imp->remove(id, value);
464}
465
467{
468 m_imp->remove(id);
469}
470
471bool MultiValue::exists(int id, int value)
472{
473 return m_imp->exists(id, value);
474}
475
477{
478 return m_imp->exists(id);
479}
480
482{
483 m_imp->load_data();
484}
485
487
489 SingleValue(new SingleValueImp("videocategory", "intid", "category"))
490{
491}
492
494{
495 static VideoCategory s_vc;
496 s_vc.load_data();
497 return s_vc;
498}
499
501
503 SingleValue(new SingleValueImp("videocountry", "intid", "country"))
504{
505}
506
508{
509 static VideoCountry s_vc;
510 s_vc.load_data();
511 return s_vc;
512}
513
515
517 SingleValue(new SingleValueImp("videogenre", "intid", "genre"))
518{
519}
520
522{
523 static VideoGenre s_vg;
524 s_vg.load_data();
525 return s_vg;
526}
527
529
531 SingleValue(new SingleValueImp("videocast", "intid", "cast"))
532{
533}
534
536{
537 static VideoCast s_vc;
538 s_vc.load_data();
539 return s_vc;
540}
541
543
545 MultiValue(new MultiValueImp("videometadatagenre", "idvideo", "idgenre"))
546{
547}
548
550{
551 static VideoGenreMap s_vgm;
552 s_vgm.load_data();
553 return s_vgm;
554}
555
557
559 MultiValue(new MultiValueImp("videometadatacountry", "idvideo",
560 "idcountry"))
561{
562}
563
565{
566 static VideoCountryMap s_vcm;
567 s_vcm.load_data();
568 return s_vcm;
569}
570
572
574 MultiValue(new MultiValueImp("videometadatacast", "idvideo",
575 "idcast"))
576{
577}
578
580{
581 static VideoCastMap s_vcm;
582 s_vcm.load_data();
583 return s_vcm;
584}
585
587
589{
590 public:
594
595 public:
597
599 {
600 file_association ret_fa(fa);
601
602 file_association *existing_fa = nullptr;
604
605 auto p = find(ret_fa.extension);
606 if (p != m_fileAssociations.end())
607 {
608 ret_fa.id = p->id;
609 existing_fa = &(*p);
610
611 query.prepare("UPDATE videotypes SET extension = :EXT, "
612 "playcommand = :PLAYCMD, f_ignore = :IGNORED, "
613 "use_default = :USEDEFAULT WHERE intid = :ID");
614 query.bindValue(":ID", ret_fa.id);
615 }
616 else
617 {
618 query.prepare("INSERT INTO videotypes (extension, playcommand, "
619 "f_ignore, use_default) VALUES "
620 "(:EXT, :PLAYCMD, :IGNORED, :USEDEFAULT)");
621 }
622
623 query.bindValue(":EXT", ret_fa.extension);
624 query.bindValue(":PLAYCMD", ret_fa.playcommand);
625 query.bindValue(":IGNORED", ret_fa.ignore);
626 query.bindValue(":USEDEFAULT", ret_fa.use_default);
627
628 if (query.exec() && query.isActive())
629 {
630 if (!existing_fa)
631 {
632 if (query.exec("SELECT LAST_INSERT_ID()") && query.next())
633 {
634 ret_fa.id = query.value(0).toUInt();
635 m_fileAssociations.push_back(ret_fa);
636 }
637 else
638 {
639 return false;
640 }
641 }
642 else
643 {
644 *existing_fa = ret_fa;
645 }
646
647 fa = ret_fa;
648 return true;
649 }
650
651 return false;
652 }
653
654 bool get(unsigned int id, file_association &val) const
655 {
656 auto p = cfind(id);
657 if (p != m_fileAssociations.end())
658 {
659 val = *p;
660 return true;
661 }
662 return false;
663 }
664
665 bool get(const QString &ext, file_association &val) const
666 {
667 auto p = cfind(ext);
668 if (p != m_fileAssociations.end())
669 {
670 val = *p;
671 return true;
672 }
673 return false;
674 }
675
676 bool remove(unsigned int id)
677 {
678 auto p = find(id);
679 if (p != m_fileAssociations.end())
680 {
682 query.prepare("DELETE FROM videotypes WHERE intid = :ID");
683 query.bindValue(":ID", p->id);
684 if (query.exec())
685 {
686 m_fileAssociations.erase(p);
687 return true;
688 }
689 }
690 return false;
691 }
692
694 {
695 return m_fileAssociations;
696 }
697
699 {
700 for (const auto & fa : m_fileAssociations)
701 ext_ignore.emplace_back(fa.extension, fa.ignore);
702 }
703
704 mutable QMutex m_mutex;
705
707 {
708 QMutexLocker locker(&m_mutex);
709 if (!m_ready)
710 {
711 fill_from_db();
712 m_ready = true;
713 }
714 }
715
716 void cleanup()
717 {
718 m_ready = false;
719 m_fileAssociations.clear();
720 }
721
722 private:
724 {
726 if (query.exec("SELECT intid, extension, playcommand, f_ignore, "
727 "use_default FROM videotypes"))
728 {
729 while (query.next())
730 {
731 file_association fa(query.value(0).toUInt(),
732 query.value(1).toString(),
733 query.value(2).toString(),
734 query.value(3).toBool(),
735 query.value(4).toBool());
736 m_fileAssociations.push_back(fa);
737 }
738 }
739 }
740
741 association_list::iterator find(const QString &ext)
742 {
743 for (auto p = m_fileAssociations.begin();
744 p != m_fileAssociations.end(); ++p)
745 {
746 if (p->extension.length() == ext.length() &&
747 ext.indexOf(p->extension) == 0)
748 {
749 return p;
750 }
751 }
752 return m_fileAssociations.end();
753 }
754
755 association_list::iterator find(unsigned int id)
756 {
757 for (auto p = m_fileAssociations.begin();
758 p != m_fileAssociations.end(); ++p)
759 {
760 if (p->id == id) return p;
761 }
762 return m_fileAssociations.end();
763 }
764
765 association_list::const_iterator cfind(const QString &ext) const
766 {
767 for (auto p = m_fileAssociations.cbegin();
768 p != m_fileAssociations.cend(); ++p)
769 {
770 if (p->extension.length() == ext.length() &&
771 ext.indexOf(p->extension) == 0)
772 {
773 return p;
774 }
775 }
776 return m_fileAssociations.cend();
777 }
778
779 association_list::const_iterator cfind(unsigned int id) const
780 {
781 for (auto p = m_fileAssociations.cbegin();
782 p != m_fileAssociations.cend(); ++p)
783 {
784 if (p->id == id) return p;
785 }
786 return m_fileAssociations.cend();
787 }
788
789 private:
791 bool m_ready {false};
792};
793
794
796{
797 return m_imp->add(fa);
798}
799
800bool FileAssociations::get(unsigned int id, file_association &val) const
801{
802 return m_imp->get(id, val);
803}
804
805bool FileAssociations::get(const QString &ext, file_association &val) const
806{
807 return m_imp->get(ext, val);
808}
809
810bool FileAssociations::remove(unsigned int id)
811{
812 return m_imp->remove(id);
813}
814
816{
817 return m_imp->getList();
818}
819
821{
822 m_imp->getExtensionIgnoreList(ext_ignore);
823}
824
826{
827 m_imp->load_data();
828}
829
831 : m_imp(new FileAssociationsImp)
832{
833}
834
836{
837 delete m_imp;
838}
839
841{
842 static FileAssociations s_fa;
843 s_fa.load_data();
844 return s_fa;
845}
FileAssociationsImp()=default
bool remove(unsigned int id)
Definition: dbaccess.cpp:676
bool get(unsigned int id, file_association &val) const
Definition: dbaccess.cpp:654
association_list::iterator find(unsigned int id)
Definition: dbaccess.cpp:755
association_list::const_iterator cfind(unsigned int id) const
Definition: dbaccess.cpp:779
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:698
FileAssociations::ext_ignore_list ext_ignore_list
Definition: dbaccess.cpp:593
const association_list & getList() const
Definition: dbaccess.cpp:693
bool get(const QString &ext, file_association &val) const
Definition: dbaccess.cpp:665
association_list m_fileAssociations
Definition: dbaccess.cpp:790
FileAssociations::association_list association_list
Definition: dbaccess.cpp:592
bool add(file_association &fa)
Definition: dbaccess.cpp:598
association_list::const_iterator cfind(const QString &ext) const
Definition: dbaccess.cpp:765
association_list::iterator find(const QString &ext)
Definition: dbaccess.cpp:741
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:820
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:155
bool add(file_association &fa)
Definition: dbaccess.cpp:795
bool remove(unsigned int id)
Definition: dbaccess.cpp:810
bool get(unsigned int id, file_association &val) const
Definition: dbaccess.cpp:800
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:840
const association_list & getList() const
Definition: dbaccess.cpp:815
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:838
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:619
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
int add(int id, int value)
Definition: dbaccess.cpp:291
bool get(int id, entry &values)
Definition: dbaccess.cpp:331
QString m_idName
Definition: dbaccess.cpp:438
QString m_fillSql
Definition: dbaccess.cpp:442
std::map< int, entry > id_map
Definition: dbaccess.cpp:259
void fill_from_db()
Definition: dbaccess.cpp:404
void cleanup()
Definition: dbaccess.cpp:285
bool exists(int id)
Definition: dbaccess.cpp:398
QString m_tableName
Definition: dbaccess.cpp:437
QString m_valueName
Definition: dbaccess.cpp:439
QString m_insertSql
Definition: dbaccess.cpp:441
void load_data()
Definition: dbaccess.cpp:275
bool exists(int id, int value)
Definition: dbaccess.cpp:385
SimpleCleanup< MultiValueImp > m_cleanStub
Definition: dbaccess.cpp:446
void remove(int id)
Definition: dbaccess.cpp:367
id_map m_valMap
Definition: dbaccess.cpp:435
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:342
QString m_idSql
Definition: dbaccess.cpp:443
int add(int id, int value)
Definition: dbaccess.cpp:451
bool get(int id, entry &values)
Definition: dbaccess.cpp:456
void load_data()
Definition: dbaccess.cpp:481
MultiValueImp * m_imp
Definition: dbaccess.h:63
bool exists(int id, int value)
Definition: dbaccess.cpp:471
void remove(int id, int value)
Definition: dbaccess.cpp:461
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
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:579
static VideoCast & GetCast()
Definition: dbaccess.cpp:535
static VideoCategory & GetCategory()
Definition: dbaccess.cpp:493
static VideoCountryMap & getCountryMap()
Definition: dbaccess.cpp:564
static VideoCountry & getCountry()
Definition: dbaccess.cpp:507
static VideoGenreMap & getGenreMap()
Definition: dbaccess.cpp:549
static VideoGenre & getGenre()
Definition: dbaccess.cpp:521
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:61
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