Qt 4.8
qsql_tds.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 <qglobal.h>
43 #ifdef Q_OS_WIN32 // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase.
44 // Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
45 #define _WINSCARD_H_
46 #include <windows.h>
47 #else
48 #define Q_USE_SYBASE
49 #endif
50 
51 #include "qsql_tds.h"
52 
53 #include <qvariant.h>
54 #include <qdatetime.h>
55 #include <qhash.h>
56 #include <qregexp.h>
57 #include <qsqlerror.h>
58 #include <qsqlfield.h>
59 #include <qsqlindex.h>
60 #include <qsqlquery.h>
61 #include <qstringlist.h>
62 #include <qvector.h>
63 
64 #include <stdlib.h>
65 
67 
68 #ifdef DBNTWIN32
69 #define QMSGHANDLE DBMSGHANDLE_PROC
70 #define QERRHANDLE DBERRHANDLE_PROC
71 #define QTDSCHAR SQLCHAR
72 #define QTDSDATETIME4 SQLDATETIM4
73 #define QTDSDATETIME SQLDATETIME
74 #define QTDSDATETIME_N SQLDATETIMN
75 #define QTDSDECIMAL SQLDECIMAL
76 #define QTDSFLT4 SQLFLT4
77 #define QTDSFLT8 SQLFLT8
78 #define QTDSFLT8_N SQLFLTN
79 #define QTDSINT1 SQLINT1
80 #define QTDSINT2 SQLINT2
81 #define QTDSINT4 SQLINT4
82 #define QTDSINT4_N SQLINTN
83 #define QTDSMONEY4 SQLMONEY4
84 #define QTDSMONEY SQLMONEY
85 #define QTDSMONEY_N SQLMONEYN
86 #define QTDSNUMERIC SQLNUMERIC
87 #define QTDSTEXT SQLTEXT
88 #define QTDSVARCHAR SQLVARCHAR
89 #define QTDSBIT SQLBIT
90 #define QTDSBINARY SQLBINARY
91 #define QTDSVARBINARY SQLVARBINARY
92 #define QTDSIMAGE SQLIMAGE
93 #else
94 #define QMSGHANDLE MHANDLEFUNC
95 #define QERRHANDLE EHANDLEFUNC
96 #define QTDSCHAR SYBCHAR
97 #define QTDSDATETIME4 SYBDATETIME4
98 #define QTDSDATETIME SYBDATETIME
99 #define QTDSDATETIME_N SYBDATETIMN
100 #define QTDSDECIMAL SYBDECIMAL
101 #define QTDSFLT8 SYBFLT8
102 #define QTDSFLT8_N SYBFLTN
103 #define QTDSFLT4 SYBREAL
104 #define QTDSINT1 SYBINT1
105 #define QTDSINT2 SYBINT2
106 #define QTDSINT4 SYBINT4
107 #define QTDSINT4_N SYBINTN
108 #define QTDSMONEY4 SYBMONEY4
109 #define QTDSMONEY SYBMONEY
110 #define QTDSMONEY_N SYBMONEYN
111 #define QTDSNUMERIC SYBNUMERIC
112 #define QTDSTEXT SYBTEXT
113 #define QTDSVARCHAR SYBVARCHAR
114 #define QTDSBIT SYBBIT
115 #define QTDSBINARY SYBBINARY
116 #define QTDSVARBINARY SYBVARBINARY
117 #define QTDSIMAGE SYBIMAGE
118 // magic numbers not defined anywhere in Sybase headers
119 #define QTDSDECIMAL_2 55
120 #define QTDSNUMERIC_2 63
121 #endif //DBNTWIN32
122 
123 #define TDS_CURSOR_SIZE 50
124 
125 // workaround for FreeTDS
126 #ifndef CS_PUBLIC
127 #define CS_PUBLIC
128 #endif
129 
131 {
132  return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo);
133 }
134 
136 {
137 public:
139  LOGINREC* login; // login information
143 };
144 
145 
147 {
148 public:
149  QTDSResultPrivate():login(0), dbproc(0) {}
150  LOGINREC* login; // login information
151  DBPROCESS* dbproc; // connection from app to server
153  void addErrorMsg(QString& errMsg) { errorMsgs.append(errMsg); }
154  QString getErrorMsgs() { return errorMsgs.join(QLatin1String("\n")); }
155  void clearErrorMsgs() { errorMsgs.clear(); }
158 
159 private:
161 };
162 
165 
166 extern "C" {
167 static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc,
168  DBINT msgno,
169  int msgstate,
170  int severity,
171  char* msgtext,
172  char* srvname,
173  char* /*procname*/,
174  int line)
175 {
176  QTDSResultPrivate* p = errs()->value(dbproc);
177 
178  if (!p) {
179 // ### umm... temporary disabled since this throws a lot of warnings...
180 // qWarning("QTDSDriver warning (%d): [%s] from server [%s]", msgstate, msgtext, srvname);
181  return INT_CANCEL;
182  }
183 
184  if (severity > 0) {
185  QString errMsg = QString::fromLatin1("%1 (Msg %2, Level %3, State %4, Server %5, Line %6)")
186  .arg(QString::fromAscii(msgtext))
187  .arg(msgno)
188  .arg(severity)
189  .arg(msgstate)
190  .arg(QString::fromAscii(srvname))
191  .arg(line);
192  p->addErrorMsg(errMsg);
193  if (severity > 10) {
194  // Severe messages are really errors in the sense of lastError
195  errMsg = p->getErrorMsgs();
196  p->lastError = qMakeError(errMsg, QSqlError::UnknownError, msgno);
197  p->clearErrorMsgs();
198  }
199  }
200 
201  return INT_CANCEL;
202 }
203 
204 static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
205  int /*severity*/,
206  int dberr,
207  int /*oserr*/,
208  char* dberrstr,
209  char* oserrstr)
210 {
211  QTDSResultPrivate* p = errs()->value(dbproc);
212  if (!p) {
213  qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
214  return INT_CANCEL;
215  }
216  /*
217  * If the process is dead or NULL and
218  * we are not in the middle of logging in...
219  */
220  if((dbproc == NULL || DBDEAD(dbproc))) {
221  qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
222  return INT_CANCEL;
223  }
224 
225 
226  QString errMsg = QString::fromLatin1("%1 %2\n").arg(QLatin1String(dberrstr)).arg(
227  QLatin1String(oserrstr));
228  errMsg += p->getErrorMsgs();
229  p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
230  p->clearErrorMsgs();
231 
232  return INT_CANCEL ;
233 }
234 
235 } //extern "C"
236 
237 
239 {
241  switch (type) {
242  case QTDSCHAR:
243  case QTDSTEXT:
244  case QTDSVARCHAR:
245  t = QVariant::String;
246  break;
247  case QTDSINT1:
248  case QTDSINT2:
249  case QTDSINT4:
250  case QTDSINT4_N:
251  case QTDSBIT:
252  t = QVariant::Int;
253  break;
254  case QTDSFLT4:
255  case QTDSFLT8:
256  case QTDSFLT8_N:
257  case QTDSMONEY4:
258  case QTDSMONEY:
259  case QTDSDECIMAL:
260  case QTDSNUMERIC:
261 #ifdef QTDSNUMERIC_2
262  case QTDSNUMERIC_2:
263 #endif
264 #ifdef QTDSDECIMAL_2
265  case QTDSDECIMAL_2:
266 #endif
267  case QTDSMONEY_N:
268  t = QVariant::Double;
269  break;
270  case QTDSDATETIME4:
271  case QTDSDATETIME:
272  case QTDSDATETIME_N:
273  t = QVariant::DateTime;
274  break;
275  case QTDSBINARY:
276  case QTDSVARBINARY:
277  case QTDSIMAGE:
279  break;
280  default:
281  t = QVariant::Invalid;
282  break;
283  }
284  return t;
285 }
286 
288 {
289  QVariant::Type type = qDecodeTDSType(dbcoltype(d->dbproc, i+1));
290  return type;
291 }
292 
293 
295  : QSqlCachedResult(db)
296 {
297  d = new QTDSResultPrivate();
298  d->login = db->d->login;
299 
300  d->dbproc = dbopen(d->login, const_cast<char*>(db->d->hostName.toLatin1().constData()));
301  if (!d->dbproc)
302  return;
303  if (dbuse(d->dbproc, const_cast<char*>(db->d->db.toLatin1().constData())) == FAIL)
304  return;
305 
306  // insert d in error handler dict
307  errs()->insert(d->dbproc, d);
308  dbcmd(d->dbproc, "set quoted_identifier on");
309  dbsqlexec(d->dbproc);
310 }
311 
313 {
314  cleanup();
315  if (d->dbproc)
316  dbclose(d->dbproc);
317  errs()->remove(d->dbproc);
318  delete d;
319 }
320 
322 {
323  d->clearErrorMsgs();
324  d->rec.clear();
325  for (int i = 0; i < d->buffer.size() / 2; ++i)
326  free(d->buffer.at(i * 2));
327  d->buffer.clear();
328  // "can" stands for "cancel"... very clever.
329  dbcanquery(d->dbproc);
330  dbfreebuf(d->dbproc);
331 
333 }
334 
336 {
337  return QVariant(qRegisterMetaType<DBPROCESS *>("DBPROCESS*"), &d->dbproc);
338 }
339 
340 static inline bool qIsNull(const void *ind)
341 {
342  return *reinterpret_cast<const DBINT *>(&ind) == -1;
343 }
344 
346 {
347  STATUS stat = dbnextrow(d->dbproc);
348  if (stat == NO_MORE_ROWS) {
350  return false;
351  }
352  if ((stat == FAIL) || (stat == BUF_FULL)) {
354  return false;
355  }
356 
357  if (index < 0)
358  return true;
359 
360  for (int i = 0; i < d->rec.count(); ++i) {
361  int idx = index + i;
362  switch (d->rec.field(i).type()) {
363  case QVariant::DateTime:
364  if (qIsNull(d->buffer.at(i * 2 + 1))) {
365  values[idx] = QVariant(QVariant::DateTime);
366  } else {
367  DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i * 2);
368  QDate date = QDate::fromString(QLatin1String("1900-01-01"), Qt::ISODate);
369  QTime time = QTime::fromString(QLatin1String("00:00:00"), Qt::ISODate);
370  values[idx] = QDateTime(date.addDays(bdt->dtdays), time.addMSecs(int(bdt->dttime / 0.3)));
371  }
372  break;
373  case QVariant::Int:
374  if (qIsNull(d->buffer.at(i * 2 + 1)))
375  values[idx] = QVariant(QVariant::Int);
376  else
377  values[idx] = *((int*)d->buffer.at(i * 2));
378  break;
379  case QVariant::Double:
380  case QVariant::String:
381  if (qIsNull(d->buffer.at(i * 2 + 1)))
382  values[idx] = QVariant(QVariant::String);
383  else
384  values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i * 2)).trimmed();
385  break;
386  case QVariant::ByteArray: {
387  if (qIsNull(d->buffer.at(i * 2 + 1)))
388  values[idx] = QVariant(QVariant::ByteArray);
389  else
390  values[idx] = QByteArray((const char*)d->buffer.at(i * 2));
391  break;
392  }
393  default:
394  // should never happen, and we already fired
395  // a warning while binding.
396  values[idx] = QVariant();
397  break;
398  }
399  }
400 
401  return true;
402 }
403 
404 bool QTDSResult::reset (const QString& query)
405 {
406  cleanup();
407  if (!driver() || !driver()-> isOpen() || driver()->isOpenError())
408  return false;
409  setActive(false);
411  if (dbcmd(d->dbproc, const_cast<char*>(query.toLocal8Bit().constData())) == FAIL) {
413  return false;
414  }
415 
416  if (dbsqlexec(d->dbproc) == FAIL) {
418  dbfreebuf(d->dbproc);
419  return false;
420  }
421  if (dbresults(d->dbproc) != SUCCEED) {
423  dbfreebuf(d->dbproc);
424  return false;
425  }
426 
427  setSelect((DBCMDROW(d->dbproc) == SUCCEED)); // decide whether or not we are dealing with a SELECT query
428  int numCols = dbnumcols(d->dbproc);
429  if (numCols > 0) {
430  d->buffer.resize(numCols * 2);
431  init(numCols);
432  }
433  for (int i = 0; i < numCols; ++i) {
434  int dbType = dbcoltype(d->dbproc, i+1);
435  QVariant::Type vType = qDecodeTDSType(dbType);
436  QSqlField f(QString::fromAscii(dbcolname(d->dbproc, i+1)), vType);
437  f.setSqlType(dbType);
438  f.setLength(dbcollen(d->dbproc, i+1));
439  d->rec.append(f);
440 
441  RETCODE ret = -1;
442  void* p = 0;
443  switch (vType) {
444  case QVariant::Int:
445  p = malloc(4);
446  ret = dbbind(d->dbproc, i+1, INTBIND, (DBINT) 4, (unsigned char *)p);
447  break;
448  case QVariant::Double:
449  // use string binding to prevent loss of precision
450  p = malloc(50);
451  ret = dbbind(d->dbproc, i+1, STRINGBIND, 50, (unsigned char *)p);
452  break;
453  case QVariant::String:
454  p = malloc(dbcollen(d->dbproc, i+1) + 1);
455  ret = dbbind(d->dbproc, i+1, STRINGBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
456  break;
457  case QVariant::DateTime:
458  p = malloc(8);
459  ret = dbbind(d->dbproc, i+1, DATETIMEBIND, (DBINT) 8, (unsigned char *)p);
460  break;
461  case QVariant::ByteArray:
462  p = malloc(dbcollen(d->dbproc, i+1) + 1);
463  ret = dbbind(d->dbproc, i+1, BINARYBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
464  break;
465  default: //don't bind the field since we do not support it
466  qWarning("QTDSResult::reset: Unsupported type for field \"%s\"", dbcolname(d->dbproc, i+1));
467  break;
468  }
469  if (ret == SUCCEED) {
470  d->buffer[i * 2] = p;
471  ret = dbnullbind(d->dbproc, i+1, (DBINT*)(&d->buffer[i * 2 + 1]));
472  } else {
473  d->buffer[i * 2] = 0;
474  d->buffer[i * 2 + 1] = 0;
475  free(p);
476  }
477  if ((ret != SUCCEED) && (ret != -1)) {
479  return false;
480  }
481  }
482 
483  setActive(true);
484  return true;
485 }
486 
488 {
489  return -1;
490 }
491 
493 {
494 #ifdef DBNTWIN32
495  if (dbiscount(d->dbproc)) {
496  return DBCOUNT(d->dbproc);
497  }
498  return -1;
499 #else
500  return DBCOUNT(d->dbproc);
501 #endif
502 }
503 
505 {
506  return d->rec;
507 }
508 
510 
512  : QSqlDriver(parent)
513 {
514  init();
515 }
516 
517 QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent)
518  : QSqlDriver(parent)
519 {
520  init();
521  d->login = rec;
522  d->hostName = host;
523  d->db = db;
524  if (rec) {
525  setOpen(true);
526  setOpenError(false);
527  }
528 }
529 
531 {
532  return QVariant(qRegisterMetaType<LOGINREC *>("LOGINREC*"), &d->login);
533 }
534 
536 {
537  d = new QTDSDriverPrivate();
538  d->initialized = (dbinit() == SUCCEED);
539  // the following two code-lines will fail compilation on some FreeTDS versions
540  // just comment them out if you have FreeTDS (you won't get any errors and warnings then)
541  dberrhandle((QERRHANDLE)qTdsErrHandler);
542  dbmsghandle((QMSGHANDLE)qTdsMsgHandler);
543 }
544 
546 {
547  dberrhandle(0);
548  dbmsghandle(0);
549  // dbexit also calls dbclose if necessary
550  dbexit();
551  delete d;
552 }
553 
555 {
556  switch (f) {
557  case Transactions:
558  case QuerySize:
559  case Unicode:
560  case SimpleLocking:
561  case EventNotifications:
562  case MultipleResultSets:
563  return false;
564  case BLOB:
565  return true;
566  default:
567  return false;
568  }
569 }
570 
571 bool QTDSDriver::open(const QString & db,
572  const QString & user,
573  const QString & password,
574  const QString & host,
575  int /*port*/,
576  const QString& /*connOpts*/)
577 {
578  if (isOpen())
579  close();
580  if (!d->initialized) {
581  setOpenError(true);
582  return false;
583  }
584  d->login = dblogin();
585  if (!d->login) {
586  setOpenError(true);
587  return false;
588  }
589  DBSETLPWD(d->login, const_cast<char*>(password.toLocal8Bit().constData()));
590  DBSETLUSER(d->login, const_cast<char*>(user.toLocal8Bit().constData()));
591 
592  // Now, try to open and use the database. If this fails, return false.
593  DBPROCESS* dbproc;
594 
595  dbproc = dbopen(d->login, const_cast<char*>(host.toLatin1().constData()));
596  if (!dbproc) {
597  setLastError(qMakeError(tr("Unable to open connection"), QSqlError::ConnectionError, -1));
598  setOpenError(true);
599  return false;
600  }
601  if (dbuse(dbproc, const_cast<char*>(db.toLatin1().constData())) == FAIL) {
602  setLastError(qMakeError(tr("Unable to use database"), QSqlError::ConnectionError, -1));
603  setOpenError(true);
604  return false;
605  }
606  dbclose( dbproc );
607 
608  setOpen(true);
609  setOpenError(false);
610  d->hostName = host;
611  d->db = db;
612  return true;
613 }
614 
616 {
617  if (isOpen()) {
618 #ifdef Q_USE_SYBASE
619  dbloginfree(d->login);
620 #else
621  dbfreelogin(d->login);
622 #endif
623  d->login = 0;
624  setOpen(false);
625  setOpenError(false);
626  }
627 }
628 
630 {
631  return new QTDSResult(this);
632 }
633 
635 {
636  return false;
637 /*
638  if (!isOpen()) {
639  qWarning("QTDSDriver::beginTransaction: Database not open");
640  return false;
641  }
642  if (dbcmd(d->dbproc, "BEGIN TRANSACTION") == FAIL) {
643  setLastError(d->lastError);
644  dbfreebuf(d->dbproc);
645  return false;
646  }
647  if (dbsqlexec(d->dbproc) == FAIL) {
648  setLastError(d->lastError);
649  dbfreebuf(d->dbproc);
650  return false;
651  }
652  while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
653  dbfreebuf(d->dbproc);
654  inTransaction = true;
655  return true;
656 */
657 }
658 
660 {
661  return false;
662 /*
663  if (!isOpen()) {
664  qWarning("QTDSDriver::commitTransaction: Database not open");
665  return false;
666  }
667  if (dbcmd(d->dbproc, "COMMIT TRANSACTION") == FAIL) {
668  setLastError(d->lastError);
669  dbfreebuf(d->dbproc);
670  return false;
671  }
672  if (dbsqlexec(d->dbproc) == FAIL) {
673  setLastError(d->lastError);
674  dbfreebuf(d->dbproc);
675  return false;
676  }
677  while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
678  dbfreebuf(d->dbproc);
679  inTransaction = false;
680  return true;
681 */
682 }
683 
685 {
686  return false;
687 /*
688  if (!isOpen()) {
689  qWarning("QTDSDriver::rollbackTransaction: Database not open");
690  return false;
691  }
692  if (dbcmd(d->dbproc, "ROLLBACK TRANSACTION") == FAIL) {
693  setLastError(d->lastError);
694  dbfreebuf(d->dbproc);
695  return false;
696  }
697  if (dbsqlexec(d->dbproc) == FAIL) {
698  setLastError(d->lastError);
699  dbfreebuf(d->dbproc);
700  return false;
701  }
702  while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
703  dbfreebuf(d->dbproc);
704  inTransaction = false;
705  return true;
706 */
707 }
708 
709 QSqlRecord QTDSDriver::record(const QString& tablename) const
710 {
712  if (!isOpen())
713  return info;
714  QSqlQuery t(createResult());
715  t.setForwardOnly(true);
716 
717  QString table = tablename;
719  table = stripDelimiters(table, QSqlDriver::TableName);
720 
721  QString stmt (QLatin1String("select name, type, length, prec from syscolumns "
722  "where id = (select id from sysobjects where name = '%1')"));
723  t.exec(stmt.arg(table));
724  while (t.next()) {
726  f.setLength(t.value(2).toInt());
727  f.setPrecision(t.value(3).toInt());
728  f.setSqlType(t.value(1).toInt());
729  info.append(f);
730  }
731  return info;
732 }
733 
735 {
736  QStringList list;
737 
738  if (!isOpen())
739  return list;
740 
741  QStringList typeFilter;
742 
743  if (type & QSql::Tables)
744  typeFilter += QLatin1String("type='U'");
745  if (type & QSql::SystemTables)
746  typeFilter += QLatin1String("type='S'");
747  if (type & QSql::Views)
748  typeFilter += QLatin1String("type='V'");
749 
750  if (typeFilter.isEmpty())
751  return list;
752 
753  QSqlQuery t(createResult());
754  t.setForwardOnly(true);
755  t.exec(QLatin1String("select name from sysobjects where ") + typeFilter.join(QLatin1String(" or ")));
756  while (t.next())
757  list.append(t.value(0).toString().simplified());
758 
759  return list;
760 }
761 
763  bool trim) const
764 {
765  QString r;
766  if (field.isNull())
767  r = QLatin1String("NULL");
768  else if (field.type() == QVariant::DateTime) {
769  if (field.value().toDateTime().isValid()){
770  r = field.value().toDateTime().toString(QLatin1String("yyyyMMdd hh:mm:ss"));
771  r.prepend(QLatin1String("'"));
772  r.append(QLatin1String("'"));
773  } else
774  r = QLatin1String("NULL");
775  } else if (field.type() == QVariant::ByteArray) {
776  QByteArray ba = field.value().toByteArray();
777  QString res;
778  static const char hexchars[] = "0123456789abcdef";
779  for (int i = 0; i < ba.size(); ++i) {
780  uchar s = (uchar) ba[i];
781  res += QLatin1Char(hexchars[s >> 4]);
782  res += QLatin1Char(hexchars[s & 0x0f]);
783  }
784  r = QLatin1String("0x") + res;
785  } else {
786  r = QSqlDriver::formatValue(field, trim);
787  }
788  return r;
789 }
790 
792 {
793  QSqlRecord rec = record(tablename);
794 
795  QString table = tablename;
797  table = stripDelimiters(table, QSqlDriver::TableName);
798 
799  QSqlIndex idx(table);
800  if ((!isOpen()) || (table.isEmpty()))
801  return QSqlIndex();
802 
803  QSqlQuery t(createResult());
804  t.setForwardOnly(true);
805  t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(table));
806  if (t.next()) {
807  QStringList fNames = t.value(2).toString().simplified().split(QLatin1Char(','));
808  QRegExp regx(QLatin1String("\\s*(\\S+)(?:\\s+(DESC|desc))?\\s*"));
809  for(QStringList::Iterator it = fNames.begin(); it != fNames.end(); ++it) {
810  regx.indexIn(*it);
811  QSqlField f(regx.cap(1), rec.field(regx.cap(1)).type());
812  if (regx.cap(2).toLower() == QLatin1String("desc")) {
813  idx.append(f, true);
814  } else {
815  idx.append(f, false);
816  }
817  }
818  idx.setName(t.value(0).toString().simplified());
819  }
820  return idx;
821 }
822 
824 {
825  QString res = identifier;
826  if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
827  res.replace(QLatin1Char('"'), QLatin1String("\"\""));
828  res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
829  res.replace(QLatin1Char('.'), QLatin1String("\".\""));
830  }
831  return res;
832 }
833 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
LOGINREC * login
Definition: qsql_tds.cpp:139
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
QSqlError lastError
Definition: qsql_tds.cpp:152
double d
Definition: qnumeric_p.h:62
#define QTDSVARBINARY
Definition: qsql_tds.cpp:116
const QSqlDriver * driver() const
Returns the driver associated with the result.
Definition: qsqlresult.cpp:389
static QString fromLocal8Bit(const char *, int size=-1)
Returns a QString initialized with the first size characters of the 8-bit string str.
Definition: qstring.cpp:4245
int type
Definition: qmetatype.cpp:239
static mach_timebase_info_data_t info
#define QTDSDECIMAL_2
Definition: qsql_tds.cpp:119
QString cap(int nth=0) const
Returns the text captured by the nth subexpression.
Definition: qregexp.cpp:4310
bool commitTransaction()
This function is called to commit a transaction.
Definition: qsql_tds.cpp:659
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
virtual void setOpen(bool o)
This function sets the open state of the database to open.
Definition: qsqldriver.cpp:283
static QString fromAscii(const char *, int size=-1)
Returns a QString initialized with the first size characters from the string str. ...
Definition: qstring.cpp:4276
QVariant::Type qDecodeTDSType(int type)
Definition: qsql_tds.cpp:238
QTDSDriverPrivate * d
Definition: qsql_tds.h:130
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
DriverFeature
This enum contains a list of features a driver might support.
Definition: qsqldriver.h:75
bool beginTransaction()
This function is called to begin a transaction.
Definition: qsql_tds.cpp:634
#define it(className, varName)
virtual void setOpenError(bool e)
This function sets the open error state of the database to error.
Definition: qsqldriver.cpp:297
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
#define QMSGHANDLE
Definition: qsql_tds.cpp:94
QString & prepend(QChar c)
Definition: qstring.h:261
#define QTDSINT4_N
Definition: qsql_tds.cpp:107
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition: qsqlquery.h:63
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has type() DateTime , Date , or String ; otherwise ...
Definition: qvariant.cpp:2349
#define QTDSFLT8_N
Definition: qsql_tds.cpp:102
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
bool isValid() const
Returns true if both the date and the time are valid; otherwise returns false.
Definition: qdatetime.cpp:2346
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
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
The QSqlDriver class is an abstract base class for accessing specific SQL databases.
Definition: qsqldriver.h:68
#define QTDSCHAR
Definition: qsql_tds.cpp:96
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
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
QStringList tables(QSql::TableType) const
Returns a list of the names of the tables in the database.
Definition: qsql_tds.cpp:734
bool hasFeature(DriverFeature f) const
Returns true if the driver supports feature feature; otherwise returns false.
Definition: qsql_tds.cpp:554
QString getErrorMsgs()
Definition: qsql_tds.cpp:154
QString toString(Qt::DateFormat f=Qt::TextDate) const
Returns the datetime as a string in the format given.
Definition: qdatetime.cpp:2628
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has type() ByteArray or String (converted using QS...
Definition: qvariant.cpp:2383
iterator Iterator
Qt-style synonym for QList::iterator.
Definition: qlist.h:278
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
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
#define QTDSDECIMAL
Definition: qsql_tds.cpp:100
#define QTDSINT1
Definition: qsql_tds.cpp:104
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
void init()
Definition: qsql_tds.cpp:535
ErrorType
This enum type describes the context in which the error occurred, e.
Definition: qsqlerror.h:56
void cleanup()
Definition: qsql_tds.cpp:321
unsigned char uchar
Definition: qglobal.h:994
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QTime class provides clock time functions.
Definition: qdatetime.h:148
void close()
Derived classes must reimplement this pure virtual function in order to close the database connection...
Definition: qsql_tds.cpp:615
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QStringList errorMsgs
Definition: qsql_tds.cpp:160
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
int indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero) const
Attempts to find a match in str from position offset (0 by default).
Definition: qregexp.cpp:4136
QTDSResultPrivate * d
Definition: qsql_tds.h:94
#define QTDSVARCHAR
Definition: qsql_tds.cpp:113
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
bool gotoNext(QSqlCachedResult::ValueCache &values, int index)
Definition: qsql_tds.cpp:345
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
QHash< DBPROCESS *, QTDSResultPrivate * > QTDSErrorHash
Definition: qsql_tds.cpp:163
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
friend class QTDSResult
Definition: qsql_tds.h:100
QVariant::Type qFieldType(QTDSResultPrivate *d, int i)
Definition: qsql_tds.cpp:287
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
#define QTDSMONEY4
Definition: qsql_tds.cpp:108
QString escapeIdentifier(const QString &identifier, IdentifierType type) const
Returns the identifier escaped according to the database rules.
Definition: qsql_tds.cpp:823
Q_CORE_EXPORT void qWarning(const char *,...)
void addErrorMsg(QString &errMsg)
Definition: qsql_tds.cpp:153
#define QTDSDATETIME_N
Definition: qsql_tds.cpp:99
#define QTDSINT2
Definition: qsql_tds.cpp:105
void setName(const QString &name)
Sets the name of the index to name.
Definition: qsqlindex.cpp:110
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
TableType
Definition: qsql.h:74
#define QTDSFLT8
Definition: qsql_tds.cpp:101
Type
This enum type defines the types of variable that a QVariant can contain.
Definition: qvariant.h:95
#define QTDSDATETIME
Definition: qsql_tds.cpp:98
QVariant handle() const
Returns the low-level database handle wrapped in a QVariant or an invalid variant if there is no hand...
Definition: qsql_tds.cpp:530
QSqlIndex primaryIndex(const QString &tablename) const
Returns the primary index for table tableName.
Definition: qsql_tds.cpp:791
QDate addDays(int days) const
Returns a QDate object containing a date ndays later than the date of this object (or earlier if nday...
Definition: qdatetime.cpp:989
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
quint16 values[128]
QVariant::Type type() const
Returns the field&#39;s type as stored in the database.
Definition: qsqlfield.cpp:394
QTDSResult(const QTDSDriver *db)
Definition: qsql_tds.cpp:294
QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
Definition: qsql_tds.cpp:504
int numRowsAffected()
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
Definition: qsql_tds.cpp:492
QByteArray toLocal8Bit() const Q_REQUIRED_RESULT
Returns the local 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4049
#define QTDSBINARY
Definition: qsql_tds.cpp:115
QSqlField field(int i) const
Returns the field at position index.
Definition: qsqlrecord.cpp:289
#define QTDSIMAGE
Definition: qsql_tds.cpp:117
void setForwardOnly(bool forward)
Sets forward only mode to forward.
Definition: qsqlquery.cpp:835
#define QTDSNUMERIC
Definition: qsql_tds.cpp:111
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
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QSqlRecord record(const QString &tablename) const
Returns a QSqlRecord populated with the names of the fields in table tableName.
Definition: qsql_tds.cpp:709
QString join(const QString &sep) const
Joins all the string list&#39;s strings into a single string with each element separated by the given sep...
Definition: qstringlist.h:162
int count() const
Returns the number of fields in the record.
Definition: qsqlrecord.cpp:573
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
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
#define QTDSTEXT
Definition: qsql_tds.cpp:112
QString trimmed(QString source)
Definition: generator.cpp:233
void clearErrorMsgs()
Definition: qsql_tds.cpp:155
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
QVector< void * > buffer
Definition: qsql_tds.cpp:156
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
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
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...
Definition: qsql_tds.cpp:571
bool isNull() const
Returns true if the field&#39;s value is NULL; otherwise returns false.
Definition: qsqlfield.cpp:428
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
QString toLower() const Q_REQUIRED_RESULT
Returns a lowercase copy of the string.
Definition: qstring.cpp:5389
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
bool reset(const QString &query)
Sets the result to use the SQL statement query for subsequent data retrieval.
Definition: qsql_tds.cpp:404
#define QERRHANDLE
Definition: qsql_tds.cpp:95
bool rollbackTransaction()
This function is called to rollback a transaction.
Definition: qsql_tds.cpp:684
void append(const QSqlField &field)
Append a copy of field field to the end of the record.
Definition: qsqlrecord.cpp:312
QVariant handle() const
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
Definition: qsql_tds.cpp:335
static bool qIsNull(const void *ind)
Definition: qsql_tds.cpp:340
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active...
Definition: qsqlresult.cpp:402
void clear()
Removes all the record&#39;s fields.
Definition: qsqlrecord.cpp:367
QSqlResult * createResult() const
Creates an empty SQL result on the database.
Definition: qsql_tds.cpp:629
QSqlRecord rec
Definition: qsql_tds.cpp:157
#define QTDSINT4
Definition: qsql_tds.cpp:106
quint16 index
#define QTDSBIT
Definition: qsql_tds.cpp:114
QTime addMSecs(int ms) const
Returns a QTime object containing a time ms milliseconds later than the time of this object (or earli...
Definition: qdatetime.cpp:1803
static int CS_PUBLIC qTdsErrHandler(DBPROCESS *dbproc, int, int dberr, int, char *dberrstr, char *oserrstr)
Definition: qsql_tds.cpp:204
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
#define QTDSFLT4
Definition: qsql_tds.cpp:103
void init(int colCount)
LOGINREC * login
Definition: qsql_tds.cpp:150
The QSqlField class manipulates the fields in SQL database tables and views.
Definition: qsqlfield.h:56
DBPROCESS * dbproc
Definition: qsql_tds.cpp:151
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
#define CS_PUBLIC
Definition: qsql_tds.cpp:127
QTDSDriver(QObject *parent=0)
Definition: qsql_tds.cpp:511
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
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
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_tds.cpp:487
QSqlError qMakeError(const QString &err, QSqlError::ErrorType type, int errNo=-1)
Definition: qsql_tds.cpp:130
QVariant value(int i) const
Returns the value of field index in the current record.
Definition: qsqlquery.cpp:403
bool next()
Retrieves the next record in the result, if available, and positions the query on the retrieved recor...
Definition: qsqlquery.cpp:594
The QSqlResult class provides an abstract interface for accessing data from specific SQL databases...
Definition: qsqlresult.h:63
static int CS_PUBLIC qTdsMsgHandler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *, int line)
Definition: qsql_tds.cpp:167
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
QString formatValue(const QSqlField &field, bool trimStrings) const
Returns a string representation of the field value for the database.
Definition: qsql_tds.cpp:762
#define QTDSNUMERIC_2
Definition: qsql_tds.cpp:120
void setSqlType(int type)
Definition: qsqlfield.cpp:285
#define QTDSMONEY_N
Definition: qsql_tds.cpp:110
#define QTDSDATETIME4
Definition: qsql_tds.cpp:97
#define QTDSMONEY
Definition: qsql_tds.cpp:109