Qt 4.8
qsql_mysql.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSql module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsql_mysql.h"
43 
44 #include <qcoreapplication.h>
45 #include <qvariant.h>
46 #include <qdatetime.h>
47 #include <qsqlerror.h>
48 #include <qsqlfield.h>
49 #include <qsqlindex.h>
50 #include <qsqlquery.h>
51 #include <qsqlrecord.h>
52 #include <qstringlist.h>
53 #include <qtextcodec.h>
54 #include <qvector.h>
55 
56 #include <qdebug.h>
57 
58 #ifdef Q_OS_WIN32
59 // comment the next line out if you want to use MySQL/embedded on Win32 systems.
60 // note that it will crash if you don't statically link to the mysql/e library!
61 # define Q_NO_MYSQL_EMBEDDED
62 #endif
63 
64 Q_DECLARE_METATYPE(MYSQL_RES*)
65 Q_DECLARE_METATYPE(MYSQL*)
66 
67 #if MYSQL_VERSION_ID >= 40108
68 Q_DECLARE_METATYPE(MYSQL_STMT*)
69 #endif
70 
71 #if MYSQL_VERSION_ID >= 40100
72 # define Q_CLIENT_MULTI_STATEMENTS CLIENT_MULTI_STATEMENTS
73 #else
74 # define Q_CLIENT_MULTI_STATEMENTS 0
75 #endif
76 
78 
80 {
81 public:
83 #ifndef QT_NO_TEXTCODEC
84  tc(QTextCodec::codecForLocale()),
85 #else
86  tc(0),
87 #endif
88  preparedQuerysEnabled(false) {}
89  MYSQL *mysql;
91 
93 };
94 
95 static inline QString toUnicode(QTextCodec *tc, const char *str)
96 {
97 #ifdef QT_NO_TEXTCODEC
98  Q_UNUSED(tc);
99  return QString::fromLatin1(str);
100 #else
101  return tc->toUnicode(str);
102 #endif
103 }
104 
105 static inline QString toUnicode(QTextCodec *tc, const char *str, int length)
106 {
107 #ifdef QT_NO_TEXTCODEC
108  Q_UNUSED(tc);
109  return QString::fromLatin1(str, length);
110 #else
111  return tc->toUnicode(str, length);
112 #endif
113 }
114 
115 static inline QByteArray fromUnicode(QTextCodec *tc, const QString &str)
116 {
117 #ifdef QT_NO_TEXTCODEC
118  Q_UNUSED(tc);
119  return str.toLatin1();
120 #else
121  return tc->fromUnicode(str);
122 #endif
123 }
124 
125 static inline QVariant qDateFromString(const QString &val)
126 {
127 #ifdef QT_NO_DATESTRING
128  Q_UNUSED(val);
129  return QVariant(val);
130 #else
131  if (val.isEmpty())
132  return QVariant(QDate());
133  return QVariant(QDate::fromString(val, Qt::ISODate));
134 #endif
135 }
136 
137 static inline QVariant qTimeFromString(const QString &val)
138 {
139 #ifdef QT_NO_DATESTRING
140  Q_UNUSED(val);
141  return QVariant(val);
142 #else
143  if (val.isEmpty())
144  return QVariant(QTime());
145  return QVariant(QTime::fromString(val, Qt::ISODate));
146 #endif
147 }
148 
150 {
151 #ifdef QT_NO_DATESTRING
152  Q_UNUSED(val);
153  return QVariant(val);
154 #else
155  if (val.isEmpty())
156  return QVariant(QDateTime());
157  if (val.length() == 14)
158  // TIMESTAMPS have the format yyyyMMddhhmmss
159  val.insert(4, QLatin1Char('-')).insert(7, QLatin1Char('-')).insert(10,
160  QLatin1Char('T')).insert(13, QLatin1Char(':')).insert(16, QLatin1Char(':'));
162 #endif
163 }
164 
166 {
167  Q_OBJECT
168 public:
169  QMYSQLResultPrivate(const QMYSQLDriver* dp, const QMYSQLResult* d) : driver(dp), result(0), q(d),
170  rowsAffected(0), hasBlobs(false)
171 #if MYSQL_VERSION_ID >= 40108
172  , stmt(0), meta(0), inBinds(0), outBinds(0)
173 #endif
174  , preparedQuery(false)
175  {
176  connect(dp, SIGNAL(destroyed()), this, SLOT(driverDestroyed()));
177  }
178 
180  MYSQL_RES *result;
181  MYSQL_ROW row;
182  const QMYSQLResult* q;
183 
185 
186  bool bindInValues();
187  void bindBlobs();
188 
189  bool hasBlobs;
190  struct QMyField
191  {
193  : outField(0), nullIndicator(false), bufLength(0ul),
194  myField(0), type(QVariant::Invalid)
195  {}
196  char *outField;
197  my_bool nullIndicator;
199  MYSQL_FIELD *myField;
201  };
202 
204 
205 #if MYSQL_VERSION_ID >= 40108
206  MYSQL_STMT* stmt;
207  MYSQL_RES* meta;
208 
209  MYSQL_BIND *inBinds;
210  MYSQL_BIND *outBinds;
211 #endif
212 
214 
215 private Q_SLOTS:
216  void driverDestroyed() { driver = NULL; }
217 };
218 
219 #ifndef QT_NO_TEXTCODEC
220 static QTextCodec* codec(MYSQL* mysql)
221 {
222 #if MYSQL_VERSION_ID >= 32321
223  QTextCodec* heuristicCodec = QTextCodec::codecForName(mysql_character_set_name(mysql));
224  if (heuristicCodec)
225  return heuristicCodec;
226 #endif
228 }
229 #endif // QT_NO_TEXTCODEC
230 
232  const QMYSQLDriverPrivate* p)
233 {
234  const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
235  return QSqlError(QLatin1String("QMYSQL: ") + err,
236  p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
237  type, mysql_errno(p->mysql));
238 }
239 
240 
241 static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags)
242 {
244  switch (mysqltype) {
245  case FIELD_TYPE_TINY :
246  case FIELD_TYPE_SHORT :
247  case FIELD_TYPE_LONG :
248  case FIELD_TYPE_INT24 :
249  type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int;
250  break;
251  case FIELD_TYPE_YEAR :
252  type = QVariant::Int;
253  break;
254  case FIELD_TYPE_LONGLONG :
255  type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong;
256  break;
257  case FIELD_TYPE_FLOAT :
258  case FIELD_TYPE_DOUBLE :
259  case FIELD_TYPE_DECIMAL :
260 #if defined(FIELD_TYPE_NEWDECIMAL)
261  case FIELD_TYPE_NEWDECIMAL:
262 #endif
263  type = QVariant::Double;
264  break;
265  case FIELD_TYPE_DATE :
266  type = QVariant::Date;
267  break;
268  case FIELD_TYPE_TIME :
269  type = QVariant::Time;
270  break;
271  case FIELD_TYPE_DATETIME :
272  case FIELD_TYPE_TIMESTAMP :
273  type = QVariant::DateTime;
274  break;
275  case FIELD_TYPE_STRING :
276  case FIELD_TYPE_VAR_STRING :
277  case FIELD_TYPE_BLOB :
278  case FIELD_TYPE_TINY_BLOB :
279  case FIELD_TYPE_MEDIUM_BLOB :
280  case FIELD_TYPE_LONG_BLOB :
281  type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::String;
282  break;
283  default:
284  case FIELD_TYPE_ENUM :
285  case FIELD_TYPE_SET :
286  type = QVariant::String;
287  break;
288  }
289  return type;
290 }
291 
292 static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
293 {
294  QSqlField f(toUnicode(tc, field->name),
295  qDecodeMYSQLType(int(field->type), field->flags));
296  f.setRequired(IS_NOT_NULL(field->flags));
297  f.setLength(field->length);
298  f.setPrecision(field->decimals);
299  f.setSqlType(field->type);
300  f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
301  return f;
302 }
303 
304 #if MYSQL_VERSION_ID >= 40108
305 
306 static QSqlError qMakeStmtError(const QString& err, QSqlError::ErrorType type,
307  MYSQL_STMT* stmt)
308 {
309  const char *cerr = mysql_stmt_error(stmt);
310  return QSqlError(QLatin1String("QMYSQL3: ") + err,
311  QString::fromLatin1(cerr),
312  type, mysql_stmt_errno(stmt));
313 }
314 
315 static bool qIsBlob(int t)
316 {
317  return t == MYSQL_TYPE_TINY_BLOB
318  || t == MYSQL_TYPE_BLOB
319  || t == MYSQL_TYPE_MEDIUM_BLOB
320  || t == MYSQL_TYPE_LONG_BLOB;
321 }
322 
323 static bool qIsInteger(int t)
324 {
325  return t == MYSQL_TYPE_TINY
326  || t == MYSQL_TYPE_SHORT
327  || t == MYSQL_TYPE_LONG
328  || t == MYSQL_TYPE_LONGLONG
329  || t == MYSQL_TYPE_INT24;
330 }
331 
332 
334 {
335  int i;
336  MYSQL_FIELD *fieldInfo;
337  MYSQL_BIND *bind;
338 
339  for(i = 0; i < fields.count(); ++i) {
340  fieldInfo = fields.at(i).myField;
341  if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) {
342  bind = &inBinds[i];
343  bind->buffer_length = fieldInfo->max_length;
344  delete[] static_cast<char*>(bind->buffer);
345  bind->buffer = new char[fieldInfo->max_length];
346  fields[i].outField = static_cast<char*>(bind->buffer);
347  }
348  }
349 }
350 
352 {
353  MYSQL_BIND *bind;
354  char *field;
355  int i = 0;
356 
357  if (!meta)
358  meta = mysql_stmt_result_metadata(stmt);
359  if (!meta)
360  return false;
361 
362  fields.resize(mysql_num_fields(meta));
363 
364  inBinds = new MYSQL_BIND[fields.size()];
365  memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND));
366 
367  MYSQL_FIELD *fieldInfo;
368 
369  while((fieldInfo = mysql_fetch_field(meta))) {
370  QMyField &f = fields[i];
371  f.myField = fieldInfo;
372 
373  f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags);
374  if (qIsBlob(fieldInfo->type)) {
375  // the size of a blob-field is available as soon as we call
376  // mysql_stmt_store_result()
377  // after mysql_stmt_exec() in QMYSQLResult::exec()
378  fieldInfo->length = 0;
379  hasBlobs = true;
380  } else {
381  // fieldInfo->length specifies the display width, which may be too
382  // small to hold valid integer values (see
383  // http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html ), so
384  // always use the MAX_BIGINT_WIDTH for integer types
385  if (qIsInteger(fieldInfo->type)) {
386  fieldInfo->length = MAX_BIGINT_WIDTH;
387  }
388  fieldInfo->type = MYSQL_TYPE_STRING;
389  }
390  bind = &inBinds[i];
391  field = new char[fieldInfo->length + 1];
392  memset(field, 0, fieldInfo->length + 1);
393 
394  bind->buffer_type = fieldInfo->type;
395  bind->buffer = field;
396  bind->buffer_length = f.bufLength = fieldInfo->length + 1;
397  bind->is_null = &f.nullIndicator;
398  bind->length = &f.bufLength;
399  f.outField=field;
400 
401  ++i;
402  }
403  return true;
404 }
405 #endif
406 
408 : QSqlResult(db)
409 {
410  d = new QMYSQLResultPrivate(db, this);
411 }
412 
414 {
415  cleanup();
416  delete d;
417 }
418 
420 {
421 #if MYSQL_VERSION_ID >= 40108
422  if(d->preparedQuery)
423  return d->meta ? QVariant::fromValue(d->meta) : qVariantFromValue(d->stmt);
424  else
425 #endif
426  return QVariant::fromValue(d->result);
427 }
428 
430 {
431  if (d->result)
432  mysql_free_result(d->result);
433 
434 // must iterate trough leftover result sets from multi-selects or stored procedures
435 // if this isn't done subsequent queries will fail with "Commands out of sync"
436 #if MYSQL_VERSION_ID >= 40100
437  while (d->driver && d->driver->d->mysql && mysql_next_result(d->driver->d->mysql) == 0) {
438  MYSQL_RES *res = mysql_store_result(d->driver->d->mysql);
439  if (res)
440  mysql_free_result(res);
441  }
442 #endif
443 
444 #if MYSQL_VERSION_ID >= 40108
445  if (d->stmt) {
446  if (mysql_stmt_close(d->stmt))
447  qWarning("QMYSQLResult::cleanup: unable to free statement handle");
448  d->stmt = 0;
449  }
450 
451  if (d->meta) {
452  mysql_free_result(d->meta);
453  d->meta = 0;
454  }
455 
456  int i;
457  for (i = 0; i < d->fields.count(); ++i)
458  delete[] d->fields[i].outField;
459 
460  if (d->outBinds) {
461  delete[] d->outBinds;
462  d->outBinds = 0;
463  }
464 
465  if (d->inBinds) {
466  delete[] d->inBinds;
467  d->inBinds = 0;
468  }
469 #endif
470 
471  d->hasBlobs = false;
472  d->fields.clear();
473  d->result = NULL;
474  d->row = NULL;
475  setAt(-1);
476  setActive(false);
477 }
478 
480 {
481  if(!d->driver)
482  return false;
483  if (isForwardOnly()) { // fake a forward seek
484  if (at() < i) {
485  int x = i - at();
486  while (--x && fetchNext()) {};
487  return fetchNext();
488  } else {
489  return false;
490  }
491  }
492  if (at() == i)
493  return true;
494  if (d->preparedQuery) {
495 #if MYSQL_VERSION_ID >= 40108
496  mysql_stmt_data_seek(d->stmt, i);
497 
498  int nRC = mysql_stmt_fetch(d->stmt);
499  if (nRC) {
500 #ifdef MYSQL_DATA_TRUNCATED
501  if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
502 #else
503  if (nRC == 1)
504 #endif
505  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
506  "Unable to fetch data"), QSqlError::StatementError, d->stmt));
507  return false;
508  }
509 #else
510  return false;
511 #endif
512  } else {
513  mysql_data_seek(d->result, i);
514  d->row = mysql_fetch_row(d->result);
515  if (!d->row)
516  return false;
517  }
518 
519  setAt(i);
520  return true;
521 }
522 
524 {
525  if(!d->driver)
526  return false;
527  if (d->preparedQuery) {
528 #if MYSQL_VERSION_ID >= 40108
529  int nRC = mysql_stmt_fetch(d->stmt);
530  if (nRC) {
531 #ifdef MYSQL_DATA_TRUNCATED
532  if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED)
533 #else
534  if (nRC == 1)
535 #endif // MYSQL_DATA_TRUNCATED
536  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
537  "Unable to fetch data"), QSqlError::StatementError, d->stmt));
538  return false;
539  }
540 #else
541  return false;
542 #endif
543  } else {
544  d->row = mysql_fetch_row(d->result);
545  if (!d->row)
546  return false;
547  }
548  setAt(at() + 1);
549  return true;
550 }
551 
553 {
554  if(!d->driver)
555  return false;
556  if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries
557  bool success = fetchNext(); // did we move at all?
558  while (fetchNext()) {};
559  return success;
560  }
561 
562  my_ulonglong numRows;
563  if (d->preparedQuery) {
564 #if MYSQL_VERSION_ID >= 40108
565  numRows = mysql_stmt_num_rows(d->stmt);
566 #else
567  numRows = 0;
568 #endif
569  } else {
570  numRows = mysql_num_rows(d->result);
571  }
572  if (at() == int(numRows))
573  return true;
574  if (!numRows)
575  return false;
576  return fetch(numRows - 1);
577 }
578 
580 {
581  if (at() == 0)
582  return true;
583 
584  if (isForwardOnly())
585  return (at() == QSql::BeforeFirstRow) ? fetchNext() : false;
586  return fetch(0);
587 }
588 
590 {
591 
592  if (!isSelect() || field >= d->fields.count()) {
593  qWarning("QMYSQLResult::data: column %d out of range", field);
594  return QVariant();
595  }
596 
597  if (!d->driver)
598  return QVariant();
599 
600  int fieldLength = 0;
601  const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
602  QString val;
603  if (d->preparedQuery) {
604  if (f.nullIndicator)
605  return QVariant(f.type);
606 
607  if (f.type != QVariant::ByteArray)
608  val = toUnicode(d->driver->d->tc, f.outField, f.bufLength);
609  } else {
610  if (d->row[field] == NULL) {
611  // NULL value
612  return QVariant(f.type);
613  }
614  fieldLength = mysql_fetch_lengths(d->result)[field];
615  if (f.type != QVariant::ByteArray)
616  val = toUnicode(d->driver->d->tc, d->row[field], fieldLength);
617  }
618 
619  switch(f.type) {
620  case QVariant::LongLong:
621  return QVariant(val.toLongLong());
622  case QVariant::ULongLong:
623  return QVariant(val.toULongLong());
624  case QVariant::Int:
625  return QVariant(val.toInt());
626  case QVariant::UInt:
627  return QVariant(val.toUInt());
628  case QVariant::Double: {
629  QVariant v;
630  bool ok=false;
631  double dbl = val.toDouble(&ok);
632  switch(numericalPrecisionPolicy()) {
634  v=QVariant(dbl).toInt();
635  break;
637  v = QVariant(dbl).toLongLong();
638  break;
640  v = QVariant(dbl);
641  break;
642  case QSql::HighPrecision:
643  default:
644  v = val;
645  ok = true;
646  break;
647  }
648  if(ok)
649  return v;
650  else
651  return QVariant();
652  }
653  return QVariant(val.toDouble());
654  case QVariant::Date:
655  return qDateFromString(val);
656  case QVariant::Time:
657  return qTimeFromString(val);
658  case QVariant::DateTime:
659  return qDateTimeFromString(val);
660  case QVariant::ByteArray: {
661 
662  QByteArray ba;
663  if (d->preparedQuery) {
664  ba = QByteArray(f.outField, f.bufLength);
665  } else {
666  ba = QByteArray(d->row[field], fieldLength);
667  }
668  return QVariant(ba);
669  }
670  default:
671  case QVariant::String:
672  return QVariant(val);
673  }
674  qWarning("QMYSQLResult::data: unknown data type");
675  return QVariant();
676 }
677 
678 bool QMYSQLResult::isNull(int field)
679 {
680  if (d->preparedQuery)
681  return d->fields.at(field).nullIndicator;
682  else
683  return d->row[field] == NULL;
684 }
685 
686 bool QMYSQLResult::reset (const QString& query)
687 {
688  if (!driver() || !driver()->isOpen() || driver()->isOpenError() || !d->driver)
689  return false;
690 
691  d->preparedQuery = false;
692 
693  cleanup();
694 
695  const QByteArray encQuery(fromUnicode(d->driver->d->tc, query));
696  if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) {
697  setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"),
699  return false;
700  }
701  d->result = mysql_store_result(d->driver->d->mysql);
702  if (!d->result && mysql_field_count(d->driver->d->mysql) > 0) {
703  setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"),
705  return false;
706  }
707  int numFields = mysql_field_count(d->driver->d->mysql);
708  setSelect(numFields != 0);
709  d->fields.resize(numFields);
710  d->rowsAffected = mysql_affected_rows(d->driver->d->mysql);
711 
712  if (isSelect()) {
713  for(int i = 0; i < numFields; i++) {
714  MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
715  d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
716  }
718  }
719  setActive(true);
720  return isActive();
721 }
722 
724 {
725  if (d->driver && isSelect())
726  if (d->preparedQuery)
727 #if MYSQL_VERSION_ID >= 40108
728  return mysql_stmt_num_rows(d->stmt);
729 #else
730  return -1;
731 #endif
732  else
733  return int(mysql_num_rows(d->result));
734  else
735  return -1;
736 }
737 
739 {
740  return d->rowsAffected;
741 }
742 
744 {
745  if (!isActive() || !d->driver)
746  return QVariant();
747 
748  if (d->preparedQuery) {
749 #if MYSQL_VERSION_ID >= 40108
750  quint64 id = mysql_stmt_insert_id(d->stmt);
751  if (id)
752  return QVariant(id);
753 #endif
754  } else {
755  quint64 id = mysql_insert_id(d->driver->d->mysql);
756  if (id)
757  return QVariant(id);
758  }
759  return QVariant();
760 }
761 
763 {
765  MYSQL_RES *res;
766  if (!isActive() || !isSelect() || !d->driver)
767  return info;
768 
769 #if MYSQL_VERSION_ID >= 40108
770  res = d->preparedQuery ? d->meta : d->result;
771 #else
772  res = d->result;
773 #endif
774 
775  if (!mysql_errno(d->driver->d->mysql)) {
776  mysql_field_seek(res, 0);
777  MYSQL_FIELD* field = mysql_fetch_field(res);
778  while(field) {
779  info.append(qToField(field, d->driver->d->tc));
780  field = mysql_fetch_field(res);
781  }
782  }
783  mysql_field_seek(res, 0);
784  return info;
785 }
786 
788 {
789  if(!d->driver)
790  return false;
791 #if MYSQL_VERSION_ID >= 40100
792  setAt(-1);
793  setActive(false);
794 
795  if (d->result && isSelect())
796  mysql_free_result(d->result);
797  d->result = 0;
798  setSelect(false);
799 
800  for (int i = 0; i < d->fields.count(); ++i)
801  delete[] d->fields[i].outField;
802  d->fields.clear();
803 
804  int status = mysql_next_result(d->driver->d->mysql);
805  if (status > 0) {
806  setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"),
808  return false;
809  } else if (status == -1) {
810  return false; // No more result sets
811  }
812 
813  d->result = mysql_store_result(d->driver->d->mysql);
814  int numFields = mysql_field_count(d->driver->d->mysql);
815  if (!d->result && numFields > 0) {
816  setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"),
818  return false;
819  }
820 
821  setSelect(numFields > 0);
822  d->fields.resize(numFields);
823  d->rowsAffected = mysql_affected_rows(d->driver->d->mysql);
824 
825  if (isSelect()) {
826  for (int i = 0; i < numFields; i++) {
827  MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i);
828  d->fields[i].type = qDecodeMYSQLType(field->type, field->flags);
829  }
830  }
831 
832  setActive(true);
833  return true;
834 #else
835  return false;
836 #endif
837 }
838 
839 void QMYSQLResult::virtual_hook(int id, void *data)
840 {
841  switch (id) {
843  Q_ASSERT(data);
844  *static_cast<bool*>(data) = nextResult();
845  break;
846  default:
847  QSqlResult::virtual_hook(id, data);
848  }
849 }
850 
851 
852 #if MYSQL_VERSION_ID >= 40108
853 
854 static MYSQL_TIME *toMySqlDate(QDate date, QTime time, QVariant::Type type)
855 {
856  Q_ASSERT(type == QVariant::Time || type == QVariant::Date
857  || type == QVariant::DateTime);
858 
859  MYSQL_TIME *myTime = new MYSQL_TIME;
860  memset(myTime, 0, sizeof(MYSQL_TIME));
861 
862  if (type == QVariant::Time || type == QVariant::DateTime) {
863  myTime->hour = time.hour();
864  myTime->minute = time.minute();
865  myTime->second = time.second();
866  myTime->second_part = time.msec();
867  }
868  if (type == QVariant::Date || type == QVariant::DateTime) {
869  myTime->year = date.year();
870  myTime->month = date.month();
871  myTime->day = date.day();
872  }
873 
874  return myTime;
875 }
876 
877 bool QMYSQLResult::prepare(const QString& query)
878 {
879  if(!d->driver)
880  return false;
881 #if MYSQL_VERSION_ID >= 40108
882  cleanup();
884  return QSqlResult::prepare(query);
885 
886  int r;
887 
888  if (query.isEmpty())
889  return false;
890 
891  if (!d->stmt)
892  d->stmt = mysql_stmt_init(d->driver->d->mysql);
893  if (!d->stmt) {
894  setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"),
896  return false;
897  }
898 
899  const QByteArray encQuery(fromUnicode(d->driver->d->tc, query));
900  r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.length());
901  if (r != 0) {
902  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
903  "Unable to prepare statement"), QSqlError::StatementError, d->stmt));
904  cleanup();
905  return false;
906  }
907 
908  if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues
909  d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)];
910  }
911 
913  d->preparedQuery = true;
914  return true;
915 #else
916  return false;
917 #endif
918 }
919 
920 bool QMYSQLResult::exec()
921 {
922  if (!d->driver)
923  return false;
924  if (!d->preparedQuery)
925  return QSqlResult::exec();
926  if (!d->stmt)
927  return false;
928 
929  int r = 0;
930  MYSQL_BIND* currBind;
931  QVector<MYSQL_TIME *> timeVector;
932  QVector<QByteArray> stringVector;
933  QVector<my_bool> nullVector;
934 
936 
937  r = mysql_stmt_reset(d->stmt);
938  if (r != 0) {
939  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
940  "Unable to reset statement"), QSqlError::StatementError, d->stmt));
941  return false;
942  }
943 
944  if (mysql_stmt_param_count(d->stmt) > 0 &&
945  mysql_stmt_param_count(d->stmt) == (uint)values.count()) {
946 
947  nullVector.resize(values.count());
948  for (int i = 0; i < values.count(); ++i) {
949  const QVariant &val = boundValues().at(i);
950  void *data = const_cast<void *>(val.constData());
951 
952  currBind = &d->outBinds[i];
953 
954  nullVector[i] = static_cast<my_bool>(val.isNull());
955  currBind->is_null = &nullVector[i];
956  currBind->length = 0;
957  currBind->is_unsigned = 0;
958 
959  switch (val.type()) {
960  case QVariant::ByteArray:
961  currBind->buffer_type = MYSQL_TYPE_BLOB;
962  currBind->buffer = const_cast<char *>(val.toByteArray().constData());
963  currBind->buffer_length = val.toByteArray().size();
964  break;
965 
966  case QVariant::Time:
967  case QVariant::Date:
968  case QVariant::DateTime: {
969  MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.type());
970  timeVector.append(myTime);
971 
972  currBind->buffer = myTime;
973  switch(val.type()) {
974  case QVariant::Time:
975  currBind->buffer_type = MYSQL_TYPE_TIME;
976  myTime->time_type = MYSQL_TIMESTAMP_TIME;
977  break;
978  case QVariant::Date:
979  currBind->buffer_type = MYSQL_TYPE_DATE;
980  myTime->time_type = MYSQL_TIMESTAMP_DATE;
981  break;
982  case QVariant::DateTime:
983  currBind->buffer_type = MYSQL_TYPE_DATETIME;
984  myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
985  break;
986  default:
987  break;
988  }
989  currBind->buffer_length = sizeof(MYSQL_TIME);
990  currBind->length = 0;
991  break; }
992  case QVariant::UInt:
993  case QVariant::Int:
994  currBind->buffer_type = MYSQL_TYPE_LONG;
995  currBind->buffer = data;
996  currBind->buffer_length = sizeof(int);
997  currBind->is_unsigned = (val.type() != QVariant::Int);
998  break;
999  case QVariant::Bool:
1000  currBind->buffer_type = MYSQL_TYPE_TINY;
1001  currBind->buffer = data;
1002  currBind->buffer_length = sizeof(bool);
1003  currBind->is_unsigned = false;
1004  break;
1005  case QVariant::Double:
1006  currBind->buffer_type = MYSQL_TYPE_DOUBLE;
1007  currBind->buffer = data;
1008  currBind->buffer_length = sizeof(double);
1009  break;
1010  case QVariant::LongLong:
1011  case QVariant::ULongLong:
1012  currBind->buffer_type = MYSQL_TYPE_LONGLONG;
1013  currBind->buffer = data;
1014  currBind->buffer_length = sizeof(qint64);
1015  currBind->is_unsigned = (val.type() == QVariant::ULongLong);
1016  break;
1017  case QVariant::String:
1018  default: {
1019  QByteArray ba = fromUnicode(d->driver->d->tc, val.toString());
1020  stringVector.append(ba);
1021  currBind->buffer_type = MYSQL_TYPE_STRING;
1022  currBind->buffer = const_cast<char *>(ba.constData());
1023  currBind->buffer_length = ba.length();
1024  break; }
1025  }
1026  }
1027 
1028  r = mysql_stmt_bind_param(d->stmt, d->outBinds);
1029  if (r != 0) {
1030  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
1031  "Unable to bind value"), QSqlError::StatementError, d->stmt));
1032  qDeleteAll(timeVector);
1033  return false;
1034  }
1035  }
1036  r = mysql_stmt_execute(d->stmt);
1037 
1038  qDeleteAll(timeVector);
1039 
1040  if (r != 0) {
1041  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
1042  "Unable to execute statement"), QSqlError::StatementError, d->stmt));
1043  return false;
1044  }
1045  //if there is meta-data there is also data
1046  setSelect(d->meta);
1047 
1048  d->rowsAffected = mysql_stmt_affected_rows(d->stmt);
1049 
1050  if (isSelect()) {
1051  my_bool update_max_length = true;
1052 
1053  r = mysql_stmt_bind_result(d->stmt, d->inBinds);
1054  if (r != 0) {
1055  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
1056  "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
1057  return false;
1058  }
1059  if (d->hasBlobs)
1060  mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length);
1061 
1062  r = mysql_stmt_store_result(d->stmt);
1063  if (r != 0) {
1064  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
1065  "Unable to store statement results"), QSqlError::StatementError, d->stmt));
1066  return false;
1067  }
1068 
1069  if (d->hasBlobs) {
1070  // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes
1071  // when called without a preceding call to mysql_stmt_bind_result()
1072  // in versions < 4.1.8
1073  d->bindBlobs();
1074  r = mysql_stmt_bind_result(d->stmt, d->inBinds);
1075  if (r != 0) {
1076  setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
1077  "Unable to bind outvalues"), QSqlError::StatementError, d->stmt));
1078  return false;
1079  }
1080  }
1082  }
1083  setActive(true);
1084  return true;
1085 }
1086 #endif
1087 
1089 static int qMySqlConnectionCount = 0;
1090 static bool qMySqlInitHandledByUser = false;
1091 
1092 static void qLibraryInit()
1093 {
1094 #ifndef Q_NO_MYSQL_EMBEDDED
1095 # if MYSQL_VERSION_ID >= 40000
1096  if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1)
1097  return;
1098 
1099 # if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
1100  if (mysql_library_init(0, 0, 0)) {
1101 # else
1102  if (mysql_server_init(0, 0, 0)) {
1103 # endif
1104  qWarning("QMYSQLDriver::qServerInit: unable to start server.");
1105  }
1106 # endif // MYSQL_VERSION_ID
1107 #endif // Q_NO_MYSQL_EMBEDDED
1108 }
1109 
1110 static void qLibraryEnd()
1111 {
1112 #ifndef Q_NO_MYSQL_EMBEDDED
1113 # if MYSQL_VERSION_ID > 40000
1114 # if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003
1115  mysql_library_end();
1116 # else
1117  mysql_server_end();
1118 # endif
1119 # endif
1120 #endif
1121 }
1122 
1124  : QSqlDriver(parent)
1125 {
1126  init();
1127  qLibraryInit();
1128 }
1129 
1136  : QSqlDriver(parent)
1137 {
1138  init();
1139  if (con) {
1140  d->mysql = (MYSQL *) con;
1141 #ifndef QT_NO_TEXTCODEC
1142  d->tc = codec(con);
1143 #endif
1144  setOpen(true);
1145  setOpenError(false);
1146  if (qMySqlConnectionCount == 1)
1147  qMySqlInitHandledByUser = true;
1148  } else {
1149  qLibraryInit();
1150  }
1151 }
1152 
1154 {
1155  d = new QMYSQLDriverPrivate();
1156  d->mysql = 0;
1157  qMySqlConnectionCount++;
1158 }
1159 
1161 {
1162  qMySqlConnectionCount--;
1163  if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser)
1164  qLibraryEnd();
1165  delete d;
1166 }
1167 
1169 {
1170  switch (f) {
1171  case Transactions:
1172 // CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34
1173 #ifdef CLIENT_TRANSACTIONS
1174  if (d->mysql) {
1175  if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS)
1176  return true;
1177  }
1178 #endif
1179  return false;
1180  case NamedPlaceholders:
1181  case BatchOperations:
1182  case SimpleLocking:
1183  case EventNotifications:
1184  case FinishQuery:
1185  return false;
1186  case QuerySize:
1187  case BLOB:
1188  case LastInsertId:
1189  case Unicode:
1190  case LowPrecisionNumbers:
1191  return true;
1192  case PreparedQueries:
1194 #if MYSQL_VERSION_ID >= 40108
1195  return d->preparedQuerysEnabled;
1196 #else
1197  return false;
1198 #endif
1199  case MultipleResultSets:
1200 #if MYSQL_VERSION_ID >= 40100
1201  return true;
1202 #else
1203  return false;
1204 #endif
1205  }
1206  return false;
1207 }
1208 
1209 static void setOptionFlag(uint &optionFlags, const QString &opt)
1210 {
1211  if (opt == QLatin1String("CLIENT_COMPRESS"))
1212  optionFlags |= CLIENT_COMPRESS;
1213  else if (opt == QLatin1String("CLIENT_FOUND_ROWS"))
1214  optionFlags |= CLIENT_FOUND_ROWS;
1215  else if (opt == QLatin1String("CLIENT_IGNORE_SPACE"))
1216  optionFlags |= CLIENT_IGNORE_SPACE;
1217  else if (opt == QLatin1String("CLIENT_INTERACTIVE"))
1218  optionFlags |= CLIENT_INTERACTIVE;
1219  else if (opt == QLatin1String("CLIENT_NO_SCHEMA"))
1220  optionFlags |= CLIENT_NO_SCHEMA;
1221  else if (opt == QLatin1String("CLIENT_ODBC"))
1222  optionFlags |= CLIENT_ODBC;
1223  else if (opt == QLatin1String("CLIENT_SSL"))
1224  optionFlags |= CLIENT_SSL;
1225  else
1226  qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData());
1227 }
1228 
1230  const QString& user,
1231  const QString& password,
1232  const QString& host,
1233  int port,
1234  const QString& connOpts)
1235 {
1236  if (isOpen())
1237  close();
1238 
1239  /* This is a hack to get MySQL's stored procedure support working.
1240  Since a stored procedure _may_ return multiple result sets,
1241  we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_
1242  stored procedure call will fail.
1243  */
1244  unsigned int optionFlags = Q_CLIENT_MULTI_STATEMENTS;
1245  const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
1246  QString unixSocket;
1247 #if MYSQL_VERSION_ID >= 50000
1248  my_bool reconnect=false;
1249 #endif
1250 
1251  // extract the real options from the string
1252  for (int i = 0; i < opts.count(); ++i) {
1253  QString tmp(opts.at(i).simplified());
1254  int idx;
1255  if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
1256  QString val = tmp.mid(idx + 1).simplified();
1257  QString opt = tmp.left(idx).simplified();
1258  if (opt == QLatin1String("UNIX_SOCKET"))
1259  unixSocket = val;
1260 #if MYSQL_VERSION_ID >= 50000
1261  else if (opt == QLatin1String("MYSQL_OPT_RECONNECT")) {
1262  if (val == QLatin1String("TRUE") || val == QLatin1String("1") || val.isEmpty())
1263  reconnect = true;
1264  }
1265 #endif
1266  else if (val == QLatin1String("TRUE") || val == QLatin1String("1"))
1267  setOptionFlag(optionFlags, tmp.left(idx).simplified());
1268  else
1269  qWarning("QMYSQLDriver::open: Illegal connect option value '%s'",
1270  tmp.toLocal8Bit().constData());
1271  } else {
1272  setOptionFlag(optionFlags, tmp);
1273  }
1274  }
1275 
1276  if ((d->mysql = mysql_init((MYSQL*) 0)) &&
1277  mysql_real_connect(d->mysql,
1278  host.isNull() ? static_cast<const char *>(0)
1279  : host.toLocal8Bit().constData(),
1280  user.isNull() ? static_cast<const char *>(0)
1281  : user.toLocal8Bit().constData(),
1282  password.isNull() ? static_cast<const char *>(0)
1283  : password.toLocal8Bit().constData(),
1284  db.isNull() ? static_cast<const char *>(0)
1285  : db.toLocal8Bit().constData(),
1286  (port > -1) ? port : 0,
1287  unixSocket.isNull() ? static_cast<const char *>(0)
1288  : unixSocket.toLocal8Bit().constData(),
1289  optionFlags))
1290  {
1291  if (!db.isEmpty() && mysql_select_db(d->mysql, db.toLocal8Bit().constData())) {
1292  setLastError(qMakeError(tr("Unable to open database '") + db +
1294  mysql_close(d->mysql);
1295  setOpenError(true);
1296  return false;
1297  }
1298 #if MYSQL_VERSION_ID >= 50000
1299  if(reconnect)
1300  mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect);
1301 #endif
1302  } else {
1303  setLastError(qMakeError(tr("Unable to connect"),
1305  mysql_close(d->mysql);
1306  d->mysql = NULL;
1307  setOpenError(true);
1308  return false;
1309  }
1310 
1311 #if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007
1312  // force the communication to be utf8
1313  mysql_set_character_set(d->mysql, "utf8");
1314 #endif
1315 #ifndef QT_NO_TEXTCODEC
1316  d->tc = codec(d->mysql);
1317 #endif
1318 
1319 #if MYSQL_VERSION_ID >= 40108
1320  d->preparedQuerysEnabled = mysql_get_client_version() >= 40108
1321  && mysql_get_server_version(d->mysql) >= 40100;
1322 #else
1323  d->preparedQuerysEnabled = false;
1324 #endif
1325 
1326 #ifndef QT_NO_THREAD
1327  mysql_thread_init();
1328 #endif
1329 
1330 
1331  setOpen(true);
1332  setOpenError(false);
1333  return true;
1334 }
1335 
1337 {
1338  if (isOpen()) {
1339 #ifndef QT_NO_THREAD
1340  mysql_thread_end();
1341 #endif
1342  mysql_close(d->mysql);
1343  d->mysql = NULL;
1344  setOpen(false);
1345  setOpenError(false);
1346  }
1347 }
1348 
1350 {
1351  return new QMYSQLResult(this);
1352 }
1353 
1355 {
1356  QStringList tl;
1357 #if MYSQL_VERSION_ID >= 40100
1358  if( mysql_get_server_version(d->mysql) < 50000)
1359  {
1360 #endif
1361  if (!isOpen())
1362  return tl;
1363  if (!(type & QSql::Tables))
1364  return tl;
1365 
1366  MYSQL_RES* tableRes = mysql_list_tables(d->mysql, NULL);
1367  MYSQL_ROW row;
1368  int i = 0;
1369  while (tableRes) {
1370  mysql_data_seek(tableRes, i);
1371  row = mysql_fetch_row(tableRes);
1372  if (!row)
1373  break;
1374  tl.append(toUnicode(d->tc, row[0]));
1375  i++;
1376  }
1377  mysql_free_result(tableRes);
1378 #if MYSQL_VERSION_ID >= 40100
1379  } else {
1380  QSqlQuery q(createResult());
1381  if(type & QSql::Tables) {
1382  QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'BASE TABLE'");
1383  q.exec(sql);
1384 
1385  while(q.next())
1386  tl.append(q.value(0).toString());
1387  }
1388  if(type & QSql::Views) {
1389  QString sql = QLatin1String("select table_name from information_schema.tables where table_schema = '") + QLatin1String(d->mysql->db) + QLatin1String("' and table_type = 'VIEW'");
1390  q.exec(sql);
1391 
1392  while(q.next())
1393  tl.append(q.value(0).toString());
1394  }
1395  }
1396 #endif
1397  return tl;
1398 }
1399 
1401 {
1402  QSqlIndex idx;
1403  if (!isOpen())
1404  return idx;
1405 
1406  QSqlQuery i(createResult());
1407  QString stmt(QLatin1String("show index from %1;"));
1408  QSqlRecord fil = record(tablename);
1409  i.exec(stmt.arg(tablename));
1410  while (i.isActive() && i.next()) {
1411  if (i.value(2).toString() == QLatin1String("PRIMARY")) {
1412  idx.append(fil.field(i.value(4).toString()));
1413  idx.setCursorName(i.value(0).toString());
1414  idx.setName(i.value(2).toString());
1415  }
1416  }
1417 
1418  return idx;
1419 }
1420 
1421 QSqlRecord QMYSQLDriver::record(const QString& tablename) const
1422 {
1423  QString table=tablename;
1425  table = stripDelimiters(table, QSqlDriver::TableName);
1426 
1427  QSqlRecord info;
1428  if (!isOpen())
1429  return info;
1430  MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
1431  if (!r) {
1432  return info;
1433  }
1434  MYSQL_FIELD* field;
1435 
1436  while ((field = mysql_fetch_field(r)))
1437  info.append(qToField(field, d->tc));
1438  mysql_free_result(r);
1439  return info;
1440 }
1441 
1443 {
1444  return QVariant::fromValue(d->mysql);
1445 }
1446 
1448 {
1449 #ifndef CLIENT_TRANSACTIONS
1450  return false;
1451 #endif
1452  if (!isOpen()) {
1453  qWarning("QMYSQLDriver::beginTransaction: Database not open");
1454  return false;
1455  }
1456  if (mysql_query(d->mysql, "BEGIN WORK")) {
1457  setLastError(qMakeError(tr("Unable to begin transaction"),
1459  return false;
1460  }
1461  return true;
1462 }
1463 
1465 {
1466 #ifndef CLIENT_TRANSACTIONS
1467  return false;
1468 #endif
1469  if (!isOpen()) {
1470  qWarning("QMYSQLDriver::commitTransaction: Database not open");
1471  return false;
1472  }
1473  if (mysql_query(d->mysql, "COMMIT")) {
1474  setLastError(qMakeError(tr("Unable to commit transaction"),
1476  return false;
1477  }
1478  return true;
1479 }
1480 
1482 {
1483 #ifndef CLIENT_TRANSACTIONS
1484  return false;
1485 #endif
1486  if (!isOpen()) {
1487  qWarning("QMYSQLDriver::rollbackTransaction: Database not open");
1488  return false;
1489  }
1490  if (mysql_query(d->mysql, "ROLLBACK")) {
1491  setLastError(qMakeError(tr("Unable to rollback transaction"),
1493  return false;
1494  }
1495  return true;
1496 }
1497 
1498 QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
1499 {
1500  QString r;
1501  if (field.isNull()) {
1502  r = QLatin1String("NULL");
1503  } else {
1504  switch(field.type()) {
1505  case QVariant::String:
1506  // Escape '\' characters
1507  r = QSqlDriver::formatValue(field, trimStrings);
1508  r.replace(QLatin1String("\\"), QLatin1String("\\\\"));
1509  break;
1510  case QVariant::ByteArray:
1511  if (isOpen()) {
1512  const QByteArray ba = field.value().toByteArray();
1513  // buffer has to be at least length*2+1 bytes
1514  char* buffer = new char[ba.size() * 2 + 1];
1515  int escapedSize = int(mysql_real_escape_string(d->mysql, buffer,
1516  ba.data(), ba.size()));
1517  r.reserve(escapedSize + 3);
1518  r.append(QLatin1Char('\'')).append(toUnicode(d->tc, buffer)).append(QLatin1Char('\''));
1519  delete[] buffer;
1520  break;
1521  } else {
1522  qWarning("QMYSQLDriver::formatValue: Database not open");
1523  }
1524  // fall through
1525  default:
1526  r = QSqlDriver::formatValue(field, trimStrings);
1527  }
1528  }
1529  return r;
1530 }
1531 
1533 {
1534  QString res = identifier;
1535  if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('`')) && !identifier.endsWith(QLatin1Char('`')) ) {
1536  res.prepend(QLatin1Char('`')).append(QLatin1Char('`'));
1537  res.replace(QLatin1Char('.'), QLatin1String("`.`"));
1538  }
1539  return res;
1540 }
1541 
1543 {
1544  Q_UNUSED(type);
1545  return identifier.size() > 2
1546  && identifier.startsWith(QLatin1Char('`')) //left delimited
1547  && identifier.endsWith(QLatin1Char('`')); //right delimited
1548 }
1549 
1551 
1552 #include "qsql_mysql.moc"
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
The QSqlError class provides SQL database error information.
Definition: qsqlerror.h:53
The QSqlIndex class provides functions to manipulate and describe database indexes.
Definition: qsqlindex.h:55
static QTextCodec * codecForLocale()
Returns a pointer to the codec most suitable for this locale.
QSqlResult * createResult() const
Creates an empty SQL result on the database.
double d
Definition: qnumeric_p.h:62
static QVariant qTimeFromString(const QString &val)
Definition: qsql_mysql.cpp:137
const QSqlDriver * driver() const
Returns the driver associated with the result.
Definition: qsqlresult.cpp:389
qlonglong toLongLong(bool *ok=0, int base=10) const
Returns the string converted to a long long using base base, which is 10 by default and must be betwe...
Definition: qstring.cpp:5943
bool isNull(int field)
Returns true if the field at position index in the current row is null; otherwise returns false...
Definition: qsql_mysql.cpp:678
bool commitTransaction()
This function is called to commit a transaction.
int type
Definition: qmetatype.cpp:239
static void setOptionFlag(uint &optionFlags, const QString &opt)
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
Definition: qsqlresult.cpp:340
static mach_timebase_info_data_t info
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QVariant qVariantFromValue(const T &)
Definition: qvariant.h:451
virtual void setOpen(bool o)
This function sets the open state of the database to open.
Definition: qsqldriver.cpp:283
bool isForwardOnly() const
Returns true if you can only scroll forward through the result set; otherwise returns false...
Definition: qsqlresult.cpp:582
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
qulonglong toULongLong(bool *ok=0, int base=10) const
Returns the string converted to an unsigned long long using base base, which is 10 by default and mus...
Definition: qstring.cpp:5984
DriverFeature
This enum contains a list of features a driver might support.
Definition: qsqldriver.h:75
QMYSQLDriver(QObject *parent=0)
static int qMySqlConnectionCount
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
MYSQL_RES * result
Definition: qsql_mysql.cpp:180
bool isNull() const
Returns true if this is a NULL variant, false otherwise.
Definition: qvariant.cpp:3102
QTextCodec * tc
Definition: qsql_mysql.cpp:90
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
Definition: qsqldriver.cpp:297
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
Definition: qsqlindex.cpp:129
QVariant value() const
Returns the value of the field as a QVariant.
Definition: qsqlfield.h:71
QString & replace(int i, int len, QChar after)
Definition: qstring.cpp:2005
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
QString & prepend(QChar c)
Definition: qstring.h:261
#define SLOT(a)
Definition: qobjectdefs.h:226
int month() const
Returns the number corresponding to the month of this date, using the following convention: ...
Definition: qdatetime.cpp:382
bool reset(const QString &query)
Sets the result to use the SQL statement query for subsequent data retrieval.
Definition: qsql_mysql.cpp:686
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition: qsqlquery.h:63
int size()
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
Definition: qsql_mysql.cpp:723
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
bool fetchFirst()
Positions the result to the first record (row 0) in the result.
Definition: qsql_mysql.cpp:579
static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, const QMYSQLDriverPrivate *p)
Definition: qsql_mysql.cpp:231
void setPrecision(int precision)
Sets the field&#39;s precision.
Definition: qsqlfield.cpp:265
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
void cleanup()
Definition: qsql_mysql.cpp:429
int day() const
Returns the day of the month (1 to 31) of this date.
Definition: qdatetime.cpp:395
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
The QDate class provides date functions.
Definition: qdatetime.h:55
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
int msec() const
Returns the millisecond part (0 to 999) of the time.
Definition: qdatetime.cpp:1611
virtual bool isOpen() const
Returns true if the database connection is open; otherwise returns false.
Definition: qsqldriver.cpp:182
The QSqlRecord class encapsulates a database record.
Definition: qsqlrecord.h:58
#define Q_SLOTS
Definition: qobjectdefs.h:71
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition: qsqldriver.h:68
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isActive() const
Returns true if the query is active.
Definition: qsqlquery.cpp:785
int at() const
Returns the current (zero-based) row position of the result.
Definition: qsqlresult.cpp:306
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
static QSqlField qToField(MYSQL_FIELD *field, QTextCodec *tc)
Definition: qsql_mysql.cpp:292
friend class QMYSQLResultPrivate
Definition: qsql_mysql.h:72
QVariant handle() const
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
Definition: qsql_mysql.cpp:419
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has type() ByteArray or String (converted using QS...
Definition: qvariant.cpp:2383
QString escapeIdentifier(const QString &identifier, IdentifierType type) const
Returns the identifier escaped according to the database rules.
virtual void setAt(int at)
This function is provided for derived classes to set the internal (zero-based) row position to index...
Definition: qsqlresult.cpp:352
QString formatValue(const QSqlField &field, bool trimStrings) const
Returns a string representation of the field value for the database.
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
virtual void setLastError(const QSqlError &e)
This function is provided for derived classes to set the last error to error.
Definition: qsqlresult.cpp:417
bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const
Returns whether identifier is escaped according to the database rules.
Definition: qsqldriver.cpp:429
int toInt(bool *ok=0) const
Returns the variant as an int if the variant has type() Int , Bool , ByteArray , Char ...
Definition: qvariant.cpp:2625
int numRowsAffected()
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
Definition: qsql_mysql.cpp:738
ErrorType
This enum type describes the context in which the error occurred, e.
Definition: qsqlerror.h:56
void reserve(int size)
Attempts to allocate memory for at least size characters.
Definition: qstring.h:881
static QVariant qDateTimeFromString(QString &val)
Definition: qsql_mysql.cpp:149
#define SIGNAL(a)
Definition: qobjectdefs.h:227
static QDateTime fromString(const QString &s, Qt::DateFormat f=Qt::TextDate)
Returns the QDateTime represented by the string, using the format given, or an invalid datetime if th...
Definition: qdatetime.cpp:3487
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
bool beginTransaction()
This function is called to begin a transaction.
The QTime class provides clock time functions.
Definition: qdatetime.h:148
const QMYSQLResult * q
Definition: qsql_mysql.cpp:182
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
qlonglong toLongLong(bool *ok=0) const
Returns the variant as a long long int if the variant has type() LongLong , Bool , ByteArray , Char , Double , Int , String , UInt , or ULongLong ; otherwise returns 0.
Definition: qvariant.cpp:2659
QByteArray fromUnicode(const QString &uc) const
Converts str from Unicode to the encoding of this codec, and returns the result in a QByteArray...
virtual void setSelect(bool s)
This function is provided for derived classes to indicate whether or not the current statement is a S...
Definition: qsqlresult.cpp:367
QMYSQLResultPrivate * d
Definition: qsql_mysql.h:99
const QMYSQLDriver * driver
Definition: qsql_mysql.cpp:179
unsigned __int64 quint64
Definition: qglobal.h:943
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
int size() const
Returns the number of characters in this string.
Definition: qstring.h:102
QVariant lastInsertId() const
Returns the object ID of the most recent inserted row if the database supports it.
Definition: qsql_mysql.cpp:743
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
friend class QMYSQLResult
Definition: qsql_mysql.h:105
QVariant handle() const
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
bool hasFeature(DriverFeature f) const
Returns true if the driver supports feature feature; otherwise returns false.
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
void setLength(int fieldLength)
Sets the field&#39;s length to fieldLength.
Definition: qsqlfield.cpp:254
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
QSqlRecord record(const QString &tablename) const
Returns a QSqlRecord populated with the names of the fields in table tableName.
Q_CORE_EXPORT void qWarning(const char *,...)
int second() const
Returns the second part (0 to 59) of the time.
Definition: qdatetime.cpp:1600
bool fetchLast()
Positions the result to the last record (last row) in the result.
Definition: qsql_mysql.cpp:552
void setName(const QString &name)
Sets the name of the index to name.
Definition: qsqlindex.cpp:110
unsigned int uint
Definition: qglobal.h:996
TableType
Definition: qsql.h:74
static QTextCodec * codec(MYSQL *mysql)
Definition: qsql_mysql.cpp:220
Type
This enum type defines the types of variable that a QVariant can contain.
Definition: qvariant.h:95
void setCursorName(const QString &cursorName)
Sets the name of the cursor that the index is associated with to cursorName.
Definition: qsqlindex.cpp:266
static bool qMySqlInitHandledByUser
QVector< QMyField > fields
Definition: qsql_mysql.cpp:203
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
__int64 qint64
Definition: qglobal.h:942
int minute() const
Returns the minute part (0 to 59) of the time.
Definition: qdatetime.cpp:1589
unsigned long ulong
Definition: qglobal.h:997
quint16 values[128]
virtual bool exec()
Executes the query, returning true if successful; otherwise returns false.
Definition: qsqlresult.cpp:675
virtual bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
Definition: qsqlresult.cpp:641
QVariant::Type type() const
Returns the field&#39;s type as stored in the database.
Definition: qsqlfield.cpp:394
static QVariant fromValue(const T &value)
Returns a QVariant containing a copy of value.
Definition: qvariant.h:336
bool fetch(int i)
Positions the result to an arbitrary (zero-based) row index.
Definition: qsql_mysql.cpp:479
QByteArray toLocal8Bit() const Q_REQUIRED_RESULT
Returns the local 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4049
QSqlField field(int i) const
Returns the field at position index.
Definition: qsqlrecord.cpp:289
virtual void virtual_hook(int id, void *data)
Definition: qsqlresult.cpp:962
static QVariant qDateFromString(const QString &val)
Definition: qsql_mysql.cpp:125
#define Q_OBJECT
Definition: qobjectdefs.h:157
#define Q_DECLARE_METATYPE(TYPE)
This macro makes the type Type known to QMetaType as long as it provides a public default constructor...
Definition: qmetatype.h:265
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
QSqlIndex primaryIndex(const QString &tablename) const
Returns the primary index for table tableName.
bool fetchNext()
Positions the result to the next available record (row) in the result.
Definition: qsql_mysql.cpp:523
QVariant data(int field)
Returns the data for field index in the current row as a QVariant.
Definition: qsql_mysql.cpp:589
static QTime fromString(const QString &s, Qt::DateFormat f=Qt::TextDate)
Returns the time represented in the string as a QTime using the format given, or an invalid time if t...
Definition: qdatetime.cpp:1928
static QString toUnicode(QTextCodec *tc, const char *str)
Definition: qsql_mysql.cpp:95
int length() const
Same as size().
Definition: qbytearray.h:356
virtual QByteArray name() const =0
QTextCodec subclasses must reimplement this function.
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition: qstring.h:505
QString toUnicode(const QByteArray &) const
Converts a from the encoding of this codec to Unicode, and returns the result in a QString...
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const
bool nextResult()
Definition: qsql_mysql.cpp:787
QDate toDate() const
Returns the variant as a QDate if the variant has type() Date , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2311
void setRequired(bool required)
Sets the required status of this field to Required if required is true; otherwise sets it to Optional...
Definition: qsqlfield.h:84
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
QString & append(QChar c)
Definition: qstring.cpp:1777
static void qLibraryInit()
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
static void qLibraryEnd()
QString simplified() const Q_REQUIRED_RESULT
Returns a string that has whitespace removed from the start and the end, and that has each sequence o...
Definition: qstring.cpp:4415
QMYSQLResultPrivate(const QMYSQLDriver *dp, const QMYSQLResult *d)
Definition: qsql_mysql.cpp:169
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
Type type() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1901
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
bool isNull() const
Returns true if the field&#39;s value is NULL; otherwise returns false.
Definition: qsqlfield.cpp:428
const void * constData() const
Definition: qvariant.cpp:3065
virtual QString formatValue(const QSqlField &field, bool trimStrings=false) const
Returns a string representation of the field value for the database.
Definition: qsqldriver.cpp:597
static QDate fromString(const QString &s, Qt::DateFormat f=Qt::TextDate)
Returns the QDate represented by the string, using the format given, or an invalid date if the string...
Definition: qdatetime.cpp:1203
#define QT_NO_TEXTCODEC
double toDouble(bool *ok=0) const
Returns the string converted to a double value.
Definition: qstring.cpp:6227
uint toUInt(bool *ok=0, int base=10) const
Returns the string converted to an unsigned int using base base, which is 10 by default and must be b...
Definition: qstring.cpp:6120
if(void) toggleToolbarShown
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
Definition: qsqlrecord.cpp:312
static QTextCodec * codecForName(const QByteArray &name)
Searches all installed QTextCodec objects and returns the one which best matches name; the match is c...
void virtual_hook(int id, void *data)
Definition: qsql_mysql.cpp:839
bool isSelect() const
Returns true if the current result is from a SELECT statement; otherwise returns false.
Definition: qsqlresult.cpp:379
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
Definition: qsql_mysql.cpp:762
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active...
Definition: qsqlresult.cpp:402
#define Q_CLIENT_MULTI_STATEMENTS
Definition: qsql_mysql.cpp:74
QMYSQLResult(const QMYSQLDriver *db)
Definition: qsql_mysql.cpp:407
static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags)
Definition: qsql_mysql.cpp:241
int year() const
Returns the year of this date.
Definition: qdatetime.cpp:353
QStringList split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const Q_REQUIRED_RESULT
Splits the string into substrings wherever sep occurs, and returns the list of those strings...
Definition: qstring.cpp:6526
static QByteArray fromUnicode(QTextCodec *tc, const QString &str)
Definition: qsql_mysql.cpp:115
QTime toTime() const
Returns the variant as a QTime if the variant has type() Time , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2330
The QSqlField class manipulates the fields in SQL database tables and views.
Definition: qsqlfield.h:56
bool exec(const QString &query)
Executes the SQL in query.
Definition: qsqlquery.cpp:355
virtual void setLastError(const QSqlError &e)
This function is used to set the value of the last error, error, that occurred on the database...
Definition: qsqldriver.cpp:350
void setAutoValue(bool autoVal)
Marks the field as an auto-generated value if autoVal is true.
Definition: qsqlfield.cpp:575
The QTextCodec class provides conversions between text encodings.
Definition: qtextcodec.h:62
QString stripDelimiters(const QString &identifier, IdentifierType type) const
Returns the identifier with the leading and trailing delimiters removed, identifier can either be a t...
Definition: qsqldriver.cpp:455
QVector< QVariant > & boundValues() const
Returns a vector of the result&#39;s bound values for the current record (row).
Definition: qsqlresult.cpp:859
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
QVariant value(int i) const
Returns the value of field index in the current record.
Definition: qsqlquery.cpp:403
QString & insert(int i, QChar c)
Definition: qstring.cpp:1671
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
bool next()
Retrieves the next record in the result, if available, and positions the query on the retrieved recor...
Definition: qsqlquery.cpp:594
bool open(const QString &db, const QString &user, const QString &password, const QString &host, int port, const QString &connOpts)
Derived classes must reimplement this pure virtual function to open a database connection on database...
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases...
Definition: qsqlresult.h:63
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
bool rollbackTransaction()
This function is called to rollback a transaction.
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
IdentifierType
This enum contains a list of SQL identifier types.
Definition: qsqldriver.h:83
void close()
Derived classes must reimplement this pure virtual function in order to close the database connection...
QStringList tables(QSql::TableType) const
Returns a list of the names of the tables in the database.
int hour() const
Returns the hour part (0 to 23) of the time.
Definition: qdatetime.cpp:1578
void setSqlType(int type)
Definition: qsqlfield.cpp:285
QMYSQLDriverPrivate * d
Definition: qsql_mysql.h:136