KDb

KDb.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2004-2018 JarosÅ‚aw Staniek <[email protected]>
3  Copyright (c) 2006, 2007 Thomas Braxton <[email protected]>
4  Copyright (c) 1999 Preston Brown <[email protected]>
5  Copyright (c) 1997 Matthias Kalle Dalheimer <[email protected]>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21 */
22 
23 #include "KDb.h"
24 #include "KDbConnection.h"
25 #include "KDbConnectionData.h"
26 #include "KDbCursor.h"
27 #include "KDbDateTime.h"
28 #include "KDbDriverBehavior.h"
29 #include "KDbDriverManager.h"
30 #include "KDbDriver_p.h"
31 #include "KDbLookupFieldSchema.h"
32 #include "KDbMessageHandler.h"
33 #include "KDbNativeStatementBuilder.h"
34 #include "KDbQuerySchema.h"
35 #include "KDbRecordData.h"
36 #include "KDbSqlResult.h"
37 #include "KDbTableOrQuerySchema.h"
38 #include "KDbVersionInfo.h"
39 #include "KDb_p.h"
40 #include "kdb_debug.h"
41 #include "transliteration/transliteration_table.h"
42 
43 #include <QMap>
44 #include <QHash>
45 #include <QBuffer>
46 #include <QPixmap>
47 #include <QSet>
48 #include <QTimer>
49 #include <QThread>
50 #include <QProgressDialog>
51 #include <QDomNode>
52 #include <QApplication>
53 #include <QDir>
54 #include <QProcess>
55 #include <QtDebug>
56 
57 #include <limits>
58 #include <memory>
59 
60 Q_DECLARE_METATYPE(KDbField::Type)
61 
62 class ConnectionTestDialog;
63 
64 class ConnectionTestThread : public QThread
65 {
66  Q_OBJECT
67 public:
68  ConnectionTestThread(ConnectionTestDialog *dlg, const KDbConnectionData& connData);
69  void run() override;
70 Q_SIGNALS:
71  void error(const QString& msg, const QString& details);
72 protected:
73  void emitError(const KDbResultable& KDbResultable);
74 
75  ConnectionTestDialog* m_dlg;
76  KDbConnectionData m_connData;
77  KDbDriver *m_driver;
78 private:
79  Q_DISABLE_COPY(ConnectionTestThread)
80 };
81 
82 class ConnectionTestDialog : public QProgressDialog // krazy:exclude=qclasses
83 {
84  Q_OBJECT
85 public:
86  ConnectionTestDialog(const KDbConnectionData& data, KDbMessageHandler* msgHandler,
87  QWidget* parent = nullptr);
88  ~ConnectionTestDialog() override;
89 
90  int exec() override;
91 
92 public Q_SLOTS:
93  void error(const QString& msg, const QString& details);
94 
95 protected Q_SLOTS:
96  void slotTimeout();
97  void accept() override;
98  void reject() override;
99 
100 protected:
101  void finish();
102 
104  KDbConnectionData m_connData;
105  QTimer m_timer;
106  KDbMessageHandler* m_msgHandler;
107  int m_elapsedTime;
108  bool m_error;
109  QString m_msg;
110  QString m_details;
111  bool m_stopWaiting;
112 
113 private:
114  Q_DISABLE_COPY(ConnectionTestDialog)
115 };
116 
117 ConnectionTestThread::ConnectionTestThread(ConnectionTestDialog* dlg, const KDbConnectionData& connData)
118  : m_dlg(dlg), m_connData(connData)
119 {
120  connect(this, SIGNAL(error(QString,QString)),
122 
123  // try to load driver now because it's not supported in different thread
124  KDbDriverManager manager;
125  m_driver = manager.driver(m_connData.driverId());
126  if (manager.result().isError()) {
127  emitError(*manager.resultable());
128  m_driver = nullptr;
129  }
130 }
131 
132 void ConnectionTestThread::emitError(const KDbResultable& KDbResultable)
133 {
134  QString msg;
135  QString details;
136  KDb::getHTMLErrorMesage(KDbResultable, &msg, &details);
137  emit error(msg, details);
138 }
139 
140 void ConnectionTestThread::run()
141 {
142  if (!m_driver) {
143  return;
144  }
145  QScopedPointer<KDbConnection> conn(m_driver->createConnection(m_connData));
146  if (conn.isNull() || m_driver->result().isError()) {
147  emitError(*m_driver);
148  return;
149  }
150  if (!conn->connect() || conn->result().isError()) {
151  emitError(*conn);
152  return;
153  }
154  // SQL database backends like PostgreSQL require executing "USE database"
155  // if we really want to know connection to the server succeeded.
156  QString tmpDbName;
157  if (!conn->useTemporaryDatabaseIfNeeded(&tmpDbName)) {
158  emitError(*conn);
159  return;
160  }
161  if (!tmpDbName.isEmpty()) {
162  if (!conn->closeDatabase()) {
163  emitError(*conn);
164  }
165  }
166  emitError(KDbResultable());
167 }
168 
169 ConnectionTestDialog::ConnectionTestDialog(const KDbConnectionData& data,
170  KDbMessageHandler* msgHandler, QWidget* parent)
171  : QProgressDialog(parent)
172  , m_thread(new ConnectionTestThread(this, data))
173  , m_connData(data)
174  , m_msgHandler(msgHandler)
175  , m_elapsedTime(0)
176  , m_error(false)
177  , m_stopWaiting(false)
178 {
179  setWindowTitle(tr("Test Connection", "Dialog's title: testing database connection"));
180  setLabelText(tr("Testing connection to \"%1\" database server...")
181  .arg(data.toUserVisibleString()));
182  setModal(true);
183  setRange(0, 0); //to show busy indicator
184  connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
185  adjustSize();
186  resize(250, height());
187 }
188 
189 ConnectionTestDialog::~ConnectionTestDialog()
190 {
191  if (m_thread->isRunning()) {
192  m_thread->terminate();
193  }
194  m_thread->deleteLater();
195 }
196 
197 int ConnectionTestDialog::exec()
198 {
199  //kdbDebug() << "tid:" << QThread::currentThread() << "this_thread:" << thread();
200  m_timer.start(20);
201  m_thread->start();
202  const int res = QProgressDialog::exec(); // krazy:exclude=qclasses
203  m_thread->wait();
204  m_timer.stop();
205  return res;
206 }
207 
208 void ConnectionTestDialog::slotTimeout()
209 {
210  //kdbDebug() << "tid:" << QThread::currentThread() << "this_thread:" << thread();
211  //kdbDebug() << m_error;
212  bool notResponding = false;
213  if (m_elapsedTime >= 1000*5) {//5 seconds
214  m_stopWaiting = true;
215  notResponding = true;
216  }
217  //kdbDebug() << m_elapsedTime << m_stopWaiting << notResponding;
218  if (m_stopWaiting) {
219  m_timer.disconnect(this);
220  m_timer.stop();
222  QString details;
224  if (m_error) {
225  reject();
226  //kdbDebug() << "after reject";
227  message = tr("Test connection to \"%1\" database server failed.")
228  .arg(m_connData.toUserVisibleString());
229  details = m_msg;
230  if (!m_details.isEmpty()) {
231  details += QLatin1Char('\n') + m_details;
232  }
233  type = KDbMessageHandler::Sorry;
234  m_error = false;
235  } else if (notResponding) {
236  reject();
237  //kdbDebug() << "after reject";
238  message = tr("Test connection to \"%1\" database server failed. The server is not responding.")
239  .arg(m_connData.toUserVisibleString());
240  type = KDbMessageHandler::Sorry;
241  } else {
242  accept();
243  //kdbDebug() << "after accept";
244  message = tr("Test connection to \"%1\" database server established successfully.")
245  .arg(m_connData.toUserVisibleString()),
246  type = KDbMessageHandler::Information;
247  }
248  if (m_msgHandler) {
249  m_msgHandler->showErrorMessage(type, message, details, tr("Test Connection"));
250  }
251  return;
252  }
253  m_elapsedTime += 20;
254  setValue(m_elapsedTime);
255 }
256 
257 void ConnectionTestDialog::error(const QString& msg, const QString& details)
258 {
259  //kdbDebug() << "tid:" << QThread::currentThread() << "this_thread:" << thread();
260  //kdbDebug() << msg << details;
261  m_stopWaiting = true;
262  m_msg = msg;
263  m_details = details;
264  m_error = !msg.isEmpty() || !details.isEmpty();
265  if (m_error) {
266  kdbDebug() << "Error:" << msg << details;
267  }
268 }
269 
270 void ConnectionTestDialog::accept()
271 {
272  finish();
273  QProgressDialog::accept(); // krazy:exclude=qclasses
274 }
275 
276 void ConnectionTestDialog::reject()
277 {
278  finish();
279  QProgressDialog::reject(); // krazy:exclude=qclasses
280 }
281 
282 void ConnectionTestDialog::finish()
283 {
284  if (m_thread->isRunning()) {
285  m_thread->terminate();
286  }
287  m_timer.disconnect(this);
288  m_timer.stop();
289 }
290 
291 // ----
292 
293 //! @return hex digit converted to integer (0 to 15), 0xFF on failure
294 inline static unsigned char hexDigitToInt(char digit)
295 {
296  if (digit >= '0' && digit <= '9') {
297  return digit - '0';
298  }
299  if (digit >= 'a' && digit <= 'f') {
300  return digit - 'a' + 10;
301  }
302  if (digit >= 'A' && digit <= 'F') {
303  return digit - 'A' + 10;
304  }
305  return 0xFF;
306 }
307 
308 //! Converts textual representation @a data of a hex number (@a length digits) to a byte array @a array
309 //! @return true on success and false if @a data contains characters that are not hex digits.
310 //! true is returned for empty @a data as well.
311 inline static bool hexToByteArrayInternal(const char* data, int length, QByteArray *array)
312 {
313  Q_ASSERT(length >= 0);
314  Q_ASSERT(data || length == 0);
315  array->resize(length / 2 + length % 2);
316  for(int i = 0; length > 0; --length, ++data, ++i) {
317  unsigned char d1 = hexDigitToInt(data[0]);
318  unsigned char d2;
319  if (i == 0 && (length % 2) == 1) { // odd number of digits; no leading 0
320  d2 = d1;
321  d1 = 0;
322  }
323  else {
324  --length;
325  ++data;
326  d2 = hexDigitToInt(data[0]);
327  }
328  if (d1 == 0xFF || d2 == 0xFF) {
329  return false;
330  }
331  (*array)[i] = (d1 << 4) + d2;
332  }
333  return true;
334 }
335 
337 {
338  return KDbVersionInfo(
339  KDB_VERSION_MAJOR, KDB_VERSION_MINOR, KDB_VERSION_PATCH);
340 }
341 
342 bool KDb::deleteRecords(KDbConnection* conn, const QString &tableName,
343  const QString &keyname, KDbField::Type keytype, const QVariant &keyval)
344 {
345  return conn
346  ? conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3")
347  .arg(conn->escapeIdentifier(tableName))
348  .arg(conn->escapeIdentifier(keyname))
349  .arg(conn->driver()->valueToSql(keytype, keyval)))
350  : false;
351 }
352 
353 bool KDb::deleteRecords(KDbConnection* conn, const QString &tableName,
354  const QString &keyname1, KDbField::Type keytype1, const QVariant& keyval1,
355  const QString &keyname2, KDbField::Type keytype2, const QVariant& keyval2)
356 {
357  return conn
358  ? conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5")
359  .arg(conn->escapeIdentifier(tableName))
360  .arg(conn->escapeIdentifier(keyname1))
361  .arg(conn->driver()->valueToSql(keytype1, keyval1))
362  .arg(conn->escapeIdentifier(keyname2))
363  .arg(conn->driver()->valueToSql(keytype2, keyval2)))
364  : false;
365 }
366 
367 bool KDb::deleteRecords(KDbConnection* conn, const QString &tableName,
368  const QString &keyname1, KDbField::Type keytype1, const QVariant& keyval1,
369  const QString &keyname2, KDbField::Type keytype2, const QVariant& keyval2,
370  const QString &keyname3, KDbField::Type keytype3, const QVariant& keyval3)
371 {
372  return conn
373  ? conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5 AND %6=%7")
374  .arg(conn->escapeIdentifier(tableName))
375  .arg(conn->escapeIdentifier(keyname1))
376  .arg(conn->driver()->valueToSql(keytype1, keyval1))
377  .arg(conn->escapeIdentifier(keyname2))
378  .arg(conn->driver()->valueToSql(keytype2, keyval2))
379  .arg(conn->escapeIdentifier(keyname3))
380  .arg(conn->driver()->valueToSql(keytype3, keyval3)))
381  : false;
382 }
383 
384 bool KDb::deleteAllRecords(KDbConnection* conn, const QString &tableName)
385 {
386  return conn
387  ? conn->executeSql(
388  KDbEscapedString("DELETE FROM %1").arg(conn->escapeIdentifier(tableName)))
389  : false;
390 }
391 
393  const QString &autoIncrementFieldName,
394  const QString &tableName, quint64 *recordId)
395 {
396  if (!result) {
397  return std::numeric_limits<quint64>::max();
398  }
399  const quint64 foundRecordId = result->lastInsertRecordId();
400  if (recordId) {
401  *recordId = foundRecordId;
402  }
403  return KDb::lastInsertedAutoIncValue(result->connection(),
404  foundRecordId, autoIncrementFieldName, tableName);
405 }
406 
407 KDB_EXPORT quint64 KDb::lastInsertedAutoIncValue(KDbConnection *conn, const quint64 recordId,
408  const QString &autoIncrementFieldName,
409  const QString &tableName)
410 {
411  const KDbDriverBehavior *behavior = KDbDriverPrivate::behavior(conn->driver());
413  return recordId;
414  }
415  KDbRecordData rdata;
416  if (recordId == std::numeric_limits<quint64>::max()
417  || true != conn->querySingleRecord(
418  KDbEscapedString("SELECT ") + escapeIdentifier(tableName) + '.'
419  + escapeIdentifier(autoIncrementFieldName)
420  + " FROM " + escapeIdentifier(tableName)
421  + " WHERE " + behavior->ROW_ID_FIELD_NAME
422  + '=' + KDbEscapedString::number(recordId), &rdata))
423  {
424  return std::numeric_limits<quint64>::max();
425  }
426  return rdata[0].toULongLong();
427 }
428 
429 bool KDb::isEmptyValue(KDbField::Type type, const QVariant &value)
430 {
431  if (KDbField::isTextType(type)) {
432  return value.toString().isEmpty() && !value.toString().isNull();
433  }
434  else if (type == KDbField::BLOB) {
435  return value.toByteArray().isEmpty() && !value.toByteArray().isNull();
436  }
437  return value.isNull();
438 }
439 
441  const QString& fieldName, const QVariant& value)
442 {
443  if (value.isNull())
444  return KDbEscapedString(fieldName) + " IS NULL";
445  return KDbEscapedString(fieldName) + '=' + drv->valueToSql(t, value);
446 }
447 
448 //! Cache
449 struct TypeCache {
450  TypeCache() {
451  for (KDbField::Type t = KDbField::InvalidType; t <= KDbField::LastType; t = KDbField::Type(int(t) + 1)) {
454  QStringList name_list, str_list;
455  if (tlist.contains(tg)) {
456  list = tlist.value(tg);
457  name_list = nlist.value(tg);
458  str_list = slist.value(tg);
459  }
460  list += t;
461  name_list += KDbField::typeName(t);
462  str_list += KDbField::typeString(t);
463  tlist[ tg ] = list;
464  nlist[ tg ] = name_list;
465  slist[ tg ] = str_list;
466  }
467 
468  def_tlist[ KDbField::InvalidGroup ] = KDbField::InvalidType;
469  def_tlist[ KDbField::TextGroup ] = KDbField::Text;
470  def_tlist[ KDbField::IntegerGroup ] = KDbField::Integer;
471  def_tlist[ KDbField::FloatGroup ] = KDbField::Double;
472  def_tlist[ KDbField::BooleanGroup ] = KDbField::Boolean;
473  def_tlist[ KDbField::DateTimeGroup ] = KDbField::Date;
474  def_tlist[ KDbField::BLOBGroup ] = KDbField::BLOB;
475  }
476 
481 };
482 
483 Q_GLOBAL_STATIC(TypeCache, KDb_typeCache)
484 
485 const QList<KDbField::Type> KDb::fieldTypesForGroup(KDbField::TypeGroup typeGroup)
486 {
487  return KDb_typeCache->tlist.value(typeGroup);
488 }
489 
491 {
492  return KDb_typeCache->nlist.value(typeGroup);
493 }
494 
496 {
497  return KDb_typeCache->slist.value(typeGroup);
498 }
499 
501 {
502  return (typeGroup <= KDbField::LastTypeGroup) ? KDb_typeCache->def_tlist.value(typeGroup) : KDbField::InvalidType;
503 }
504 
505 void KDb::getHTMLErrorMesage(const KDbResultable& resultable, QString *msg, QString *details)
506 {
507  if (!msg) {
508  kdbWarning() << "Missing 'msg' parameter";
509  return;
510  }
511  if (!details) {
512  kdbWarning() << "Missing 'details' parameter";
513  return;
514  }
515  const KDbResult result(resultable.result());
516  if (!result.isError())
517  return;
518  //lower level message is added to the details, if there is alread message specified
519  if (!result.messageTitle().isEmpty())
520  *msg += QLatin1String("<p>") + result.messageTitle();
521 
522  if (msg->isEmpty())
523  *msg = QLatin1String("<p>") + result.message();
524  else
525  *details += QLatin1String("<p>") + result.message();
526 
527  if (!result.serverMessage().isEmpty())
528  *details += QLatin1String("<p><b>") + kdb::tr("Message from server:")
529  + QLatin1String("</b> ") + result.serverMessage();
530  if (!result.recentSqlString().isEmpty())
531  *details += QLatin1String("<p><b>") + kdb::tr("SQL statement:")
532  + QString::fromLatin1("</b> <tt>%1</tt>").arg(result.recentSqlString().toString());
533  int serverErrorCode = 0;
534  QString serverResultName;
535  if (result.isError()) {
536  serverErrorCode = result.serverErrorCode();
537  serverResultName = resultable.serverResultName();
538  }
539  if ( !details->isEmpty()
540  && ( !result.serverMessage().isEmpty()
541  || !result.recentSqlString().isEmpty()
542  || !serverResultName.isEmpty()
543  || serverErrorCode != 0)
544  )
545  {
546  *details += (QLatin1String("<p><b>") + kdb::tr("Server result code:")
547  + QLatin1String("</b> ") + QString::number(serverErrorCode));
548  if (!serverResultName.isEmpty()) {
549  *details += QString::fromLatin1(" (%1)").arg(serverResultName);
550  }
551  }
552  else {
553  if (!serverResultName.isEmpty()) {
554  *details += (QLatin1String("<p><b>") + kdb::tr("Server result:")
555  + QLatin1String("</b> ") + serverResultName);
556  }
557  }
558 
559  if (!details->isEmpty() && !details->startsWith(QLatin1String("<qt>"))) {
560  if (!details->startsWith(QLatin1String("<p>")))
561  details->prepend(QLatin1String("<p>"));
562  }
563 }
564 
565 void KDb::getHTMLErrorMesage(const KDbResultable& resultable, QString *msg)
566 {
567  getHTMLErrorMesage(resultable, msg, msg);
568 }
569 
571 {
572  if (!info) {
573  kdbWarning() << "Missing 'info' parameter";
574  return;
575  }
576  getHTMLErrorMesage(resultable, &info->message, &info->description);
577 }
578 
579 tristate KDb::idForObjectName(KDbConnection* conn, int *id, const QString& objName, int objType)
580 {
581  return conn
582  ? conn->querySingleNumber(
583  KDbEscapedString("SELECT o_id FROM kexi__objects WHERE o_name=%1 AND o_type=%2")
584  .arg(conn->escapeString(objName))
585  .arg(objType),
586  id)
587  : false;
588 }
589 
590 //-----------------------------------------
591 
593  KDbMessageHandler *msgHandler)
594 {
595  ConnectionTestDialog dlg(data, msgHandler, parent);
596  const int result = dlg.exec();
597  if (dlg.wasCanceled()) {
598  return cancelled;
599  }
600  return result == QDialog::Accepted;
601 }
602 
604  QString *tableName, QString *fieldName,
606 {
607  if (!tableName || !fieldName) {
608  return false;
609  }
610  const int id = string.indexOf(QLatin1Char('.'));
611  if (option & SetFieldNameIfNoTableName && id == -1) {
612  tableName->clear();
613  *fieldName = string;
614  return !fieldName->isEmpty();
615  }
616  if (id <= 0 || id == int(string.length() - 1))
617  return false;
618  *tableName = string.left(id);
619  *fieldName = string.mid(id + 1);
620  return !tableName->isEmpty() && !fieldName->isEmpty();
621 }
622 
624 {
625 //! @todo add check for decimal type as well
626  return KDbField::isFPNumericType(type);
627 }
628 
629 inline static QString numberToString(double value, int decimalPlaces, const QLocale *locale)
630 {
631 //! @todo round?
632  QString result;
633  if (decimalPlaces == 0) {
634  result = locale ? locale->toString(qlonglong(value))
635  : QString::number(qlonglong(value));
636  } else {
637  const int realDecimalPlaces = decimalPlaces < 0 ? 10 : decimalPlaces;
638  result = locale ? locale->toString(value, 'f', realDecimalPlaces)
639  : QString::number(value, 'f', realDecimalPlaces);
640  if (decimalPlaces < 0) { // cut off zeros
641  int i = result.length() - 1;
642  while (i > 0 && result[i] == QLatin1Char('0')) {
643  i--;
644  }
645  if (result[i].isDigit()) {// last digit
646  ++i;
647  }
648  result.truncate(i);
649  }
650  }
651  return result;
652 }
653 
654 QString KDb::numberToString(double value, int decimalPlaces)
655 {
656  return ::numberToString(value, decimalPlaces, nullptr);
657 }
658 
659 QString KDb::numberToLocaleString(double value, int decimalPlaces)
660 {
661  QLocale defaultLocale;
662  return ::numberToString(value, decimalPlaces, &defaultLocale);
663 }
664 
665 QString KDb::numberToLocaleString(double value, int decimalPlaces, const QLocale &locale)
666 {
667  return ::numberToString(value, decimalPlaces, &locale);
668 }
669 
671 {
672  if (type < int(KDbField::InvalidType) || type > int(KDbField::LastType)) {
673  return KDbField::InvalidType;
674  }
675  return static_cast<KDbField::Type>(type);
676 }
677 
679 {
680  if (typeGroup < int(KDbField::InvalidGroup) || typeGroup > int(KDbField::LastTypeGroup)) {
681  return KDbField::InvalidGroup;
682  }
683  return static_cast<KDbField::TypeGroup>(typeGroup);
684 }
685 
686 static bool setIntToFieldType(KDbField *field, const QVariant& value)
687 {
688  Q_ASSERT(field);
689  bool ok;
690  const int intType = value.toInt(&ok);
691  if (!ok) {//for sanity
692  kdbWarning() << "Could not convert value" << value << "to field type";
693  return false;
694  }
695  if (KDbField::InvalidType == KDb::intToFieldType(intType)) {//for sanity
696  kdbWarning() << "Invalid field type" << intType;
697  return false;
698  }
699  field->setType((KDbField::Type)intType);
700  return true;
701 }
702 
703 //! @internal for KDb::isBuiltinTableFieldProperty()
704 struct KDb_BuiltinFieldProperties {
705  KDb_BuiltinFieldProperties() {
706 #define ADD(name) set.insert(name)
707  ADD("type");
708  ADD("primaryKey");
709  ADD("indexed");
710  ADD("autoIncrement");
711  ADD("unique");
712  ADD("notNull");
713  ADD("allowEmpty");
714  ADD("unsigned");
715  ADD("name");
716  ADD("caption");
717  ADD("description");
718  ADD("maxLength");
719  ADD("maxLengthIsDefault");
720  ADD("precision");
721  ADD("defaultValue");
722  ADD("defaultWidth");
723  ADD("visibleDecimalPlaces");
724 //! @todo always update this when new builtins appear!
725 #undef ADD
726  }
727  QSet<QByteArray> set;
728 };
729 
730 //! for KDb::isBuiltinTableFieldProperty()
731 Q_GLOBAL_STATIC(KDb_BuiltinFieldProperties, KDb_builtinFieldProperties)
732 
733 
734 bool KDb::isBuiltinTableFieldProperty(const QByteArray& propertyName)
735 {
736  return KDb_builtinFieldProperties->set.contains(propertyName);
737 }
738 
739 static QVariant visibleColumnValue(const KDbLookupFieldSchema *lookup)
740 {
741  if (!lookup || lookup->visibleColumns().count() == 1) {
742  if (lookup) {
743  const QList<int> visibleColumns = lookup->visibleColumns();
744  if (!visibleColumns.isEmpty()) {
745  return visibleColumns.first();
746  }
747  }
748  return QVariant();
749  }
750  QList<QVariant> variantList;
751  const QList<int> visibleColumns(lookup->visibleColumns());
752  for(int column : visibleColumns) {
753  variantList.append(column);
754  }
755  return variantList;
756 }
757 
759 {
760  if (!values) {
761  return;
762  }
764  if (lookup) {
765  recordSource = lookup->recordSource();
766  }
767  values->insert("rowSource", lookup ? recordSource.name() : QVariant());
768  values->insert("rowSourceType", lookup ? recordSource.typeName() : QVariant());
769  values->insert("rowSourceValues",
770  (lookup && !recordSource.values().isEmpty()) ? recordSource.values() : QVariant());
771  values->insert("boundColumn", lookup ? lookup->boundColumn() : QVariant());
772  values->insert("visibleColumn", visibleColumnValue(lookup));
773  QList<QVariant> variantList;
774  if (lookup) {
775  const QList<int> columnWidths = lookup->columnWidths();
776  for(const QVariant& variant : columnWidths) {
777  variantList.append(variant);
778  }
779  }
780  values->insert("columnWidths", lookup ? variantList : QVariant());
781  values->insert("showColumnHeaders", lookup ? lookup->columnHeadersVisible() : QVariant());
782  values->insert("listRows", lookup ? lookup->maxVisibleRecords() : QVariant());
783  values->insert("limitToList", lookup ? lookup->limitToList() : QVariant());
784  values->insert("displayWidget", lookup ? int(lookup->displayWidget()) : QVariant());
785 }
786 
788 {
789  if (!values) {
790  return;
791  }
792  values->clear();
793  // normal values
794  values->insert("type", field.type());
795  const KDbField::Constraints constraints = field.constraints();
796  values->insert("primaryKey", constraints.testFlag(KDbField::PrimaryKey));
797  values->insert("indexed", constraints.testFlag(KDbField::Indexed));
798  values->insert("autoIncrement", KDbField::isAutoIncrementAllowed(field.type())
799  && constraints.testFlag(KDbField::AutoInc));
800  values->insert("unique", constraints.testFlag(KDbField::Unique));
801  values->insert("notNull", constraints.testFlag(KDbField::NotNull));
802  values->insert("allowEmpty", !constraints.testFlag(KDbField::NotEmpty));
803  const KDbField::Options options = field.options();
804  values->insert("unsigned", options.testFlag(KDbField::Unsigned));
805  values->insert("name", field.name());
806  values->insert("caption", field.caption());
807  values->insert("description", field.description());
808  values->insert("maxLength", field.maxLength());
809  values->insert("maxLengthIsDefault", field.maxLengthStrategy() & KDbField::DefaultMaxLength);
810  values->insert("precision", field.precision());
811  values->insert("defaultValue", field.defaultValue());
812 //! @todo IMPORTANT: values->insert("defaultWidth", field.defaultWidth());
814  values->insert("visibleDecimalPlaces", field.defaultValue());
815  }
816  // insert lookup-related values
817  const KDbLookupFieldSchema *lookup = field.table()->lookupFieldSchema(field);
818  KDb::getProperties(lookup, values);
819 }
820 
821 static bool containsLookupFieldSchemaProperties(const QMap<QByteArray, QVariant>& values)
822 {
824  it != values.constEnd(); ++it)
825  {
826  if (KDb::isLookupFieldSchemaProperty(it.key())) {
827  return true;
828  }
829  }
830  return false;
831 }
832 
834 {
835  if (!field) {
836  return false;
837  }
839  if ((it = values.find("type")) != values.constEnd()) {
840  if (!setIntToFieldType(field, *it))
841  return false;
842  }
843 
844 #define SET_BOOLEAN_FLAG(flag, value) { \
845  constraints |= KDbField::flag; \
846  if (!value) \
847  constraints ^= KDbField::flag; \
848  }
849 
850  KDbField::Constraints constraints = field->constraints();
851  bool ok = true;
852  if ((it = values.find("primaryKey")) != values.constEnd())
853  SET_BOOLEAN_FLAG(PrimaryKey, (*it).toBool());
854  if ((it = values.find("indexed")) != values.constEnd())
855  SET_BOOLEAN_FLAG(Indexed, (*it).toBool());
856  if ((it = values.find("autoIncrement")) != values.constEnd()
858  SET_BOOLEAN_FLAG(AutoInc, (*it).toBool());
859  if ((it = values.find("unique")) != values.constEnd())
860  SET_BOOLEAN_FLAG(Unique, (*it).toBool());
861  if ((it = values.find("notNull")) != values.constEnd())
862  SET_BOOLEAN_FLAG(NotNull, (*it).toBool());
863  if ((it = values.find("allowEmpty")) != values.constEnd())
864  SET_BOOLEAN_FLAG(NotEmpty, !(*it).toBool());
865  field->setConstraints(constraints);
866 
867  KDbField::Options options;
868  if ((it = values.find("unsigned")) != values.constEnd()) {
869  options |= KDbField::Unsigned;
870  if (!(*it).toBool())
871  options ^= KDbField::Unsigned;
872  }
873  field->setOptions(options);
874 
875  if ((it = values.find("name")) != values.constEnd())
876  field->setName((*it).toString());
877  if ((it = values.find("caption")) != values.constEnd())
878  field->setCaption((*it).toString());
879  if ((it = values.find("description")) != values.constEnd())
880  field->setDescription((*it).toString());
881  if ((it = values.find("maxLength")) != values.constEnd())
882  field->setMaxLength((*it).isNull() ? 0/*default*/ : (*it).toInt(&ok));
883  if (!ok)
884  return false;
885  if ((it = values.find("maxLengthIsDefault")) != values.constEnd()
886  && (*it).toBool())
887  {
889  }
890  if ((it = values.find("precision")) != values.constEnd())
891  field->setPrecision((*it).isNull() ? 0/*default*/ : (*it).toInt(&ok));
892  if (!ok)
893  return false;
894  if ((it = values.find("defaultValue")) != values.constEnd())
895  field->setDefaultValue(*it);
896 //! @todo IMPORTANT: defaultWidth
897 #if 0
898  if ((it = values.find("defaultWidth")) != values.constEnd())
899  field.setDefaultWidth((*it).isNull() ? 0/*default*/ : (*it).toInt(&ok));
900  if (!ok)
901  return false;
902 #endif
903 
904  // -- extended properties
905  if ((it = values.find("visibleDecimalPlaces")) != values.constEnd()
907  field->setVisibleDecimalPlaces((*it).isNull() ? -1/*default*/ : (*it).toInt(&ok));
908  if (!ok)
909  return false;
910 
911  if (field->table() && containsLookupFieldSchemaProperties(values)) {
912  KDbLookupFieldSchema *lookup = field->table()->lookupFieldSchema(*field);
914  if (!lookup) { // create lookup if needed
915  createdLookup.reset(lookup = new KDbLookupFieldSchema());
916  }
917  if (lookup->setProperties(values)) {
918  if (createdLookup) {
919  if (field->table()->setLookupFieldSchema(field->name(), lookup)) {
920  createdLookup.take(); // ownership passed
921  lookup = nullptr;
922  }
923  }
924  }
925  }
926 
927  return true;
928 #undef SET_BOOLEAN_FLAG
929 }
930 
931 //! @internal for isExtendedTableProperty()
932 struct KDb_ExtendedProperties {
933  KDb_ExtendedProperties() {
934 #define ADD(name) set.insert( name )
935  ADD("visibledecimalplaces");
936  ADD("rowsource");
937  ADD("rowsourcetype");
938  ADD("rowsourcevalues");
939  ADD("boundcolumn");
940  ADD("visiblecolumn");
941  ADD("columnwidths");
942  ADD("showcolumnheaders");
943  ADD("listrows");
944  ADD("limittolist");
945  ADD("displaywidget");
946 #undef ADD
947  }
948  QSet<QByteArray> set;
949 };
950 
951 //! for isExtendedTableProperty()
952 Q_GLOBAL_STATIC(KDb_ExtendedProperties, KDb_extendedProperties)
953 
954 bool KDb::isExtendedTableFieldProperty(const QByteArray& propertyName)
955 {
956  return KDb_extendedProperties->set.contains(QByteArray(propertyName).toLower());
957 }
958 
959 //! @internal for isLookupFieldSchemaProperty()
960 struct KDb_LookupFieldSchemaProperties {
961  KDb_LookupFieldSchemaProperties() {
963  KDb::getProperties(nullptr, &tmp);
965  it != tmp.constEnd(); ++it)
966  {
967  set.insert(it.key().toLower());
968  }
969  }
970  QSet<QByteArray> set;
971 };
972 
973 //! for isLookupFieldSchemaProperty()
974 Q_GLOBAL_STATIC(KDb_LookupFieldSchemaProperties, KDb_lookupFieldSchemaProperties)
975 
976 bool KDb::isLookupFieldSchemaProperty(const QByteArray& propertyName)
977 {
978  return KDb_lookupFieldSchemaProperties->set.contains(propertyName.toLower());
979 }
980 
981 bool KDb::setFieldProperty(KDbField *field, const QByteArray& propertyName, const QVariant& value)
982 {
983  if (!field) {
984  return false;
985  }
986 #define SET_BOOLEAN_FLAG(flag, value) { \
987  constraints |= KDbField::flag; \
988  if (!value) \
989  constraints ^= KDbField::flag; \
990  field->setConstraints( constraints ); \
991  return true; \
992  }
993 #define GET_INT(method) { \
994  const int ival = value.toInt(&ok); \
995  if (!ok) \
996  return false; \
997  field->method( ival ); \
998  return true; \
999  }
1000 
1001  if (propertyName.isEmpty())
1002  return false;
1003 
1004  bool ok;
1005  if (KDb::isExtendedTableFieldProperty(propertyName)) {
1006  //a little speedup: identify extended property in O(1)
1007  if ("visibleDecimalPlaces" == propertyName
1009  GET_INT(setVisibleDecimalPlaces);
1010  }
1011  else if (KDb::isLookupFieldSchemaProperty(propertyName)) {
1012  if (!field->table()) {
1013  kdbWarning() << "Could not set" << propertyName << "property - no table assigned for field";
1014  } else {
1015  KDbLookupFieldSchema *lookup = field->table()->lookupFieldSchema(*field);
1016  const bool createLookup = !lookup;
1017  if (createLookup) // create lookup if needed
1018  lookup = new KDbLookupFieldSchema();
1019  if (lookup->setProperty(propertyName, value)) {
1020  if (createLookup)
1021  field->table()->setLookupFieldSchema(field->name(), lookup);
1022  return true;
1023  }
1024  if (createLookup)
1025  delete lookup; // not set, delete
1026  }
1027  }
1028  } else {//non-extended
1029  if ("type" == propertyName)
1030  return setIntToFieldType(field, value);
1031 
1032  KDbField::Constraints constraints = field->constraints();
1033  if ("primaryKey" == propertyName)
1034  SET_BOOLEAN_FLAG(PrimaryKey, value.toBool());
1035  if ("indexed" == propertyName)
1036  SET_BOOLEAN_FLAG(Indexed, value.toBool());
1037  if ("autoIncrement" == propertyName
1039  SET_BOOLEAN_FLAG(AutoInc, value.toBool());
1040  if ("unique" == propertyName)
1041  SET_BOOLEAN_FLAG(Unique, value.toBool());
1042  if ("notNull" == propertyName)
1043  SET_BOOLEAN_FLAG(NotNull, value.toBool());
1044  if ("allowEmpty" == propertyName)
1045  SET_BOOLEAN_FLAG(NotEmpty, !value.toBool());
1046 
1047  KDbField::Options options;
1048  if ("unsigned" == propertyName) {
1049  options |= KDbField::Unsigned;
1050  if (!value.toBool())
1051  options ^= KDbField::Unsigned;
1052  field->setOptions(options);
1053  return true;
1054  }
1055 
1056  if ("name" == propertyName) {
1057  if (value.toString().isEmpty())
1058  return false;
1059  field->setName(value.toString());
1060  return true;
1061  }
1062  if ("caption" == propertyName) {
1063  field->setCaption(value.toString());
1064  return true;
1065  }
1066  if ("description" == propertyName) {
1067  field->setDescription(value.toString());
1068  return true;
1069  }
1070  if ("maxLength" == propertyName)
1071  GET_INT(setMaxLength);
1072  if ("maxLengthIsDefault" == propertyName) {
1074  }
1075  if ("precision" == propertyName)
1076  GET_INT(setPrecision);
1077  if ("defaultValue" == propertyName) {
1078  field->setDefaultValue(value);
1079  return true;
1080  }
1081 
1082 //! @todo IMPORTANT: defaultWidth
1083 #if 0
1084  if ("defaultWidth" == propertyName)
1085  GET_INT(setDefaultWidth);
1086 #endif
1087  // last chance that never fails: custom field property
1088  field->setCustomProperty(propertyName, value);
1089  }
1090 
1091  kdbWarning() << "Field property" << propertyName << "not found!";
1092  return false;
1093 #undef SET_BOOLEAN_FLAG
1094 #undef GET_INT
1095 }
1096 
1097 int KDb::loadIntPropertyValueFromDom(const QDomNode& node, bool* ok)
1098 {
1099  QByteArray valueType = node.nodeName().toLatin1();
1100  if (valueType.isEmpty() || valueType != "number") {
1101  if (ok)
1102  *ok = false;
1103  return 0;
1104  }
1105  const QString text(QDomNode(node).toElement().text());
1106  int val = text.toInt(ok);
1107  return val;
1108 }
1109 
1111 {
1112  QByteArray valueType = node.nodeName().toLatin1();
1113  if (valueType != "string") {
1114  if (ok)
1115  *ok = false;
1116  return QString();
1117  }
1118  if (ok)
1119  *ok = true;
1120  return QDomNode(node).toElement().text();
1121 }
1122 
1124 {
1125  QByteArray valueType = node.nodeName().toLatin1();
1126  if (valueType.isEmpty()) {
1127  if (ok)
1128  *ok = false;
1129  return QVariant();
1130  }
1131  if (ok)
1132  *ok = true;
1133  const QString text(QDomNode(node).toElement().text());
1134  bool _ok;
1135  if (valueType == "string") {
1136  return text;
1137  }
1138  else if (valueType == "cstring") {
1139  return text.toLatin1();
1140  }
1141  else if (valueType == "number") { // integer or double
1142  if (text.indexOf(QLatin1Char('.')) != -1) {
1143  double val = text.toDouble(&_ok);
1144  if (_ok)
1145  return val;
1146  }
1147  else {
1148  const int val = text.toInt(&_ok);
1149  if (_ok)
1150  return val;
1151  const qint64 valLong = text.toLongLong(&_ok);
1152  if (_ok)
1153  return valLong;
1154  }
1155  }
1156  else if (valueType == "bool") {
1157  return text.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
1158  || text == QLatin1String("1");
1159  }
1160  else {
1161 //! @todo add more QVariant types
1162  kdbWarning() << "Unknown property type" << valueType;
1163  }
1164  if (ok)
1165  *ok = false;
1166  return QVariant();
1167 }
1168 
1170  const QString& elementName, int value)
1171 {
1172  if (!doc || !parentEl || elementName.isEmpty()) {
1173  return QDomElement();
1174  }
1175  QDomElement el(doc->createElement(elementName));
1176  parentEl->appendChild(el);
1177  QDomElement numberEl(doc->createElement(QLatin1String("number")));
1178  el.appendChild(numberEl);
1179  numberEl.appendChild(doc->createTextNode(QString::number(value)));
1180  return el;
1181 }
1182 
1184  const QString& elementName, bool value)
1185 {
1186  if (!doc || !parentEl || elementName.isEmpty()) {
1187  return QDomElement();
1188  }
1189  QDomElement el(doc->createElement(elementName));
1190  parentEl->appendChild(el);
1191  QDomElement numberEl(doc->createElement(QLatin1String("bool")));
1192  el.appendChild(numberEl);
1193  numberEl.appendChild(doc->createTextNode(
1194  value ? QLatin1String("true") : QLatin1String("false")));
1195  return el;
1196 }
1197 
1198 //! @internal Used in KDb::emptyValueForFieldType()
1199 struct KDb_EmptyValueForFieldTypeCache {
1200  KDb_EmptyValueForFieldTypeCache()
1201  : values(int(KDbField::LastType) + 1) {
1202 #define ADD(t, value) values.insert(t, value);
1203  ADD(KDbField::Byte, 0);
1204  ADD(KDbField::ShortInteger, 0);
1205  ADD(KDbField::Integer, 0);
1206  ADD(KDbField::BigInteger, 0);
1207  ADD(KDbField::Boolean, false);
1208  ADD(KDbField::Float, 0.0);
1209  ADD(KDbField::Double, 0.0);
1210 //! @todo ok? we have no better defaults
1211  ADD(KDbField::Text, QLatin1String(" "));
1212  ADD(KDbField::LongText, QLatin1String(" "));
1213  ADD(KDbField::BLOB, QByteArray());
1214 #undef ADD
1215  }
1217 };
1218 
1219 //! Used in KDb::emptyValueForFieldType()
1220 Q_GLOBAL_STATIC(KDb_EmptyValueForFieldTypeCache, KDb_emptyValueForFieldTypeCache)
1221 
1222 QVariant KDb::emptyValueForFieldType(KDbField::Type type)
1223 {
1224  const QVariant val(KDb_emptyValueForFieldTypeCache->values.at(
1225  (type <= KDbField::LastType) ? type : KDbField::InvalidType));
1226  if (!val.isNull())
1227  return val;
1228  else { //special cases
1229  if (type == KDbField::Date)
1230  return QDate::currentDate();
1231  if (type == KDbField::DateTime)
1232  return QDateTime::currentDateTime();
1233  if (type == KDbField::Time)
1234  return QTime::currentTime();
1235  }
1236  kdbWarning() << "No empty value for field type" << KDbField::typeName(type);
1237  return QVariant();
1238 }
1239 
1240 //! @internal Used in KDb::notEmptyValueForFieldType()
1241 struct KDb_NotEmptyValueForFieldTypeCache {
1242  KDb_NotEmptyValueForFieldTypeCache()
1243  : values(int(KDbField::LastType) + 1) {
1244 #define ADD(t, value) values.insert(t, value);
1245  // copy most of the values
1246  for (int i = int(KDbField::InvalidType) + 1; i <= KDbField::LastType; i++) {
1247  if (i == KDbField::Date || i == KDbField::DateTime || i == KDbField::Time)
1248  continue; //'current' value will be returned
1249  if (i == KDbField::Text || i == KDbField::LongText) {
1250  ADD(i, QVariant(QLatin1String("")));
1251  continue;
1252  }
1253  if (i == KDbField::BLOB) {
1254 //! @todo blobs will contain other MIME types too
1255  QByteArray ba;
1256 //! @todo port to Qt4
1257 #if 0
1258  QBuffer buffer(&ba);
1259  buffer.open(QIODevice::WriteOnly);
1260  QPixmap pm(SmallIcon("document-new"));
1261  pm.save(&buffer, "PNG"/*! @todo default? */);
1262 #endif
1263  ADD(i, ba);
1264  continue;
1265  }
1267  }
1268 #undef ADD
1269  }
1271 };
1272 //! Used in KDb::notEmptyValueForFieldType()
1273 Q_GLOBAL_STATIC(KDb_NotEmptyValueForFieldTypeCache, KDb_notEmptyValueForFieldTypeCache)
1274 
1275 QVariant KDb::notEmptyValueForFieldType(KDbField::Type type)
1276 {
1277  const QVariant val(KDb_notEmptyValueForFieldTypeCache->values.at(
1278  (type <= KDbField::LastType) ? type : KDbField::InvalidType));
1279  if (!val.isNull())
1280  return val;
1281  else { //special cases
1282  if (type == KDbField::Date)
1283  return QDate::currentDate();
1284  if (type == KDbField::DateTime)
1285  return QDateTime::currentDateTime();
1286  if (type == KDbField::Time)
1287  return QTime::currentTime();
1288  }
1289  kdbWarning() << "No non-empty value for field type" << KDbField::typeName(type);
1290  return QVariant();
1291 }
1292 
1293 //! @internal @return nestimated new length after escaping of string @a string
1294 template<typename T>
1295 inline static int estimatedNewLength(const T &string, bool addQuotes)
1296 {
1297  if (string.length() < 10)
1298  return string.length() * 2 + (addQuotes ? 2 : 0);
1299  return string.length() * 3 / 2;
1300 }
1301 
1302 //! @internal @return @a string string with applied KDbSQL identifier escaping.
1303 //! If @a addQuotes is true, '"' characer is prepended and appended.
1304 template<typename T, typename Latin1StringType, typename Latin1CharType, typename CharType>
1305 inline static T escapeIdentifier(const T& string, bool addQuotes)
1306 {
1307  const Latin1CharType quote('"');
1308  // create
1309  Latin1StringType escapedQuote("\"\"");
1310  T newString;
1311  newString.reserve(estimatedNewLength(string, addQuotes));
1312  if (addQuotes) {
1313  newString.append(quote);
1314  }
1315  for (int i = 0; i < string.length(); i++) {
1316  const CharType c = string.at(i);
1317  if (c == quote)
1318  newString.append(escapedQuote);
1319  else
1320  newString.append(c);
1321  }
1322  if (addQuotes) {
1323  newString.append(quote);
1324  }
1325  newString.squeeze();
1326  return newString;
1327 }
1328 
1329 static bool shouldAddQuotesToIdentifier(const QByteArray& string)
1330 {
1331  return !string.isEmpty() && (!KDb::isIdentifier(string) || KDb::isKDbSqlKeyword(string));
1332 }
1333 
1335 {
1336  return ::escapeIdentifier<QString, QLatin1String, QLatin1Char, QChar>(
1337  string, shouldAddQuotesToIdentifier(string.toLatin1()));
1338 }
1339 
1341 {
1342  return ::escapeIdentifier<QByteArray, QByteArray, char, char>(
1343  string, shouldAddQuotesToIdentifier(string));
1344 }
1345 
1347 {
1348  return ::escapeIdentifier<QString, QLatin1String, QLatin1Char, QChar>(string, true);
1349 }
1350 
1352 {
1353  return ::escapeIdentifier<QByteArray, QByteArray, char, char>(string, true);
1354 }
1355 
1357 {
1358  const QLatin1Char quote('\'');
1359  // find out the length ot the destination string
1360  // create
1361  QString newString(quote);
1362  newString.reserve(estimatedNewLength(string, true));
1363  for (int i = 0; i < string.length(); i++) {
1364  const QChar c = string.at(i);
1365  const ushort unicode = c.unicode();
1366  if (unicode == quote)
1367  newString.append(QLatin1String("''"));
1368  else if (unicode == '\t')
1369  newString.append(QLatin1String("\\t"));
1370  else if (unicode == '\\')
1371  newString.append(QLatin1String("\\\\"));
1372  else if (unicode == '\n')
1373  newString.append(QLatin1String("\\n"));
1374  else if (unicode == '\r')
1375  newString.append(QLatin1String("\\r"));
1376  else if (unicode == '\0')
1377  newString.append(QLatin1String("\\0"));
1378  else
1379  newString.append(c);
1380  }
1381  newString.append(QLatin1Char(quote));
1382  return newString;
1383 }
1384 
1386 {
1387  return drv ? drv->escapeString(string) : KDbEscapedString(KDb::escapeString(string));
1388 }
1389 
1391 {
1392  return conn ? conn->escapeString(string) : KDbEscapedString(KDb::escapeString(string));
1393 }
1394 
1395 //! @see handleHex()
1396 const int CODE_POINT_DIGITS = std::numeric_limits<int>::max();
1397 //! @see handleHex()
1398 const int MAX_CODE_POINT_VALUE = 0x10FFFF;
1399 
1400 //! @internal Decodes hex of length @a digits for handleXhh(), handleUxxxx() and handleUcodePoint()
1401 //! If @a digits is CODE_POINT_DIGITS, any number of hex digits is decoded until '}' character
1402 //! is found (error if not found), and the function succeeds when the resulting number
1403 //! is not larger than MAX_CODE_POINT_VALUE.
1404 //! If @a digits is smaller than CODE_POINT_DIGITS the function succeeds only if exactly @a digits
1405 //! number of digits has been found.
1406 //! @return -1 on error (when invalid character found or on missing character
1407 //! or if the resulting number is too large)
1408 //! @see KDb::unescapeString()
1409 static int handleHex(QString *result, int *from, int stringLen, int *errorPosition, int digits)
1410 {
1411  int digit = 0;
1412  for (int i=0; i<digits; ++i) {
1413  if ((*from + 1) >= stringLen) { // unfinished
1414  if (errorPosition) {
1415  *errorPosition = *from;
1416  }
1417  return -1;
1418  }
1419  ++(*from);
1420  if (digits == CODE_POINT_DIGITS && (*result)[*from] == QLatin1Char('}')) {
1421  // special case: code point character decoded
1422  if (i == 0) {
1423  if (errorPosition) {
1424  *errorPosition = *from;
1425  }
1426  return -1;
1427  }
1428  return digit;
1429  }
1430  const unsigned char d = hexDigitToInt((*result)[*from].toLatin1());
1431  if (d == 0xFF) { // unfinished or wrong character
1432  if (errorPosition) {
1433  *errorPosition = *from;
1434  }
1435  return -1;
1436  }
1437  digit = (digit << 4) + d;
1438  if (digits == CODE_POINT_DIGITS) {
1439  if (digit > MAX_CODE_POINT_VALUE) { // special case: exceeded limit of code point
1440  if (errorPosition) {
1441  *errorPosition = *from;
1442  }
1443  return -1;
1444  }
1445  }
1446  }
1447  return digit;
1448 }
1449 
1450 //! @internal Handles \xhh format for handleEscape()
1451 //! Assumption: the @a *from points to "x" in the "\x"
1452 //! @see KDb::unescapeString()
1453 static bool handleXhh(QString *result, int *from, int to, int stringLen, int *errorPosition)
1454 {
1455  const int intDigit = handleHex(result, from, stringLen, errorPosition, 2);
1456  if (intDigit == -1) {
1457  return false;
1458  }
1459  (*result)[to] = QChar(static_cast<unsigned char>(intDigit), 0);
1460  return true;
1461 }
1462 
1463 //! @internal Handles \uxxxx format for handleEscape()
1464 //! Assumption: the @a *from points to the "u" in the "\u".
1465 //! @see KDb::unescapeString()
1466 static bool handleUxxxx(QString *result, int *from, int to, int stringLen, int *errorPosition)
1467 {
1468  const int intDigit = handleHex(result, from, stringLen, errorPosition, 4);
1469  if (intDigit == -1) {
1470  return false;
1471  }
1472  (*result)[to] = QChar(static_cast<unsigned short>(intDigit));
1473  return true;
1474 }
1475 
1476 //! @internal Handles \u{xxxxxx} format for handleEscape()
1477 //! Assumption: the @a *from points to the "{" in the "\u{".
1478 //! @see KDb::unescapeString()
1479 static bool handleUcodePoint(QString *result, int *from, int to, int stringLen, int *errorPosition)
1480 {
1481  const int intDigit = handleHex(result, from, stringLen, errorPosition, CODE_POINT_DIGITS);
1482  if (intDigit == -1) {
1483  return false;
1484  }
1485  (*result)[to] = QChar(intDigit);
1486  return true;
1487 }
1488 
1489 //! @internal Handles escaped character @a c2 for KDb::unescapeString()
1490 //! Updates @a result
1491 //! @return true on success
1492 static bool handleEscape(QString *result, int *from, int *to, int stringLen, int *errorPosition)
1493 {
1494  const QCharRef c2 = (*result)[*from];
1495  if (c2 == QLatin1Char('x')) { // \xhh
1496  if (!handleXhh(result, from, *to, stringLen, errorPosition)) {
1497  return false;
1498  }
1499  } else if (c2 == QLatin1Char('u')) { // \u
1500  if ((*from + 1) >= stringLen) { // unfinished
1501  if (errorPosition) {
1502  *errorPosition = *from;
1503  }
1504  return false;
1505  }
1506  ++(*from);
1507  const QCharRef c3 = (*result)[*from];
1508  if (c3 == QLatin1Char('{')) { // \u{
1509  if (!handleUcodePoint(result, from, *to, stringLen, errorPosition)) {
1510  return false;
1511  }
1512  } else {
1513  --(*from);
1514  if (!handleUxxxx(result, from, *to, stringLen, errorPosition)) {
1515  return false;
1516  }
1517  }
1518 #define _RULE(in, out) \
1519  } else if (c2 == QLatin1Char(in)) { \
1520  (*result)[*to] = QLatin1Char(out);
1521  _RULE('0', '\0') _RULE('b', '\b') _RULE('f', '\f') _RULE('n', '\n')
1522  _RULE('r', '\r') _RULE('t', '\t') _RULE('v', '\v')
1523 #undef _RULE
1524  } else { // \ ' " ? % _ and any other without special meaning can be escaped: just skip "\"
1525  (*result)[*to] = c2;
1526  }
1527  return true;
1528 }
1529 
1530 QString KDb::unescapeString(const QString& string, char quote, int *errorPosition)
1531 {
1532  if (quote != '\'' && quote != '\"') {
1533  if (errorPosition) {
1534  *errorPosition = 0;
1535  }
1536  return QString();
1537  }
1538  const QLatin1Char quoteChar(quote);
1539  if (string.isEmpty()
1540  || (!string.contains(QLatin1Char('\\')) && !string.contains(quoteChar)))
1541  {
1542  if (errorPosition) {
1543  *errorPosition = -1;
1544  }
1545  return string; // optimization: there are no escapes and quotes
1546  }
1547  QString result(string);
1548  const int stringLen = string.length();
1549  int from = 0;
1550  int to = 0;
1551  bool doubleQuoteExpected = false;
1552  while (from < stringLen) {
1553  const QCharRef c = result[from];
1554  if (doubleQuoteExpected) {
1555  if (c == quoteChar) {
1556  result[to] = c;
1557  doubleQuoteExpected = false;
1558  } else {
1559  // error: missing second quote
1560  if (errorPosition) {
1561  *errorPosition = from - 1; // -1 because error is at prev. char
1562  }
1563  return QString();
1564  }
1565  } else if (c == quoteChar) {
1566  doubleQuoteExpected = true;
1567  ++from;
1568  continue;
1569  } else if (c == QLatin1Char('\\')) { // escaping
1570  if ((from + 1) >= stringLen) { // ignore unfinished '\'
1571  break;
1572  }
1573  ++from;
1574  if (!handleEscape(&result, &from, &to, stringLen, errorPosition)) {
1575  return QString();
1576  }
1577  } else { // normal character: skip
1578  result[to] = result[from];
1579  }
1580  ++from;
1581  ++to;
1582  }
1583  if (doubleQuoteExpected) { // error: string ends with a single quote
1584  if (errorPosition) {
1585  *errorPosition = from - 1;
1586  }
1587  return QString();
1588  }
1589  if (errorPosition) {
1590  *errorPosition = -1;
1591  }
1592  result.truncate(to);
1593  return result;
1594 }
1595 
1596 //! @return hex digit '0'..'F' for integer number 0..15
1597 inline static char intToHexDigit(unsigned char val)
1598 {
1599  return (val < 10) ? ('0' + val) : ('A' + (val - 10));
1600 }
1601 
1602 QString KDb::escapeBLOB(const QByteArray& array, BLOBEscapingType type)
1603 {
1604  const int size = array.size();
1605  if (size == 0 && type == BLOBEscapingType::ZeroXHex)
1606  return QString();
1607  int escaped_length = size * 2;
1608  if (type == BLOBEscapingType::ZeroXHex || type == BLOBEscapingType::Octal)
1609  escaped_length += 2/*0x or X'*/;
1610  else if (type == BLOBEscapingType::XHex)
1611  escaped_length += 3; //X' + '
1612  else if (type == BLOBEscapingType::ByteaHex)
1613  escaped_length += (4 + 8); // E'\x + '::bytea
1614 
1615  QString str;
1616  str.reserve(escaped_length);
1617  if (str.capacity() < escaped_length) {
1618  kdbWarning() << "Not enough memory (cannot allocate" << escaped_length << "characters)";
1619  return QString();
1620  }
1621  if (type == BLOBEscapingType::XHex)
1622  str = QString::fromLatin1("X'");
1623  else if (type == BLOBEscapingType::ZeroXHex)
1624  str = QString::fromLatin1("0x");
1625  else if (type == BLOBEscapingType::Octal)
1626  str = QString::fromLatin1("'");
1627  else if (type == BLOBEscapingType::ByteaHex)
1628  str = QString::fromLatin1("E'\\\\x");
1629 
1630  if (type == BLOBEscapingType::Octal) {
1631  // only escape nonprintable characters as in Table 8-7:
1632  // https://www.postgresql.org/docs/8.1/interactive/datatype-binary.html
1633  // i.e. escape for bytes: < 32, >= 127, 39 ('), 92(\).
1634  for (int i = 0; i < size; i++) {
1635  const unsigned char val = array[i];
1636  if (val < 32 || val >= 127 || val == 39 || val == 92) {
1637  str.append(QLatin1Char('\\'));
1638  str.append(QLatin1Char('\\'));
1639  str.append(QChar::fromLatin1('0' + val / 64));
1640  str.append(QChar::fromLatin1('0' + (val % 64) / 8));
1641  str.append(QChar::fromLatin1('0' + val % 8));
1642  } else {
1643  str.append(QChar::fromLatin1(val));
1644  }
1645  }
1646  } else {
1647  for (int i = 0; i < size; i++) {
1648  const unsigned char val = array[i];
1649  str.append(QChar::fromLatin1(intToHexDigit(val / 16)));
1650  str.append(QChar::fromLatin1(intToHexDigit(val % 16)));
1651  }
1652  }
1653  if (type == BLOBEscapingType::XHex || type == BLOBEscapingType::Octal) {
1654  str.append(QLatin1Char('\''));
1655  } else if (type == BLOBEscapingType::ByteaHex) {
1656  str.append(QLatin1String("\'::bytea"));
1657  }
1658  return str;
1659 }
1660 
1661 QByteArray KDb::pgsqlByteaToByteArray(const char* data, int length)
1662 {
1663  if (!data) {
1664  return QByteArray();
1665  }
1666  QByteArray array;
1667  int output = 0;
1668  if (length < 0) {
1669  length = qstrlen(data);
1670  }
1671  for (int pass = 0; pass < 2; pass++) {//2 passes to avoid allocating buffer twice:
1672  // 0: count #of chars; 1: copy data
1673  const char* s = data;
1674  const char* end = s + length;
1675  if (pass == 1) {
1676  //kdbDebug() << "processBinaryData(): real size == " << output;
1677  array.resize(output);
1678  output = 0;
1679  }
1680  for (int input = 0; s < end; output++) {
1681  // kdbDebug()<<(int)s[0]<<" "<<(int)s[1]<<" "<<(int)s[2]<<" "<<(int)s[3]<<" "<<(int)s[4];
1682  if (s[0] == '\\' && (s + 1) < end) {
1683  //special cases as in https://www.postgresql.org/docs/8.1/interactive/datatype-binary.html
1684  if (s[1] == '\'') {// \'
1685  if (pass == 1)
1686  array[output] = '\'';
1687  s += 2;
1688  } else if (s[1] == '\\') { // 2 backslashes
1689  if (pass == 1)
1690  array[output] = '\\';
1691  s += 2;
1692  } else if ((input + 3) < length) {// \\xyz where xyz are 3 octal digits
1693  if (pass == 1)
1694  array[output] = char((int(s[1] - '0') * 8 + int(s[2] - '0')) * 8 + int(s[3] - '0'));
1695  s += 4;
1696  } else {
1697  kdbWarning() << "Missing octal value after backslash";
1698  s++;
1699  }
1700  } else {
1701  if (pass == 1)
1702  array[output] = s[0];
1703  s++;
1704  }
1705  // kdbDebug()<<output<<": "<<(int)array[output];
1706  }
1707  }
1708  return array;
1709 }
1710 
1711 QByteArray KDb::xHexToByteArray(const char* data, int length, bool *ok)
1712 {
1713  if (length < 0) {
1714  length = qstrlen(data);
1715  }
1716  if (length < 3 || data[0] != 'X' || data[1] != '\'' || data[length-1] != '\'') { // must be at least X''
1717  if (ok) {
1718  *ok = false;
1719  }
1720  return QByteArray();
1721  }
1722  data += 2; // eat X'
1723  length -= 3; // eax X' and '
1724  QByteArray array;
1725  if (!hexToByteArrayInternal(data, length, &array)) {
1726  if (ok) {
1727  *ok = false;
1728  }
1729  array.clear();
1730  }
1731  if (ok) {
1732  *ok = true;
1733  }
1734  return array;
1735 }
1736 
1737 /*! \return byte array converted from \a data of length \a length.
1738  \a data is escaped in format 0x*, where * is one or more bytes in hexadecimal format.
1739  See BLOBEscapingType::ZeroXHex. */
1740 QByteArray KDb::zeroXHexToByteArray(const char* data, int length, bool *ok)
1741 {
1742  if (length < 0) {
1743  length = qstrlen(data);
1744  }
1745  if (length < 3 || data[0] != '0' || data[1] != 'x') { // must be at least 0xD
1746  if (ok) {
1747  *ok = false;
1748  }
1749  return QByteArray();
1750  }
1751  data += 2; // eat 0x
1752  length -= 2;
1753  QByteArray array;
1754  if (!hexToByteArrayInternal(data, length, &array)) {
1755  if (ok) {
1756  *ok = false;
1757  }
1758  array.clear();
1759  }
1760  if (ok) {
1761  *ok = true;
1762  }
1763  return array;
1764 }
1765 
1767 {
1768  QList<int> result;
1769  foreach (const QString &item, list) {
1770  int val = item.toInt(ok);
1771  if (ok && !*ok) {
1772  return QList<int>();
1773  }
1774  result.append(val);
1775  }
1776  if (ok) {
1777  *ok = true;
1778  }
1779  return result;
1780 }
1781 
1782 // Based on KConfigGroupPrivate::serializeList() from kconfiggroup.cpp (kdelibs 4)
1784 {
1785  QString value;
1786 
1787  if (!list.isEmpty()) {
1789  const QStringList::ConstIterator end = list.constEnd();
1790 
1791  value = QString(*it).replace(QLatin1Char('\\'), QLatin1String("\\\\"))
1792  .replace(QLatin1Char(','), QLatin1String("\\,"));
1793 
1794  while (++it != end) {
1795  // In the loop, so it is not done when there is only one element.
1796  // Doing it repeatedly is a pretty cheap operation.
1797  value.reserve(4096);
1798 
1799  value += QLatin1Char(',')
1800  + QString(*it).replace(QLatin1Char('\\'), QLatin1String("\\\\"))
1801  .replace(QLatin1Char(','), QLatin1String("\\,"));
1802  }
1803 
1804  // To be able to distinguish an empty list from a list with one empty element.
1805  if (value.isEmpty())
1806  value = QLatin1String("\\0");
1807  }
1808 
1809  return value;
1810 }
1811 
1812 // Based on KConfigGroupPrivate::deserializeList() from kconfiggroup.cpp (kdelibs 4)
1814 {
1815  if (data.isEmpty())
1816  return QStringList();
1817  if (data == QLatin1String("\\0"))
1818  return QStringList(QString());
1819  QStringList value;
1820  QString val;
1821  val.reserve(data.size());
1822  bool quoted = false;
1823  for (int p = 0; p < data.length(); p++) {
1824  if (quoted) {
1825  val += data[p];
1826  quoted = false;
1827  } else if (data[p].unicode() == QLatin1Char('\\')) {
1828  quoted = true;
1829  } else if (data[p].unicode() == QLatin1Char(',')) {
1830  val.squeeze(); // release any unused memory
1831  value.append(val);
1832  val.clear();
1833  val.reserve(data.size() - p);
1834  } else {
1835  val += data[p];
1836  }
1837  }
1838  value.append(val);
1839  return value;
1840 }
1841 
1843 {
1844  return KDb::stringListToIntList(
1845  KDb::deserializeList(data), ok);
1846 }
1847 
1849  {
1850  if (v.type() == QVariant::ByteArray) {
1852  }
1853  else if (v.type() == QVariant::StringList) {
1854  return serializeList(v.toStringList());
1855  }
1856  return v.toString();
1857 }
1858 
1860 {
1861  if (s.isNull()) {
1862  if (ok)
1863  *ok = true;
1864  return QVariant();
1865  }
1866  switch (type) {
1867  case QVariant::Invalid:
1868  if (ok)
1869  *ok = false;
1870  return QVariant();
1871  case QVariant::ByteArray: {//special case: hex string
1872  const int len = s.length();
1873  QByteArray ba;
1874  ba.resize(len / 2 + len % 2);
1875  for (int i = 0; i < (len - 1); i += 2) {
1876  bool _ok;
1877  int c = s.midRef(i, 2).toInt(&_ok, 16);
1878  if (!_ok) {
1879  if (ok)
1880  *ok = _ok;
1881  kdbWarning() << "Error in digit" << i;
1882  return QVariant();
1883  }
1884  ba[i/2] = (char)c;
1885  }
1886  if (ok)
1887  *ok = true;
1888  return ba;
1889  }
1890  case QVariant::StringList:
1891  *ok = true;
1892  return KDb::deserializeList(s);
1893  default:;
1894  }
1895 
1896  QVariant result(s);
1897  if (!result.convert(type)) {
1898  if (ok)
1899  *ok = false;
1900  return QVariant();
1901  }
1902  if (ok)
1903  *ok = true;
1904  return result;
1905 }
1906 
1908 {
1909  return !field.isUniqueKey();
1910 }
1911 
1912 void KDb::getLimitsForFieldType(KDbField::Type type, qlonglong *minValue, qlonglong *maxValue,
1913  Signedness signedness)
1914 {
1915  if (!minValue || !maxValue) {
1916  return;
1917  }
1918  switch (type) {
1919  case KDbField::Byte:
1920 //! @todo always ok?
1921  *minValue = signedness == KDb::Signed ? -0x80 : 0;
1922  *maxValue = signedness == KDb::Signed ? 0x7F : 0xFF;
1923  break;
1925  *minValue = signedness == KDb::Signed ? -0x8000 : 0;
1926  *maxValue = signedness == KDb::Signed ? 0x7FFF : 0xFFFF;
1927  break;
1928  case KDbField::Integer:
1929  case KDbField::BigInteger: //!< @todo cannot return anything larger?
1930  default:
1931  *minValue = signedness == KDb::Signed ? qlonglong(-0x07FFFFFFF) : qlonglong(0);
1932  *maxValue = signedness == KDb::Signed ? qlonglong(0x07FFFFFFF) : qlonglong(0x0FFFFFFFF);
1933  }
1934 }
1935 
1937 {
1939  return KDbField::InvalidType;
1940  if (t1 == t2)
1941  return t2;
1943  return t1;
1944  if (t1 == KDbField::Integer && t2 != KDbField::BigInteger)
1945  return t1;
1946  if (t1 == KDbField::BigInteger)
1947  return t1;
1948  return KDb::maximumForIntegerFieldTypes(t2, t1); //swap
1949 }
1950 
1952 {
1953  if (KDbField::isNumericType(type))
1954  return KDbField::tr("Number"); //simplify
1955  else if (type == KDbField::BLOB)
1956 //! @todo support names of other BLOB subtypes
1957  return KDbField::tr("Image"); //simplify
1958 
1960 }
1961 
1963 {
1964  return QLatin1String("application/x-kexiproject-sqlite3");
1965 }
1966 
1968 {
1969  return QLatin1String("org.kde.kdb.sqlite");
1970 }
1971 
1972 // Try to convert from string to type T
1973 template <typename T>
1974 QVariant convert(T (QString::*ConvertToT)(bool*,int) const, const char *data, int size,
1975  qlonglong minValue, qlonglong maxValue, bool *ok)
1976 {
1977  T v = (QString::fromLatin1(data, size).*ConvertToT)(ok, 10);
1978  if (*ok) {
1979  *ok = minValue <= v && v <= maxValue;
1980  }
1981  return KDb::iif(*ok, QVariant(v));
1982 }
1983 
1984 QVariant KDb::cstringToVariant(const char* data, KDbField::Type type, bool *ok, int length,
1985  KDb::Signedness signedness)
1986 {
1987  bool tempOk;
1988  bool *thisOk = ok ? ok : &tempOk;
1989  if (type < KDbField::Byte || type > KDbField::LastType) {
1990  *thisOk = false;
1991  return QVariant();
1992  }
1993  if (!data) { // NULL value
1994  *thisOk = true;
1995  return QVariant();
1996  }
1997  // from most to least frequently used types:
1998 
1999  if (KDbField::isTextType(type)) {
2000  *thisOk = true;
2001  //! @todo use KDbDriverBehavior::TEXT_TYPE_MAX_LENGTH for Text type?
2002  return QString::fromUtf8(data, length);
2003  }
2004  if (KDbField::isIntegerType(type)) {
2005  qlonglong minValue, maxValue;
2006  const bool isUnsigned = signedness == KDb::Unsigned;
2007  KDb::getLimitsForFieldType(type, &minValue, &maxValue, signedness);
2008  switch (type) {
2009  case KDbField::Byte: // Byte here too, minValue/maxValue will take care of limits
2011  return isUnsigned ?
2012  convert(&QString::toUShort, data, length, minValue, maxValue, thisOk)
2013  : convert(&QString::toShort, data, length, minValue, maxValue, thisOk);
2014  case KDbField::Integer:
2015  return isUnsigned ?
2016  convert(&QString::toUInt, data, length, minValue, maxValue, thisOk)
2017  : convert(&QString::toInt, data, length, minValue, maxValue, thisOk);
2018  case KDbField::BigInteger:
2019  return convert(&QString::toLongLong, data, length, minValue, maxValue, thisOk);
2020  default:
2021  qFatal("Unsupported integer type %d", type);
2022  }
2023  }
2024  if (KDbField::isFPNumericType(type)) {
2025  const QVariant result(QString::fromLatin1(data, length).toDouble(thisOk));
2026  return KDb::iif(*thisOk, result);
2027  }
2028  if (type == KDbField::BLOB) {
2029  *thisOk = length >= 0;
2030  return *thisOk ? QVariant(QByteArray(data, length)) : QVariant();
2031  }
2032  // the default
2033 //! @todo date/time?
2034  QVariant result(QString::fromUtf8(data, length));
2035  if (!result.convert(KDbField::variantType(type))) {
2036  *thisOk = false;
2037  return QVariant();
2038  }
2039  *thisOk = true;
2040  return result;
2041 }
2042 
2044 {
2045  QStringList result;
2046  foreach (const QString& path, qApp->libraryPaths()) {
2047  const QString dir(path + QLatin1Char('/') + QLatin1String(KDB_BASE_NAME_LOWER));
2048  if (QDir(dir).exists() && QDir(dir).isReadable()) {
2049  result += dir;
2050  }
2051  }
2052  return result;
2053 }
2054 
2056 {
2057  if (!conn) {
2058  return QString();
2059  }
2060  while (true) {
2061  QString name = QLatin1String("tmp__") + baseName;
2062  for (int i = 0; i < 10; ++i) {
2063  name += QString::number(int(double(qrand()) / RAND_MAX * 0x10), 16);
2064  }
2065  const tristate res = conn->containsTable(name);
2066  if (~res) {
2067  return QString();
2068  } else if (res == false) {
2069  return name;
2070  }
2071  }
2072 }
2073 
2075 {
2076  QString path = KDbUtils::findExe(QLatin1String("sqlite3"));
2077  if (path.isEmpty()) {
2078  kdbWarning() << "Could not find program \"sqlite3\"";
2079  }
2080  return path;
2081 }
2082 
2083 bool KDb::importSqliteFile(const QString &inputFileName, const QString &outputFileName)
2084 {
2085  const QString sqlite_app = KDb::sqlite3ProgramPath();
2086  if (sqlite_app.isEmpty()) {
2087  return false;
2088  }
2089 
2090  QFileInfo fi(inputFileName);
2091  if (!fi.isReadable()) {
2092  kdbWarning() << "No readable input file" << fi.absoluteFilePath();
2093  return false;
2094  }
2095  QFileInfo fo(outputFileName);
2096  if (QFile(fo.absoluteFilePath()).exists()) {
2097  if (!QFile::remove(fo.absoluteFilePath())) {
2098  kdbWarning() << "Could not remove output file" << fo.absoluteFilePath();
2099  return false;
2100  }
2101  }
2102  kdbDebug() << inputFileName << fi.absoluteDir().path() << fo.absoluteFilePath();
2103 
2104  QProcess p;
2105  p.start(sqlite_app, QStringList() << fo.absoluteFilePath());
2106  if (!p.waitForStarted()) {
2107  kdbWarning() << "Failed to start program" << sqlite_app;
2108  return false;
2109  }
2110  QByteArray line(".read " + QFile::encodeName(fi.absoluteFilePath()));
2111  if (p.write(line) != line.length() || !p.waitForBytesWritten()) {
2112  kdbWarning() << "Failed to send \".read\" command to program" << sqlite_app;
2113  return false;
2114  }
2115  p.closeWriteChannel();
2116  if (!p.waitForFinished()) {
2117  kdbWarning() << "Failed to finish program" << sqlite_app;
2118  return false;
2119  }
2120  return true;
2121 }
2122 
2123 //---------
2124 
2126 {
2127  int i;
2128  const int sLength = s.length();
2129  for (i = 0; i < sLength; i++) {
2130  const char c = s.at(i).toLower().toLatin1();
2131  if (c == 0 || !(c == '_' || (c >= 'a' && c <= 'z') || (i > 0 && c >= '0' && c <= '9')))
2132  break;
2133  }
2134  return i > 0 && i == sLength;
2135 }
2136 
2137 bool KDb::isIdentifier(const QByteArray& s)
2138 {
2139  int i;
2140  const int sLength = s.length();
2141  for (i = 0; i < sLength; i++) {
2142  const char c = s.at(i);
2143  if (c == 0 || !(c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (i > 0 && c >= '0' && c <= '9'))) {
2144  break;
2145  }
2146  }
2147  return i > 0 && i == sLength;
2148 }
2149 
2150 static inline QString charToIdentifier(const QChar& c)
2151 {
2152  if (c.unicode() >= TRANSLITERATION_TABLE_SIZE)
2153  return QLatin1String("_");
2154  const char *const s = transliteration_table[c.unicode()];
2155  return s ? QString::fromLatin1(s) : QLatin1String("_");
2156 }
2157 
2159 {
2160  if (s.isEmpty())
2161  return QString();
2162  QString r, id = s.simplified();
2163  if (id.isEmpty())
2164  return QString();
2165  r.reserve(id.length());
2166  id.replace(QLatin1Char(' '), QLatin1String("_"));
2167  const QChar c = id[0];
2168  const char ch = c.toLatin1();
2169  QString add;
2170  bool wasUnderscore = false;
2171 
2172  if (ch >= '0' && ch <= '9') {
2173  r += QLatin1Char('_') + c;
2174  } else {
2175  add = charToIdentifier(c);
2176  r += add;
2177  wasUnderscore = add == QLatin1String("_");
2178  }
2179 
2180  const int idLength = id.length();
2181  for (int i = 1; i < idLength; i++) {
2182  add = charToIdentifier(id.at(i));
2183  if (wasUnderscore && add == QLatin1String("_"))
2184  continue;
2185  wasUnderscore = add == QLatin1String("_");
2186  r += add;
2187  }
2188  return r;
2189 }
2190 
2192 {
2193  return QLatin1String("<p>") + kdb::tr("Value of \"%1\" field must be an identifier.")
2194  .arg(valueName)
2195  + QLatin1String("</p><p>")
2196  + kdb::tr("\"%1\" is not a valid identifier.").arg(v.toString()) + QLatin1String("</p>");
2197 }
2198 
2199 //---------
2200 
2202 {
2203  return valueToSqlInternal(nullptr, ftype, v);
2204 }
2205 
2206 static QByteArray dateToSqlInternal(const QVariant& v, bool allowInvalidKDbDate)
2207 {
2208  QByteArray result(QByteArrayLiteral("<INVALID_DATE>"));
2209  if (v.canConvert<KDbDate>()) {
2210  const KDbDate date(v.value<KDbDate>());
2211  if (date.isValid() || allowInvalidKDbDate) {
2212  result = date.toString(); // OK even if invalid or null
2213  }
2214  } else if (v.canConvert<QDate>()) {
2215  const QDate date(v.toDate());
2216  if (date.isValid()) {
2217  result = date.toString(Qt::ISODate).toLatin1();
2218  }
2219  }
2220  return result;
2221 }
2222 
2224 {
2225  return KDbEscapedString('#') + dateToSqlInternal(v, true) + '#';
2226 }
2227 
2228 static QByteArray timeToSqlInternal(const QVariant& v, bool allowInvalidKDbTime)
2229 {
2230  QByteArray result(QByteArrayLiteral("<INVALID_TIME>"));
2231  if (v.canConvert<KDbTime>()) {
2232  const KDbTime time(v.value<KDbTime>());
2233  if (time.isValid() || allowInvalidKDbTime) {
2234  result = time.toString(); // OK even if invalid or null
2235  }
2236  } else if (v.canConvert<QTime>()) {
2237  const QTime time(v.toTime());
2238  if (time.isValid()) {
2239  if (time.msec() == 0) {
2240  result = time.toString(Qt::ISODate).toLatin1();
2241  } else {
2242  result = KDbUtils::toISODateStringWithMs(time).toLatin1();
2243  }
2244  }
2245  }
2246  return result;
2247 }
2248 
2250 {
2251  return KDbEscapedString('#') + timeToSqlInternal(v, true) + '#';
2252 }
2253 
2254 static QByteArray dateTimeToSqlInternal(const QVariant& v, char separator, bool allowInvalidKDbDateTime)
2255 {
2256  QByteArray result(QByteArrayLiteral("<INVALID_DATETIME>"));
2257  if (v.canConvert<KDbDateTime>()) {
2258  const KDbDateTime dateTime(v.value<KDbDateTime>());
2259  if (dateTime.isValid() || allowInvalidKDbDateTime) {
2260  result = dateTime.toString(); // OK even if invalid or null
2261  }
2262  } else if (v.canConvert<QDateTime>()) {
2263  const QDateTime dateTime(v.toDateTime());
2264  if (dateTime.isValid()) {
2265  result = dateTime.date().toString(Qt::ISODate).toLatin1() + separator;
2266  const QTime time(dateTime.time());
2267  if (time.msec() == 0) {
2268  result += time.toString(Qt::ISODate).toLatin1();
2269  } else {
2270  result += KDbUtils::toISODateStringWithMs(time).toLatin1();
2271  }
2272  }
2273  }
2274  return result;
2275 }
2276 
2278 {
2279  return KDbEscapedString('#') + dateTimeToSqlInternal(v, ' ', true) + '#';
2280 }
2281 
2283 {
2284  return KDb::dateTimeToIsoString(v);
2285 }
2286 
2288 {
2289  return KDbEscapedString('\'') + dateToSqlInternal(v, false) + KDbEscapedString('\'');
2290 }
2291 
2293 {
2294  return KDbEscapedString('\'') + timeToSqlInternal(v, false) + KDbEscapedString('\'');
2295 }
2296 
2298 {
2299  return KDbEscapedString('\'') + dateTimeToSqlInternal(v, 'T', false) + KDbEscapedString('\'');
2300 }
2301 
2302 //--------------------------------------------------------------------------------
2303 
2304 #ifdef KDB_DEBUG_GUI
2305 
2306 static KDb::DebugGUIHandler s_debugGUIHandler = nullptr;
2307 
2308 void KDb::setDebugGUIHandler(KDb::DebugGUIHandler handler)
2309 {
2310  s_debugGUIHandler = handler;
2311 }
2312 
2313 void KDb::debugGUI(const QString& text)
2314 {
2315  if (s_debugGUIHandler)
2316  s_debugGUIHandler(text);
2317 }
2318 
2319 static KDb::AlterTableActionDebugGUIHandler s_alterTableActionDebugHandler = nullptr;
2320 
2321 void KDb::setAlterTableActionDebugHandler(KDb::AlterTableActionDebugGUIHandler handler)
2322 {
2323  s_alterTableActionDebugHandler = handler;
2324 }
2325 
2326 void KDb::alterTableActionDebugGUI(const QString& text, int nestingLevel)
2327 {
2328  if (s_alterTableActionDebugHandler)
2329  s_alterTableActionDebugHandler(text, nestingLevel);
2330 }
2331 
2332 #endif // KDB_DEBUG_GUI
2333 
2334 #include "KDb.moc"
QString caption() const
Definition: KDbField.cpp:316
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
Q_OBJECTQ_OBJECT
void append(const T &value)
bool isNull() const const
QMap::const_iterator constBegin() const const
T & first()
KDB_EXPORT QVariant loadPropertyValueFromDom(const QDomNode &node, bool *ok)
Definition: KDb.cpp:1123
tristate containsTable(const QString &tableName)
KDB_EXPORT QString escapeIdentifier(const QString &string)
Definition: KDb.cpp:1334
bool isNull() const const
QVariant defaultValue() const
Definition: KDbField.cpp:281
void squeeze()
bool isNull() const const
void truncate(int position)
short toShort(bool *ok, int base) const const
int toInt(bool *ok, int base) const const
QString text() const const
tristate querySingleNumber(const KDbEscapedString &sql, int *number, int column=0, QueryRecordOptions options=QueryRecordOption::Default)
virtual KDbEscapedString recentSqlString() const
QString description() const
Definition: KDbField.cpp:331
KDB_EXPORT void getProperties(const KDbLookupFieldSchema *lookup, QMap< QByteArray, QVariant > *values)
Definition: KDb.cpp:758
QDomElement toElement() const const
Provides information about lookup field's setup.
KDB_EXPORT QList< int > deserializeIntList(const QString &data, bool *ok)
Definition: KDb.cpp:1842
QString number(int n, int base)
KDB_EXPORT bool splitToTableAndFieldParts(const QString &string, QString *tableName, QString *fieldName, SplitToTableAndFieldPartsOptions option=FailIfNoTableOrFieldName)
Definition: KDb.cpp:603
QString fromUtf8(const char *str, int size)
KDB_EXPORT QVariant cstringToVariant(const char *data, KDbField::Type type, bool *ok, int length=-1, KDb::Signedness signedness=KDb::Signed)
Definition: KDb.cpp:1984
virtual void reject()
QChar toLower() const const
int size() const const
CaseInsensitive
bool waitForFinished(int msecs)
Q_SLOTSQ_SLOTS
KDB_EXPORT bool deleteAllRecords(KDbConnection *conn, const QString &tableName)
Deletes all records from table tableName.
Definition: KDb.cpp:384
@ InvalidType
Definition: KDbField.h:86
bool remove()
KDB_EXPORT QStringList fieldTypeNamesForGroup(KDbField::TypeGroup typeGroup)
Definition: KDb.cpp:490
Type type(const QSqlDatabase &db)
KDB_EXPORT QDomElement saveNumberElementToDom(QDomDocument *doc, QDomElement *parentEl, const QString &elementName, int value)
Definition: KDb.cpp:1169
QDateTime currentDateTime()
QStringRef midRef(int position, int n) const const
KDbTableSchema * table()
Definition: KDbField.cpp:585
@ NotEmpty
only legal for string-like and blob fields
Definition: KDbField.h:139
int count(const T &value) const const
T value() const const
QByteArray encodeName(const QString &fileName)
@ Text
Definition: KDbField.h:98
int decimalPlaces(const int rangeMax, const int significantFigures)
virtual bool waitForBytesWritten(int msecs) override
KDB_EXPORT KDbEscapedString dateTimeToIsoString(const QVariant &v)
Converts date/time value to its string representation in ISO 8601 DateTime format - with "T" delimite...
Definition: KDb.cpp:2297
void clear()
bool testFlag(Enum flag) const const
A database connectivity and creation framework.
QString arg(Args &&... args) const const
QDomText createTextNode(const QString &value)
Specialized string for escaping.
KDB_EXPORT bool importSqliteFile(const QString &inputFileName, const QString &outputFileName)
Definition: KDb.cpp:2083
QString & prepend(QChar ch)
qlonglong toLongLong(bool *ok, int base) const const
KDB_EXPORT KDbEscapedString dateToSql(const QVariant &v)
Converts date value to its string representation required by KDBSQL commands.
Definition: KDb.cpp:2223
KDB_EXPORT KDbField::TypeGroup intToFieldTypeGroup(int typeGroup)
Definition: KDb.cpp:678
virtual QString escapeIdentifier(const QString &id) const
Identifier escaping function in the associated KDbDriver.
Database driver's abstraction.
Definition: KDbDriver.h:49
KDbResultable * resultable() const
QByteArray toLatin1() const const
bool isUniqueKey() const
Definition: KDbField.h:292
QList::const_iterator constBegin() const const
KDB_EXPORT QDomElement saveBooleanElementToDom(QDomDocument *doc, QDomElement *parentEl, const QString &elementName, bool value)
Definition: KDb.cpp:1183
void reserve(int size)
Options options() const
Definition: KDbField.cpp:261
QByteArray toByteArray() const const
ushort toUShort(bool *ok, int base) const const
QString message
Error message, empty by default.
Definition: KDbError.h:128
bool setProperties(const QMap< QByteArray, QVariant > &values)
void clear()
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
QDomElement createElement(const QString &tagName)
bool isFPNumericType() const
Definition: KDbField.h:335
QDate toDate() const const
bool exists() const const
KDB_DEPRECATED_EXPORT KDbEscapedString dateTimeToSql(const QDateTime &v)
Converts date/time value to its string representation in ISO 8601 DateTime format - with "T" delimite...
Definition: KDb.cpp:2282
KDB_EXPORT QStringList libraryPaths()
Definition: KDb.cpp:2043
QString simplified() const const
KDB_EXPORT QString defaultFileBasedDriverMimeType()
Definition: KDb.cpp:1962
@ LastType
Definition: KDbField.h:102
void setPrecision(int p)
Definition: KDbField.cpp:676
KDB_EXPORT QVariant emptyValueForFieldType(KDbField::Type type)
Used in KDb::emptyValueForFieldType()
Definition: KDb.cpp:1222
char at(int i) const const
KDB_EXPORT QString sqlite3ProgramPath()
Definition: KDb.cpp:2074
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
KDB_EXPORT KDbField::Type intToFieldType(int type)
Definition: KDb.cpp:670
KDB_EXPORT bool setFieldProperty(KDbField *field, const QByteArray &propertyName, const QVariant &value)
Definition: KDb.cpp:981
QString typeName() const
Definition: KDbField.h:377
void setVisibleDecimalPlaces(int p)
Definition: KDbField.cpp:692
KDB_EXPORT KDbField::Type defaultFieldTypeForGroup(KDbField::TypeGroup typeGroup)
Definition: KDb.cpp:500
KDbResult result() const
virtual KDbEscapedString escapeString(const QString &str) const =0
KDB_EXPORT bool isLookupFieldSchemaProperty(const QByteArray &propertyName)
for isLookupFieldSchemaProperty()
Definition: KDb.cpp:976
void setOptions(Options options)
Definition: KDbField.cpp:266
QString typeString() const
Definition: KDbField.h:393
Interface for classes providing a result.
void setType(Type t)
Definition: KDbField.cpp:620
QTime currentTime()
KDB_EXPORT QString unescapeString(const QString &string, char quote, int *errorPosition=nullptr)
Unescapes characters in string string for the KDBSQL dialect.
KDB_EXPORT QVariant stringToVariant(const QString &s, QVariant::Type type, bool *ok)
Definition: KDb.cpp:1859
KDB_EXPORT bool isKDbSqlKeyword(const QByteArray &word)
bool isAutoIncrementAllowed() const
Definition: KDbField.h:531
bool isTextType() const
Definition: KDbField.h:353
Record source information that can be specified for the lookup field schema.
bool isIntegerType() const
Definition: KDbField.h:326
KDB_EXPORT void getLimitsForFieldType(KDbField::Type type, qlonglong *minValue, qlonglong *maxValue, KDb::Signedness signedness=KDb::Signed)
Provides limits for values of type type.
Definition: KDb.cpp:1912
void setMaxLengthStrategy(MaxLengthStrategy strategy)
Definition: KDbField.cpp:660
QString absoluteFilePath() const const
bool executeSql(const KDbEscapedString &sql)
Executes a new native (raw, backend-specific) SQL query.
QVariant::Type type() const const
KDB_EXPORT QString simplifiedFieldTypeName(KDbField::Type type)
Definition: KDb.cpp:1951
void setConstraints(Constraints c)
Definition: KDbField.cpp:630
bool setProperty(const QByteArray &propertyName, const QVariant &value)
virtual QString serverResultName() const
Definition: KDbResult.cpp:209
virtual void run()
DisplayWidget displayWidget() const
KDB_EXPORT QString identifierExpectedMessage(const QString &valueName, const QVariant &v)
Definition: KDb.cpp:2191
QMap::const_iterator constEnd() const const
QVariant::Type variantType() const
Converts field's type to QVariant equivalent as accurate as possible.
Definition: KDbField.h:368
@ Integer
Definition: KDbField.h:90
void setDescription(const QString &description)
Definition: KDbField.cpp:336
KDbLookupFieldSchemaRecordSource recordSource() const
KDB_EXPORT bool deleteRecords(KDbConnection *conn, const QString &tableName, const QString &keyname, KDbField::Type keytype, const QVariant &keyval)
Deletes records using one generic criteria.
Definition: KDb.cpp:342
KDB_EXPORT bool supportsVisibleDecimalPlacesProperty(KDbField::Type type)
Definition: KDb.cpp:623
bool isEmpty() const const
KDB_EXPORT bool isDefaultValueAllowed(const KDbField &field)
Definition: KDb.cpp:1907
Constraints constraints() const
Definition: KDbField.cpp:301
int length() const const
bool waitForStarted(int msecs)
KDB_EXPORT QList< int > stringListToIntList(const QStringList &list, bool *ok=nullptr)
Definition: KDb.cpp:1766
KDB_EXPORT int loadIntPropertyValueFromDom(const QDomNode &node, bool *ok)
Definition: KDb.cpp:1097
QString description
Detailed error description, empty by default.
Definition: KDbError.h:129
Generic time constant.
Definition: KDbDateTime.h:260
KDB_EXPORT QStringList fieldTypeStringsForGroup(KDbField::TypeGroup typeGroup)
Definition: KDb.cpp:495
KDB_EXPORT QString escapeIdentifierAndAddQuotes(const QString &string)
Definition: KDb.cpp:1346
TypeGroup typeGroup() const
Definition: KDbField.h:382
virtual void accept()
int maxLength() const
Definition: KDbField.cpp:665
int toInt(bool *ok) const const
int toInt(bool *ok, int base) const const
KDB_EXPORT bool setFieldProperties(KDbField *field, const QMap< QByteArray, QVariant > &values)
Definition: KDb.cpp:833
KDB_EXPORT KDbField::Type maximumForIntegerFieldTypes(KDbField::Type t1, KDbField::Type t2)
Definition: KDb.cpp:1936
QueuedConnection
QList< int > columnWidths() const
bool isEmpty() const const
int precision() const
Definition: KDbField.cpp:286
KDB_EXPORT QByteArray zeroXHexToByteArray(const char *data, int length=-1, bool *ok=nullptr)
Definition: KDb.cpp:1740
QDate currentDate()
KDB_EXPORT void getFieldProperties(const KDbField &field, QMap< QByteArray, QVariant > *values)
Definition: KDb.cpp:787
virtual int exec()
@ SetFieldNameIfNoTableName
see splitToTableAndFieldParts()
Definition: KDb.h:248
bool isError() const
Definition: KDbResult.cpp:64
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition: KDbTristate.h:100
@ BigInteger
Definition: KDbField.h:91
Type type() const
Definition: KDbField.cpp:379
bool isNumericType() const
Definition: KDbField.h:317
void setCaption(const QString &caption)
Definition: KDbField.cpp:321
KDB_EXPORT QStringList deserializeList(const QString &data)
Definition: KDb.cpp:1813
bool convert(int targetTypeId)
virtual KDbEscapedString escapeString(const QString &str) const
uint toUInt(bool *ok, int base) const const
QDir absoluteDir() const const
QString message
@ Double
Definition: KDbField.h:97
QString path() const const
QString nodeName() const const
double toDouble(bool *ok) const const
KDB_EXPORT KDbEscapedString valueToSql(KDbField::Type ftype, const QVariant &v)
Definition: KDb.cpp:2201
bool toBool() const const
KDB_EXPORT bool isEmptyValue(KDbField::Type type, const QVariant &value)
Definition: KDb.cpp:429
@ LongText
Definition: KDbField.h:99
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString & replace(int position, int n, QChar after)
@ Byte
Definition: KDbField.h:87
void setName(const QString &name)
Definition: KDbField.cpp:615
@ Signed
Values can be both positive and negative.
Definition: KDbGlobal.h:152
bool canConvert(int targetTypeId) const const
Q_SIGNALSQ_SIGNALS
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
LocaleWrapper locale()
KDB_EXPORT QString defaultFileBasedDriverId()
Definition: KDb.cpp:1967
virtual KDbEscapedString valueToSql(KDbField::Type ftype, const QVariant &v) const
Definition: KDbDriver.cpp:246
KDB_EXPORT QString escapeBLOB(const QByteArray &array, BLOBEscapingType type)
typedef ConstIterator
QString typeGroupName() const
Definition: KDbField.h:387
bool setLookupFieldSchema(const QString &fieldName, KDbLookupFieldSchema *lookupFieldSchema)
Generic date/time constant.
Definition: KDbDateTime.h:403
Signedness
A property of numeric values.
Definition: KDbGlobal.h:150
KDB_EXPORT bool isIdentifier(const QString &s)
Definition: KDb.cpp:2125
Detailed definition of driver's default behavior.
QDateTime toDateTime() const const
KDB_EXPORT quint64 lastInsertedAutoIncValue(QSharedPointer< KDbSqlResult > result, const QString &autoIncrementFieldName, const QString &tableName, quint64 *recordId=nullptr)
Returns value of last inserted record for an autoincrement field.
Definition: KDb.cpp:392
KDB_EXPORT KDbEscapedString dateToIsoString(const QVariant &v)
Converts date value to its string representation in ISO 8601 DateTime format.
Definition: KDb.cpp:2287
bool isEmpty() const const
@ Boolean
Definition: KDbField.h:92
Structure for storing single record with type information.
Definition: KDbRecordData.h:36
T iif(bool ok, const T &value)
Definition: KDb.h:841
KDB_EXPORT QByteArray pgsqlByteaToByteArray(const char *data, int length=-1)
Definition: KDb.cpp:1661
KDB_EXPORT QString numberToString(double value, int decimalPlaces)
Definition: KDb.cpp:654
void resize(int size)
QList::const_iterator constEnd() const const
KDB_EXPORT KDbVersionInfo version()
Definition: KDb.cpp:336
QList< int > visibleColumns() const
KDB_EXPORT QString variantToString(const QVariant &v)
Definition: KDb.cpp:1848
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setDefaultValue(const QVariant &def)
Definition: KDbField.cpp:711
QDomNode appendChild(const QDomNode &newChild)
tristate querySingleRecord(const KDbEscapedString &sql, KDbRecordData *data, QueryRecordOptions options=QueryRecordOption::Default)
KDB_EXPORT KDbEscapedString sqlWhere(KDbDriver *drv, KDbField::Type t, const QString &fieldName, const QVariant &value)
Definition: KDb.cpp:440
QString left(int n) const const
QString fromLatin1(const char *str, int size)
void setCustomProperty(const QByteArray &propertyName, const QVariant &value)
Sets value value for custom property propertyName.
Definition: KDbField.cpp:1042
QString toUserVisibleString(UserVisibleStringOptions options=UserVisibleStringOption::AddUser) const
QTime toTime() const const
KDB_EXPORT tristate showConnectionTestDialog(QWidget *parent, const KDbConnectionData &data, KDbMessageHandler *msgHandler)
Shows connection test dialog.
Definition: KDb.cpp:592
MessageType
Message types.
Database specific connection data, e.g. host, port.
void setMaxLength(int maxLength)
Definition: KDbField.cpp:670
const QChar at(int position) const const
KDB_EXPORT QString temporaryTableName(KDbConnection *conn, const QString &baseName)
Definition: KDb.cpp:2055
KDB_EXPORT QString loadStringPropertyValueFromDom(const QDomNode &node, bool *ok)
Definition: KDb.cpp:1110
Meta-data for a field.
Definition: KDbField.h:71
KDB_EXPORT QString escapeString(const QString &string)
Definition: KDb.cpp:1356
KDB_EXPORT QString serializeList(const QStringList &list)
Definition: KDb.cpp:1783
MaxLengthStrategy maxLengthStrategy() const
Definition: KDbField.cpp:655
KDB_EXPORT bool isExtendedTableFieldProperty(const QByteArray &propertyName)
for isExtendedTableProperty()
Definition: KDb.cpp:954
int size() const const
KDB_EXPORT void getHTMLErrorMesage(const KDbResultable &resultable, QString *msg, QString *details)
Sets HTML-formatted error message with extra details obtained from result object.
Definition: KDb.cpp:505
KDB_EXPORT tristate idForObjectName(KDbConnection *conn, int *id, const QString &objName, int objType)
Finds an identifier for object objName of type objType.
Definition: KDb.cpp:579
@ Float
Definition: KDbField.h:96
int compare(const QString &other, Qt::CaseSensitivity cs) const const
A driver manager for finding and loading driver plugins.
QStringList toStringList() const const
KDB_EXPORT KDbEscapedString timeToSql(const QVariant &v)
Converts time value to its string representation required by KDBSQL commands.
Definition: KDb.cpp:2249
int length() const const
Generic date constant.
Definition: KDbDateTime.h:157
Provides database connection, allowing queries and data modification.
Definition: KDbConnection.h:51
QString name() const
Definition: KDbField.cpp:256
KDbDriver * driver() const
bool ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE
void reset(T *other)
char toLatin1() const const
QString mid(int position, int n) const const
Q_DISABLE_COPY(Class)
KDB_EXPORT QByteArray xHexToByteArray(const char *data, int length=-1, bool *ok=nullptr)
Definition: KDb.cpp:1711
int capacity() const const
@ ShortInteger
Definition: KDbField.h:89
QString serverMessage
@ Unsigned
Values can be both non-negative.
Definition: KDbGlobal.h:153
@ Hex
Escaping like 1FAD without quotes or prefixes.
QVector< V > values(const QMultiHash< K, V > &c)
QString message
T value(int i) const const
QString & append(QChar ch)
SplitToTableAndFieldPartsOptions
Used in splitToTableAndFieldParts().
Definition: KDb.h:246
void closeWriteChannel()
KDB_EXPORT QString numberToLocaleString(double value, int decimalPlaces)
Returns number converted to string using default locale.
Definition: KDb.cpp:659
bool isReadable() const const
QString messageTitle
ushort unicode() const const
qint64 write(const char *data, qint64 maxSize)
KDB_EXPORT KDbEscapedString timeToIsoString(const QVariant &v)
Converts time value to its string representation in ISO 8601 Time format.
Definition: KDb.cpp:2292
KDbDriver * driver(const QString &id)
QString toString() const const
QChar fromLatin1(char c)
KDB_EXPORT QString stringToIdentifier(const QString &s)
Definition: KDb.cpp:2158
KDbLookupFieldSchema * lookupFieldSchema(const KDbField &field)
@ DefaultMaxLength
Default maximum text length defined globally by the application.
Definition: KDbField.h:430
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Oct 3 2023 04:09:13 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.