source: trunk/src/sql/drivers/tds/qsql_tds.cpp@ 116

Last change on this file since 116 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 22.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtSql module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
66QT_BEGIN_NAMESPACE
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
130QSqlError qMakeError(const QString& err, QSqlError::ErrorType type, int errNo = -1)
131{
132 return QSqlError(QLatin1String("QTDS: ") + err, QString(), type, errNo);
133}
134
135class QTDSDriverPrivate
136{
137public:
138 QTDSDriverPrivate(): login(0) {}
139 LOGINREC* login; // login information
140 QString hostName;
141 QString db;
142};
143
144
145class QTDSResultPrivate
146{
147public:
148 QTDSResultPrivate():login(0), dbproc(0) {}
149 LOGINREC* login; // login information
150 DBPROCESS* dbproc; // connection from app to server
151 QSqlError lastError;
152 void addErrorMsg(QString& errMsg) { errorMsgs.append(errMsg); }
153 QString getErrorMsgs() { return errorMsgs.join(QLatin1String("\n")); }
154 void clearErrorMsgs() { errorMsgs.clear(); }
155 QVector<void *> buffer;
156 QSqlRecord rec;
157
158private:
159 QStringList errorMsgs;
160};
161
162typedef QHash<DBPROCESS *, QTDSResultPrivate *> QTDSErrorHash;
163Q_GLOBAL_STATIC(QTDSErrorHash, errs)
164
165extern "C" {
166static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc,
167 DBINT /*msgno*/,
168 int msgstate,
169 int severity,
170 char* msgtext,
171 char* /*srvname*/,
172 char* /*procname*/,
173 int /*line*/)
174{
175 QTDSResultPrivate* p = errs()->value(dbproc);
176
177 if (!p) {
178// ### umm... temporary disabled since this throws a lot of warnings...
179// qWarning("QTDSDriver warning (%d): [%s] from server [%s]", msgstate, msgtext, srvname);
180 return INT_CANCEL;
181 }
182
183 if (severity > 0) {
184 QString errMsg = QString(QLatin1String("%1 (%2)")).arg(QString::fromAscii(msgtext)).arg(
185 msgstate);
186 p->addErrorMsg(errMsg);
187 }
188
189 return INT_CANCEL;
190}
191
192static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
193 int /*severity*/,
194 int dberr,
195 int /*oserr*/,
196 char* dberrstr,
197 char* oserrstr)
198{
199 QTDSResultPrivate* p = errs()->value(dbproc);
200 if (!p) {
201 qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
202 return INT_CANCEL;
203 }
204 /*
205 * If the process is dead or NULL and
206 * we are not in the middle of logging in...
207 */
208 if((dbproc == NULL || DBDEAD(dbproc))) {
209 qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
210 return INT_CANCEL;
211 }
212
213
214 QString errMsg = QString(QLatin1String("%1 %2\n")).arg(QString::fromAscii(dberrstr)).arg(
215 QString::fromAscii(oserrstr));
216 errMsg += p->getErrorMsgs();
217 p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
218 p->clearErrorMsgs();
219
220 return INT_CANCEL ;
221}
222
223} //extern "C"
224
225
226QVariant::Type qDecodeTDSType(int type)
227{
228 QVariant::Type t = QVariant::Invalid;
229 switch (type) {
230 case QTDSCHAR:
231 case QTDSTEXT:
232 case QTDSVARCHAR:
233 t = QVariant::String;
234 break;
235 case QTDSINT1:
236 case QTDSINT2:
237 case QTDSINT4:
238 case QTDSINT4_N:
239 case QTDSBIT:
240 t = QVariant::Int;
241 break;
242 case QTDSFLT4:
243 case QTDSFLT8:
244 case QTDSFLT8_N:
245 case QTDSMONEY4:
246 case QTDSMONEY:
247 case QTDSDECIMAL:
248 case QTDSNUMERIC:
249#ifdef QTDSNUMERIC_2
250 case QTDSNUMERIC_2:
251#endif
252#ifdef QTDSDECIMAL_2
253 case QTDSDECIMAL_2:
254#endif
255 case QTDSMONEY_N:
256 t = QVariant::Double;
257 break;
258 case QTDSDATETIME4:
259 case QTDSDATETIME:
260 case QTDSDATETIME_N:
261 t = QVariant::DateTime;
262 break;
263 case QTDSBINARY:
264 case QTDSVARBINARY:
265 case QTDSIMAGE:
266 t = QVariant::ByteArray;
267 break;
268 default:
269 t = QVariant::Invalid;
270 break;
271 }
272 return t;
273}
274
275QVariant::Type qFieldType(QTDSResultPrivate* d, int i)
276{
277 QVariant::Type type = qDecodeTDSType(dbcoltype(d->dbproc, i+1));
278 return type;
279}
280
281
282QTDSResult::QTDSResult(const QTDSDriver* db)
283 : QSqlCachedResult(db)
284{
285 d = new QTDSResultPrivate();
286 d->login = db->d->login;
287
288 d->dbproc = dbopen(d->login, const_cast<char*>(db->d->hostName.toLatin1().constData()));
289 if (!d->dbproc)
290 return;
291 if (dbuse(d->dbproc, const_cast<char*>(db->d->db.toLatin1().constData())) == FAIL)
292 return;
293
294 // insert d in error handler dict
295 errs()->insert(d->dbproc, d);
296}
297
298QTDSResult::~QTDSResult()
299{
300 cleanup();
301 if (d->dbproc)
302 dbclose(d->dbproc);
303 errs()->remove(d->dbproc);
304 delete d;
305}
306
307void QTDSResult::cleanup()
308{
309 d->clearErrorMsgs();
310 d->rec.clear();
311 for (int i = 0; i < d->buffer.size() / 2; ++i)
312 free(d->buffer.at(i * 2));
313 d->buffer.clear();
314 // "can" stands for "cancel"... very clever.
315 dbcanquery(d->dbproc);
316 dbfreebuf(d->dbproc);
317
318 QSqlCachedResult::cleanup();
319}
320
321QVariant QTDSResult::handle() const
322{
323 return QVariant(qRegisterMetaType<DBPROCESS *>("DBPROCESS*"), &d->dbproc);
324}
325
326static inline bool qIsNull(const void *ind)
327{
328 return *reinterpret_cast<const DBINT *>(&ind) == -1;
329}
330
331bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
332{
333 STATUS stat = dbnextrow(d->dbproc);
334 if (stat == NO_MORE_ROWS) {
335 setAt(QSql::AfterLastRow);
336 return false;
337 }
338 if ((stat == FAIL) || (stat == BUF_FULL)) {
339 setLastError(d->lastError);
340 return false;
341 }
342
343 if (index < 0)
344 return true;
345
346 for (int i = 0; i < d->rec.count(); ++i) {
347 int idx = index + i;
348 switch (d->rec.field(i).type()) {
349 case QVariant::DateTime:
350 if (qIsNull(d->buffer.at(i * 2 + 1))) {
351 values[idx] = QVariant(QVariant::DateTime);
352 } else {
353 DBDATETIME *bdt = (DBDATETIME*) d->buffer.at(i * 2);
354 QDate date = QDate::fromString(QLatin1String("1900-01-01"), Qt::ISODate);
355 QTime time = QTime::fromString(QLatin1String("00:00:00"), Qt::ISODate);
356 values[idx] = QDateTime(date.addDays(bdt->dtdays), time.addMSecs(int(bdt->dttime / 0.3)));
357 }
358 break;
359 case QVariant::Int:
360 if (qIsNull(d->buffer.at(i * 2 + 1)))
361 values[idx] = QVariant(QVariant::Int);
362 else
363 values[idx] = *((int*)d->buffer.at(i * 2));
364 break;
365 case QVariant::Double:
366 case QVariant::String:
367 if (qIsNull(d->buffer.at(i * 2 + 1)))
368 values[idx] = QVariant(QVariant::String);
369 else
370 values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i * 2));
371 break;
372 case QVariant::ByteArray: {
373 if (qIsNull(d->buffer.at(i * 2 + 1)))
374 values[idx] = QVariant(QVariant::ByteArray);
375 else
376 values[idx] = QByteArray((const char*)d->buffer.at(i * 2));
377 break;
378 }
379 default:
380 // should never happen, and we already fired
381 // a warning while binding.
382 values[idx] = QVariant();
383 break;
384 }
385 }
386
387 return true;
388}
389
390bool QTDSResult::reset (const QString& query)
391{
392 cleanup();
393 if (!driver() || !driver()-> isOpen() || driver()->isOpenError())
394 return false;
395 setActive(false);
396 setAt(QSql::BeforeFirstRow);
397 if (dbcmd(d->dbproc, const_cast<char*>(query.toLocal8Bit().constData())) == FAIL) {
398 setLastError(d->lastError);
399 return false;
400 }
401
402 if (dbsqlexec(d->dbproc) == FAIL) {
403 setLastError(d->lastError);
404 dbfreebuf(d->dbproc);
405 return false;
406 }
407 if (dbresults(d->dbproc) != SUCCEED) {
408 setLastError(d->lastError);
409 dbfreebuf(d->dbproc);
410 return false;
411 }
412
413 setSelect((DBCMDROW(d->dbproc) == SUCCEED)); // decide whether or not we are dealing with a SELECT query
414 int numCols = dbnumcols(d->dbproc);
415 if (numCols > 0) {
416 d->buffer.resize(numCols * 2);
417 init(numCols);
418 }
419 for (int i = 0; i < numCols; ++i) {
420 int dbType = dbcoltype(d->dbproc, i+1);
421 QVariant::Type vType = qDecodeTDSType(dbType);
422 QSqlField f(QString::fromAscii(dbcolname(d->dbproc, i+1)), vType);
423 f.setSqlType(dbType);
424 f.setLength(dbcollen(d->dbproc, i+1));
425 d->rec.append(f);
426
427 RETCODE ret = -1;
428 void* p = 0;
429 switch (vType) {
430 case QVariant::Int:
431 p = malloc(4);
432 ret = dbbind(d->dbproc, i+1, INTBIND, (DBINT) 4, (unsigned char *)p);
433 break;
434 case QVariant::Double:
435 // use string binding to prevent loss of precision
436 p = malloc(50);
437 ret = dbbind(d->dbproc, i+1, STRINGBIND, 50, (unsigned char *)p);
438 break;
439 case QVariant::String:
440 p = malloc(dbcollen(d->dbproc, i+1) + 1);
441 ret = dbbind(d->dbproc, i+1, STRINGBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
442 break;
443 case QVariant::DateTime:
444 p = malloc(8);
445 ret = dbbind(d->dbproc, i+1, DATETIMEBIND, (DBINT) 8, (unsigned char *)p);
446 break;
447 case QVariant::ByteArray:
448 p = malloc(dbcollen(d->dbproc, i+1) + 1);
449 ret = dbbind(d->dbproc, i+1, BINARYBIND, DBINT(dbcollen(d->dbproc, i+1) + 1), (unsigned char *)p);
450 break;
451 default: //don't bind the field since we do not support it
452 qWarning("QTDSResult::reset: Unsupported type for field \"%s\"", dbcolname(d->dbproc, i+1));
453 break;
454 }
455 if (ret == SUCCEED) {
456 d->buffer[i * 2] = p;
457 ret = dbnullbind(d->dbproc, i+1, (DBINT*)(&d->buffer[i * 2 + 1]));
458 } else {
459 d->buffer[i * 2] = 0;
460 d->buffer[i * 2 + 1] = 0;
461 free(p);
462 }
463 if ((ret != SUCCEED) && (ret != -1)) {
464 setLastError(d->lastError);
465 return false;
466 }
467 }
468
469 setActive(true);
470 return true;
471}
472
473int QTDSResult::size()
474{
475 return -1;
476}
477
478int QTDSResult::numRowsAffected()
479{
480#ifdef DBNTWIN32
481 if (dbiscount(d->dbproc)) {
482 return DBCOUNT(d->dbproc);
483 }
484 return -1;
485#else
486 return DBCOUNT(d->dbproc);
487#endif
488}
489
490QSqlRecord QTDSResult::record() const
491{
492 return d->rec;
493}
494
495///////////////////////////////////////////////////////////////////
496
497QTDSDriver::QTDSDriver(QObject* parent)
498 : QSqlDriver(parent)
499{
500 init();
501}
502
503QTDSDriver::QTDSDriver(LOGINREC* rec, const QString& host, const QString &db, QObject* parent)
504 : QSqlDriver(parent)
505{
506 init();
507 d->login = rec;
508 d->hostName = host;
509 d->db = db;
510 if (rec) {
511 setOpen(true);
512 setOpenError(false);
513 }
514}
515
516QVariant QTDSDriver::handle() const
517{
518 return QVariant(qRegisterMetaType<LOGINREC *>("LOGINREC*"), &d->login);
519}
520
521void QTDSDriver::init()
522{
523 d = new QTDSDriverPrivate();
524 // the following two code-lines will fail compilation on some FreeTDS versions
525 // just comment them out if you have FreeTDS (you won't get any errors and warnings then)
526 dberrhandle((QERRHANDLE)qTdsErrHandler);
527 dbmsghandle((QMSGHANDLE)qTdsMsgHandler);
528}
529
530QTDSDriver::~QTDSDriver()
531{
532 dberrhandle(0);
533 dbmsghandle(0);
534 // dbexit also calls dbclose if necessary
535 dbexit();
536 delete d;
537}
538
539bool QTDSDriver::hasFeature(DriverFeature f) const
540{
541 switch (f) {
542 case Transactions:
543 case QuerySize:
544 case Unicode:
545 case SimpleLocking:
546 case EventNotifications:
547 case MultipleResultSets:
548 return false;
549 case BLOB:
550 return true;
551 default:
552 return false;
553 }
554}
555
556bool QTDSDriver::open(const QString & db,
557 const QString & user,
558 const QString & password,
559 const QString & host,
560 int /*port*/,
561 const QString& /*connOpts*/)
562{
563 if (isOpen())
564 close();
565 if (!dbinit()) {
566 setOpenError(true);
567 return false;
568 }
569 d->login = dblogin();
570 if (!d->login) {
571 setOpenError(true);
572 return false;
573 }
574 DBSETLPWD(d->login, const_cast<char*>(password.toLocal8Bit().constData()));
575 DBSETLUSER(d->login, const_cast<char*>(user.toLocal8Bit().constData()));
576
577 // Now, try to open and use the database. If this fails, return false.
578 DBPROCESS* dbproc;
579
580 dbproc = dbopen(d->login, const_cast<char*>(host.toLatin1().constData()));
581 if (!dbproc) {
582 setLastError(qMakeError(tr("Unable to open connection"), QSqlError::ConnectionError, -1));
583 setOpenError(true);
584 return false;
585 }
586 if (dbuse(dbproc, const_cast<char*>(db.toLatin1().constData())) == FAIL) {
587 setLastError(qMakeError(tr("Unable to use database"), QSqlError::ConnectionError, -1));
588 setOpenError(true);
589 return false;
590 }
591 dbclose( dbproc );
592
593 setOpen(true);
594 setOpenError(false);
595 d->hostName = host;
596 d->db = db;
597 return true;
598}
599
600void QTDSDriver::close()
601{
602 if (isOpen()) {
603#ifdef Q_USE_SYBASE
604 dbloginfree(d->login);
605#else
606 dbfreelogin(d->login);
607#endif
608 d->login = 0;
609 setOpen(false);
610 setOpenError(false);
611 }
612}
613
614QSqlResult *QTDSDriver::createResult() const
615{
616 return new QTDSResult(this);
617}
618
619bool QTDSDriver::beginTransaction()
620{
621 return false;
622/*
623 if (!isOpen()) {
624 qWarning("QTDSDriver::beginTransaction: Database not open");
625 return false;
626 }
627 if (dbcmd(d->dbproc, "BEGIN TRANSACTION") == FAIL) {
628 setLastError(d->lastError);
629 dbfreebuf(d->dbproc);
630 return false;
631 }
632 if (dbsqlexec(d->dbproc) == FAIL) {
633 setLastError(d->lastError);
634 dbfreebuf(d->dbproc);
635 return false;
636 }
637 while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
638 dbfreebuf(d->dbproc);
639 inTransaction = true;
640 return true;
641*/
642}
643
644bool QTDSDriver::commitTransaction()
645{
646 return false;
647/*
648 if (!isOpen()) {
649 qWarning("QTDSDriver::commitTransaction: Database not open");
650 return false;
651 }
652 if (dbcmd(d->dbproc, "COMMIT TRANSACTION") == FAIL) {
653 setLastError(d->lastError);
654 dbfreebuf(d->dbproc);
655 return false;
656 }
657 if (dbsqlexec(d->dbproc) == FAIL) {
658 setLastError(d->lastError);
659 dbfreebuf(d->dbproc);
660 return false;
661 }
662 while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
663 dbfreebuf(d->dbproc);
664 inTransaction = false;
665 return true;
666*/
667}
668
669bool QTDSDriver::rollbackTransaction()
670{
671 return false;
672/*
673 if (!isOpen()) {
674 qWarning("QTDSDriver::rollbackTransaction: Database not open");
675 return false;
676 }
677 if (dbcmd(d->dbproc, "ROLLBACK TRANSACTION") == FAIL) {
678 setLastError(d->lastError);
679 dbfreebuf(d->dbproc);
680 return false;
681 }
682 if (dbsqlexec(d->dbproc) == FAIL) {
683 setLastError(d->lastError);
684 dbfreebuf(d->dbproc);
685 return false;
686 }
687 while(dbresults(d->dbproc) == NO_MORE_RESULTS) {}
688 dbfreebuf(d->dbproc);
689 inTransaction = false;
690 return true;
691*/
692}
693
694QSqlRecord QTDSDriver::record(const QString& tablename) const
695{
696 QSqlRecord info;
697 if (!isOpen())
698 return info;
699 QSqlQuery t(createResult());
700 t.setForwardOnly(true);
701 QString stmt (QLatin1String("select name, type, length, prec from syscolumns "
702 "where id = (select id from sysobjects where name = '%1')"));
703 t.exec(stmt.arg(tablename));
704 while (t.next()) {
705 QSqlField f(t.value(0).toString().simplified(), qDecodeTDSType(t.value(1).toInt()));
706 f.setLength(t.value(2).toInt());
707 f.setPrecision(t.value(3).toInt());
708 f.setSqlType(t.value(1).toInt());
709 info.append(f);
710 }
711 return info;
712}
713
714QStringList QTDSDriver::tables(QSql::TableType type) const
715{
716 QStringList list;
717
718 if (!isOpen())
719 return list;
720
721 QStringList typeFilter;
722
723 if (type & QSql::Tables)
724 typeFilter += QLatin1String("type='U'");
725 if (type & QSql::SystemTables)
726 typeFilter += QLatin1String("type='S'");
727 if (type & QSql::Views)
728 typeFilter += QLatin1String("type='V'");
729
730 if (typeFilter.isEmpty())
731 return list;
732
733 QSqlQuery t(createResult());
734 t.setForwardOnly(true);
735 t.exec(QLatin1String("select name from sysobjects where ") + typeFilter.join(QLatin1String(" or ")));
736 while (t.next())
737 list.append(t.value(0).toString().simplified());
738
739 return list;
740}
741
742QString QTDSDriver::formatValue(const QSqlField &field,
743 bool trim) const
744{
745 QString r;
746 if (field.isNull())
747 r = QLatin1String("NULL");
748 else if (field.type() == QVariant::DateTime) {
749 if (field.value().toDateTime().isValid()){
750 r = field.value().toDateTime().toString(QLatin1String("'yyyyMMdd hh:mm:ss'"));
751 } else
752 r = QLatin1String("NULL");
753 } else if (field.type() == QVariant::ByteArray) {
754 QByteArray ba = field.value().toByteArray();
755 QString res;
756 static const char hexchars[] = "0123456789abcdef";
757 for (int i = 0; i < ba.size(); ++i) {
758 uchar s = (uchar) ba[i];
759 res += QLatin1Char(hexchars[s >> 4]);
760 res += QLatin1Char(hexchars[s & 0x0f]);
761 }
762 r = QLatin1String("0x") + res;
763 } else {
764 r = QSqlDriver::formatValue(field, trim);
765 }
766 return r;
767}
768
769QSqlIndex QTDSDriver::primaryIndex(const QString& tablename) const
770{
771 QSqlRecord rec = record(tablename);
772
773 QSqlIndex idx(tablename);
774 if ((!isOpen()) || (tablename.isEmpty()))
775 return QSqlIndex();
776
777 QSqlQuery t(createResult());
778 t.setForwardOnly(true);
779 t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(tablename));
780 if (t.next()) {
781 QStringList fNames = t.value(2).toString().simplified().split(QLatin1Char(','));
782 QRegExp regx(QLatin1String("\\s*(\\S+)(?:\\s+(DESC|desc))?\\s*"));
783 for(QStringList::Iterator it = fNames.begin(); it != fNames.end(); ++it) {
784 regx.indexIn(*it);
785 QSqlField f(regx.cap(1), rec.field(regx.cap(1)).type());
786 if (regx.cap(2).toLower() == QLatin1String("desc")) {
787 idx.append(f, true);
788 } else {
789 idx.append(f, false);
790 }
791 }
792 idx.setName(t.value(0).toString().simplified());
793 }
794 return idx;
795}
796
797QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.