Merge pull request #26350 from jjd-uk/estuary_media_align
[xbmc.git] / xbmc / dbwrappers / dataset.cpp
blob69aa5efd374b198f98ad24a35201918bab442133
1 /*
2 * Copyright (C) 2004, Leo Seib, Hannover
4 * Project: C++ Dynamic Library
5 * Module: Dataset abstraction layer realisation file
6 * Author: Leo Seib E-Mail: leoseib@web.de
7 * Begin: 5/04/2002
9 * SPDX-License-Identifier: MIT
10 * See LICENSES/README.md for more information.
13 #include "dataset.h"
15 #include "utils/StringUtils.h"
16 #include "utils/log.h"
18 #include <algorithm>
19 #include <cstring>
21 #ifndef __GNUC__
22 #pragma warning(disable : 4800)
23 #endif
25 namespace dbiplus
27 //************* Database implementation ***************
29 Database::Database()
30 : error(), //S_NO_CONNECTION,
31 host(),
32 port(),
33 db(),
34 login(),
35 passwd(),
36 sequence_table("db_sequence")
38 active = false; // No connection yet
39 compression = false;
42 Database::~Database()
44 disconnect(); // Disconnect if connected to database
47 int Database::connectFull(const char* newHost,
48 const char* newPort,
49 const char* newDb,
50 const char* newLogin,
51 const char* newPasswd,
52 const char* newKey,
53 const char* newCert,
54 const char* newCA,
55 const char* newCApath,
56 const char* newCiphers,
57 bool newCompression)
59 host = newHost;
60 port = newPort;
61 db = newDb;
62 login = newLogin;
63 passwd = newPasswd;
64 key = newKey;
65 cert = newCert;
66 ca = newCA;
67 capath = newCApath;
68 ciphers = newCiphers;
69 compression = newCompression;
70 return connect(true);
73 std::string Database::prepare(const char* format, ...)
75 va_list args;
76 va_start(args, format);
77 std::string result = vprepare(format, args);
78 va_end(args);
80 return result;
83 //************* Dataset implementation ***************
85 Dataset::Dataset() : select_sql("")
88 db = NULL;
89 haveError = active = false;
90 frecno = 0;
91 fbof = feof = true;
92 autocommit = true;
94 fields_object = new Fields();
96 edit_object = new Fields();
99 Dataset::Dataset(Database* newDb) : select_sql("")
102 db = newDb;
103 haveError = active = false;
104 frecno = 0;
105 fbof = feof = true;
106 autocommit = true;
108 fields_object = new Fields();
110 edit_object = new Fields();
113 Dataset::~Dataset()
115 update_sql.clear();
116 insert_sql.clear();
117 delete_sql.clear();
119 delete fields_object;
120 delete edit_object;
123 void Dataset::setSqlParams(sqlType t, const char* sqlFrmt, ...)
125 va_list ap;
126 char sqlCmd[DB_BUFF_MAX + 1];
128 va_start(ap, sqlFrmt);
129 #ifndef TARGET_POSIX
130 _vsnprintf(sqlCmd, DB_BUFF_MAX - 1, sqlFrmt, ap);
131 #else
132 vsnprintf(sqlCmd, DB_BUFF_MAX - 1, sqlFrmt, ap);
133 #endif
134 va_end(ap);
136 switch (t)
138 case sqlSelect:
139 set_select_sql(sqlCmd);
140 break;
141 case sqlUpdate:
142 add_update_sql(sqlCmd);
143 break;
144 case sqlInsert:
145 add_insert_sql(sqlCmd);
146 break;
147 case sqlDelete:
148 add_delete_sql(sqlCmd);
149 break;
150 case sqlExec:
151 sql = sqlCmd;
152 break;
156 void Dataset::set_select_sql(const char* sel_sql)
158 select_sql = sel_sql;
161 void Dataset::set_select_sql(const std::string& sel_sql)
163 select_sql = sel_sql;
166 void Dataset::parse_sql(std::string& sql)
168 std::string fpattern, by_what;
169 for (unsigned int i = 0; i < fields_object->size(); i++)
171 fpattern = ":OLD_" + (*fields_object)[i].props.name;
172 by_what = "'" + (*fields_object)[i].val.get_asString() + "'";
173 int idx = 0;
174 int next_idx = 0;
175 while ((idx = sql.find(fpattern, next_idx)) >= 0)
177 next_idx = idx + fpattern.size();
178 if (sql.length() > ((unsigned int)next_idx))
179 if (isalnum(sql[next_idx]) || sql[next_idx] == '_')
181 continue;
183 sql.replace(idx, fpattern.size(), by_what);
184 } //while
185 } //for
187 for (unsigned int i = 0; i < edit_object->size(); i++)
189 fpattern = ":NEW_" + (*edit_object)[i].props.name;
190 by_what = "'" + (*edit_object)[i].val.get_asString() + "'";
191 int idx = 0;
192 int next_idx = 0;
193 while ((idx = sql.find(fpattern, next_idx)) >= 0)
195 next_idx = idx + fpattern.size();
196 if (sql.length() > ((unsigned int)next_idx))
197 if (isalnum(sql[next_idx]) || sql[next_idx] == '_')
199 continue;
201 sql.replace(idx, fpattern.size(), by_what);
202 } //while
203 } //for
206 void Dataset::close(void)
208 haveError = false;
209 frecno = 0;
210 fbof = feof = true;
211 active = false;
213 name2indexMap.clear();
216 bool Dataset::seek(int pos)
218 frecno = (pos < num_rows() - 1) ? pos : num_rows() - 1;
219 frecno = (frecno < 0) ? 0 : frecno;
220 fbof = feof = (num_rows() == 0) ? true : false;
221 return ((bool)frecno);
224 void Dataset::refresh()
226 int row = frecno;
227 if ((row != 0) && active)
229 close();
230 open();
231 seek(row);
233 else
234 open();
237 void Dataset::first()
239 if (ds_state == dsSelect)
241 frecno = 0;
242 feof = fbof = (num_rows() > 0) ? false : true;
246 void Dataset::next()
248 if (ds_state == dsSelect)
250 fbof = false;
251 if (frecno < num_rows() - 1)
253 frecno++;
254 feof = false;
256 else
257 feof = true;
258 if (num_rows() <= 0)
259 fbof = feof = true;
263 void Dataset::prev()
265 if (ds_state == dsSelect)
267 feof = false;
268 if (frecno)
270 frecno--;
271 fbof = false;
273 else
274 fbof = true;
275 if (num_rows() <= 0)
276 fbof = feof = true;
280 void Dataset::last()
282 if (ds_state == dsSelect)
284 frecno = (num_rows() > 0) ? num_rows() - 1 : 0;
285 feof = fbof = (num_rows() > 0) ? false : true;
289 bool Dataset::goto_rec(int pos)
291 if (ds_state == dsSelect)
293 return seek(pos - 1);
295 return false;
298 void Dataset::insert()
300 edit_object->resize(field_count());
301 for (int i = 0; i < field_count(); i++)
303 (*fields_object)[i].val = "";
304 (*edit_object)[i].val = "";
305 (*edit_object)[i].props = (*fields_object)[i].props;
307 ds_state = dsInsert;
310 void Dataset::edit()
312 if (ds_state != dsSelect)
314 throw DbErrors("Editing is possible only when query exists!");
316 edit_object->resize(field_count());
317 for (unsigned int i = 0; i < fields_object->size(); i++)
319 (*edit_object)[i].props = (*fields_object)[i].props;
320 (*edit_object)[i].val = (*fields_object)[i].val;
322 ds_state = dsEdit;
325 void Dataset::post()
327 if (ds_state == dsInsert)
328 make_insert();
329 else if (ds_state == dsEdit)
330 make_edit();
333 void Dataset::del()
335 ds_state = dsDelete;
338 void Dataset::deletion()
340 if (ds_state == dsDelete)
341 make_deletion();
344 bool Dataset::set_field_value(const char* f_name, const field_value& value)
346 if ((ds_state == dsInsert) || (ds_state == dsEdit))
348 const int idx = fieldIndex(f_name);
349 if (idx >= 0)
351 (*edit_object)[idx].val = value;
352 return true;
354 throw DbErrors("Field not found: %s", f_name);
356 throw DbErrors("Not in Insert or Edit state");
357 // return false;
360 const field_value& Dataset::get_field_value(const char* f_name)
362 if (ds_state != dsInactive)
364 if (ds_state == dsEdit || ds_state == dsInsert)
366 const int idx = fieldIndex(f_name);
367 if (idx >= 0)
368 return (*edit_object)[idx].val;
370 throw DbErrors("Field not found: %s", f_name);
372 else
374 int idx = fieldIndex(f_name);
375 if (idx < 0)
377 const char* name = strstr(f_name, ".");
378 if (name)
379 name++;
381 if (name)
382 idx = fieldIndex(name);
385 if (idx >= 0)
386 return (*fields_object)[idx].val;
388 throw DbErrors("Field not found: %s", f_name);
391 throw DbErrors("Dataset state is Inactive");
394 const field_value& Dataset::get_field_value(int index)
396 if (ds_state != dsInactive)
398 if (ds_state == dsEdit || ds_state == dsInsert)
400 if (index < 0 || index >= field_count())
401 throw DbErrors("Field index not found: %d", index);
403 return (*edit_object)[index].val;
405 else
407 if (index < 0 || index >= field_count())
408 throw DbErrors("Field index not found: %d", index);
410 return (*fields_object)[index].val;
413 throw DbErrors("Dataset state is Inactive");
416 const sql_record* Dataset::get_sql_record()
418 if (result.records.empty() || frecno >= (int)result.records.size())
419 return NULL;
421 return result.records[frecno];
424 field_value Dataset::f_old(const char* f_name)
426 if (ds_state != dsInactive)
427 for (int unsigned i = 0; i < fields_object->size(); i++)
428 if ((*fields_object)[i].props.name == f_name)
429 return (*fields_object)[i].val;
430 return {};
433 void Dataset::setParamList(const ParamList& params)
435 plist = params;
438 bool Dataset::locate()
440 bool result;
441 if (plist.empty())
442 return false;
444 std::map<std::string, field_value>::const_iterator i;
445 first();
446 while (!eof())
448 result = true;
449 for (i = plist.begin(); i != plist.end(); ++i)
450 if (fv(i->first.c_str()).get_asString() == i->second.get_asString())
452 continue;
454 else
456 result = false;
457 break;
459 if (result)
461 return result;
463 next();
465 return false;
468 bool Dataset::locate(const ParamList& params)
470 plist = params;
471 return locate();
474 bool Dataset::findNext(void)
476 bool result;
477 if (plist.empty())
478 return false;
480 std::map<std::string, field_value>::const_iterator i;
481 while (!eof())
483 result = true;
484 for (i = plist.begin(); i != plist.end(); ++i)
485 if (fv(i->first.c_str()).get_asString() == i->second.get_asString())
487 continue;
489 else
491 result = false;
492 break;
494 if (result)
496 return result;
498 next();
500 return false;
503 void Dataset::add_update_sql(const char* upd_sql)
505 std::string s = upd_sql;
506 update_sql.push_back(s);
509 void Dataset::add_update_sql(const std::string& upd_sql)
511 update_sql.push_back(upd_sql);
514 void Dataset::add_insert_sql(const char* ins_sql)
516 std::string s = ins_sql;
517 insert_sql.push_back(s);
520 void Dataset::add_insert_sql(const std::string& ins_sql)
522 insert_sql.push_back(ins_sql);
525 void Dataset::add_delete_sql(const char* del_sql)
527 std::string s = del_sql;
528 delete_sql.push_back(s);
531 void Dataset::add_delete_sql(const std::string& del_sql)
533 delete_sql.push_back(del_sql);
536 void Dataset::clear_update_sql()
538 update_sql.clear();
541 void Dataset::clear_insert_sql()
543 insert_sql.clear();
546 void Dataset::clear_delete_sql()
548 delete_sql.clear();
551 size_t Dataset::insert_sql_count()
553 return insert_sql.size();
556 size_t Dataset::delete_sql_count()
558 return delete_sql.size();
561 int Dataset::field_count()
563 return fields_object->size();
565 int Dataset::fieldCount()
567 return fields_object->size();
570 const char* Dataset::fieldName(int n)
572 if (n < field_count() && n >= 0)
573 return (*fields_object)[n].props.name.c_str();
574 else
575 return NULL;
578 char* Dataset::str_toLower(char* s)
580 for (char* p = s; *p; p++)
581 *p = std::tolower(*p);
583 return s;
586 int Dataset::fieldIndex(const char* fn)
588 std::string name(fn);
589 const auto it = name2indexMap.find(str_toLower(name.data()));
590 if (it != name2indexMap.end())
591 return (*it).second;
592 else
593 return -1;
596 //************* DbErrors implementation ***************
598 DbErrors::DbErrors() : msg_("Unknown Database Error")
602 DbErrors::DbErrors(const char* msg, ...)
604 va_list vl;
605 va_start(vl, msg);
606 char buf[DB_BUFF_MAX] = "";
607 #ifndef TARGET_POSIX
608 _vsnprintf(buf, DB_BUFF_MAX - 1, msg, vl);
609 #else
610 vsnprintf(buf, DB_BUFF_MAX - 1, msg, vl);
611 #endif
612 va_end(vl);
613 msg_ = "SQL: ";
614 msg_ += buf;
616 CLog::Log(LOGERROR, "{}", msg_);
619 const char* DbErrors::getMsg()
621 return msg_.c_str();
624 } // namespace dbiplus