Qt 4.8
qsql_ibase.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_ibase.h"
43 #include <qcoreapplication.h>
44 #include <qdatetime.h>
45 #include <qvariant.h>
46 #include <qsqlerror.h>
47 #include <qsqlfield.h>
48 #include <qsqlindex.h>
49 #include <qsqlquery.h>
50 #include <qlist.h>
51 #include <qvector.h>
52 #include <qtextcodec.h>
53 #include <qmutex.h>
54 #include <stdlib.h>
55 #include <limits.h>
56 #include <math.h>
57 #include <qdebug.h>
58 #include <QVarLengthArray>
59 
61 
62 #define FBVERSION SQL_DIALECT_V6
63 
64 #ifndef SQLDA_CURRENT_VERSION
65 #define SQLDA_CURRENT_VERSION SQLDA_VERSION1
66 #endif
67 
68 enum { QIBaseChunkSize = SHRT_MAX / 2 };
69 
70 #if defined(FB_API_VER) && FB_API_VER >= 20
71 static bool getIBaseError(QString& msg, const ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
72 #else
73 static bool getIBaseError(QString& msg, ISC_STATUS* status, ISC_LONG &sqlcode, QTextCodec *tc)
74 #endif
75 {
76  if (status[0] != 1 || status[1] <= 0)
77  return false;
78 
79  msg.clear();
80  sqlcode = isc_sqlcode(status);
81  char buf[512];
82 #if defined(FB_API_VER) && FB_API_VER >= 20
83  while(fb_interpret(buf, 512, &status)) {
84 #else
85  while(isc_interprete(buf, &status)) {
86 #endif
87  if(!msg.isEmpty())
88  msg += QLatin1String(" - ");
89  if (tc)
90  msg += tc->toUnicode(buf);
91  else
92  msg += QString::fromUtf8(buf);
93  }
94  return true;
95 }
96 
97 static void createDA(XSQLDA *&sqlda)
98 {
99  sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));
100  if (sqlda == (XSQLDA*)0) return;
101  sqlda->sqln = 1;
102  sqlda->sqld = 0;
103  sqlda->version = SQLDA_CURRENT_VERSION;
104  sqlda->sqlvar[0].sqlind = 0;
105  sqlda->sqlvar[0].sqldata = 0;
106 }
107 
108 static void enlargeDA(XSQLDA *&sqlda, int n)
109 {
110  if (sqlda != (XSQLDA*)0)
111  free(sqlda);
112  sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n));
113  if (sqlda == (XSQLDA*)0) return;
114  sqlda->sqln = n;
115  sqlda->version = SQLDA_CURRENT_VERSION;
116 }
117 
118 static void initDA(XSQLDA *sqlda)
119 {
120  for (int i = 0; i < sqlda->sqld; ++i) {
121  switch (sqlda->sqlvar[i].sqltype & ~1) {
122  case SQL_INT64:
123  case SQL_LONG:
124  case SQL_SHORT:
125  case SQL_FLOAT:
126  case SQL_DOUBLE:
127  case SQL_TIMESTAMP:
128  case SQL_TYPE_TIME:
129  case SQL_TYPE_DATE:
130  case SQL_TEXT:
131  case SQL_BLOB:
132  sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen];
133  break;
134  case SQL_ARRAY:
135  sqlda->sqlvar[i].sqldata = new char[sizeof(ISC_QUAD)];
136  memset(sqlda->sqlvar[i].sqldata, 0, sizeof(ISC_QUAD));
137  break;
138  case SQL_VARYING:
139  sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen + sizeof(short)];
140  break;
141  default:
142  // not supported - do not bind.
143  sqlda->sqlvar[i].sqldata = 0;
144  break;
145  }
146  if (sqlda->sqlvar[i].sqltype & 1) {
147  sqlda->sqlvar[i].sqlind = new short[1];
148  *(sqlda->sqlvar[i].sqlind) = 0;
149  } else {
150  sqlda->sqlvar[i].sqlind = 0;
151  }
152  }
153 }
154 
155 static void delDA(XSQLDA *&sqlda)
156 {
157  if (!sqlda)
158  return;
159  for (int i = 0; i < sqlda->sqld; ++i) {
160  delete [] sqlda->sqlvar[i].sqlind;
161  delete [] sqlda->sqlvar[i].sqldata;
162  }
163  free(sqlda);
164  sqlda = 0;
165 }
166 
167 static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
168 {
169  switch (iType) {
170  case blr_varying:
171  case blr_varying2:
172  case blr_text:
173  case blr_cstring:
174  case blr_cstring2:
175  return QVariant::String;
176  case blr_sql_time:
177  return QVariant::Time;
178  case blr_sql_date:
179  return QVariant::Date;
180  case blr_timestamp:
181  return QVariant::DateTime;
182  case blr_blob:
183  return QVariant::ByteArray;
184  case blr_quad:
185  case blr_short:
186  case blr_long:
187  return (hasScale ? QVariant::Double : QVariant::Int);
188  case blr_int64:
189  return (hasScale ? QVariant::Double : QVariant::LongLong);
190  case blr_float:
191  case blr_d_float:
192  case blr_double:
193  return QVariant::Double;
194  }
195  qWarning("qIBaseTypeName: unknown datatype: %d", iType);
196  return QVariant::Invalid;
197 }
198 
199 static QVariant::Type qIBaseTypeName2(int iType, bool hasScale)
200 {
201  switch(iType & ~1) {
202  case SQL_VARYING:
203  case SQL_TEXT:
204  return QVariant::String;
205  case SQL_LONG:
206  case SQL_SHORT:
207  return (hasScale ? QVariant::Double : QVariant::Int);
208  case SQL_INT64:
209  return (hasScale ? QVariant::Double : QVariant::LongLong);
210  case SQL_FLOAT:
211  case SQL_DOUBLE:
212  return QVariant::Double;
213  case SQL_TIMESTAMP:
214  return QVariant::DateTime;
215  case SQL_TYPE_TIME:
216  return QVariant::Time;
217  case SQL_TYPE_DATE:
218  return QVariant::Date;
219  case SQL_ARRAY:
220  return QVariant::List;
221  case SQL_BLOB:
222  return QVariant::ByteArray;
223  default:
224  return QVariant::Invalid;
225  }
226 }
227 
228 static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
229 {
230  static const QTime midnight(0, 0, 0, 0);
231  static const QDate basedate(1858, 11, 17);
232  ISC_TIMESTAMP ts;
233  ts.timestamp_time = midnight.msecsTo(dt.time()) * 10;
234  ts.timestamp_date = basedate.daysTo(dt.date());
235  return ts;
236 }
237 
238 static QDateTime fromTimeStamp(char *buffer)
239 {
240  static const QDate bd(1858, 11, 17);
241  QTime t;
242  QDate d;
243 
244  // have to demangle the structure ourselves because isc_decode_time
245  // strips the msecs
246  t = t.addMSecs(int(((ISC_TIMESTAMP*)buffer)->timestamp_time / 10));
247  d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
248 
249  return QDateTime(d, t);
250 }
251 
252 static ISC_TIME toTime(const QTime &t)
253 {
254  static const QTime midnight(0, 0, 0, 0);
255  return (ISC_TIME)midnight.msecsTo(t) * 10;
256 }
257 
258 static QTime fromTime(char *buffer)
259 {
260  QTime t;
261  // have to demangle the structure ourselves because isc_decode_time
262  // strips the msecs
263  t = t.addMSecs(int((*(ISC_TIME*)buffer) / 10));
264 
265  return t;
266 }
267 
268 static ISC_DATE toDate(const QDate &t)
269 {
270  static const QDate basedate(1858, 11, 17);
271  ISC_DATE date;
272 
273  date = basedate.daysTo(t);
274  return date;
275 }
276 
277 static QDate fromDate(char *buffer)
278 {
279  static const QDate bd(1858, 11, 17);
280  QDate d;
281 
282  // have to demangle the structure ourselves because isc_decode_time
283  // strips the msecs
284  d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
285 
286  return d;
287 }
288 
289 static QByteArray encodeString(QTextCodec *tc, const QString &str)
290 {
291  if (tc)
292  return tc->fromUnicode(str);
293  return str.toUtf8();
294 }
295 
297 #if defined(FB_API_VER) && FB_API_VER >= 20
298  ISC_UCHAR *eventBuffer;
299  ISC_UCHAR *resultBuffer;
300 #else
301  char *eventBuffer;
303 #endif
304  ISC_LONG bufferLength;
305  ISC_LONG eventId;
306 
309 };
310 
312 {
313 public:
314  QIBaseDriverPrivate(QIBaseDriver *d) : q(d), ibase(0), trans(0), tc(0) {}
315 
317  {
318  QString imsg;
319  ISC_LONG sqlcode;
320  if (!getIBaseError(imsg, status, sqlcode, tc))
321  return false;
322 
323  q->setLastError(QSqlError(QCoreApplication::translate("QIBaseDriver", msg),
324  imsg, typ, int(sqlcode)));
325  return true;
326  }
327 
328 public:
330  isc_db_handle ibase;
331  isc_tr_handle trans;
333  ISC_STATUS status[20];
335 };
336 
338 Q_GLOBAL_STATIC(QIBaseBufferDriverMap, qBufferDriverMap)
339 Q_GLOBAL_STATIC(QMutex, qMutex);
340 
341 static void qFreeEventBuffer(QIBaseEventBuffer* eBuffer)
342 {
343  qMutex()->lock();
344  qBufferDriverMap()->remove(reinterpret_cast<void *>(eBuffer->resultBuffer));
345  qMutex()->unlock();
346  delete eBuffer;
347 }
348 
350 {
351 public:
354 
355  void cleanup();
357  {
358  QString imsg;
359  ISC_LONG sqlcode;
360  if (!getIBaseError(imsg, status, sqlcode, tc))
361  return false;
362 
363  q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg),
364  imsg, typ, int(sqlcode)));
365  return true;
366  }
367 
368  bool transaction();
369  bool commit();
370 
371  bool isSelect();
372  QVariant fetchBlob(ISC_QUAD *bId);
373  bool writeBlob(int i, const QByteArray &ba);
374  QVariant fetchArray(int pos, ISC_QUAD *arr);
375  bool writeArray(int i, const QList<QVariant> &list);
376 
377 public:
379  const QIBaseDriver *db;
380  ISC_STATUS status[20];
381  isc_tr_handle trans;
382  //indicator whether we have a local transaction or a transaction on driver level
384  isc_stmt_handle stmt;
385  isc_db_handle ibase;
386  XSQLDA *sqlda; // output sqlda
387  XSQLDA *inda; // input parameters
390 };
391 
392 
394  q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d->ibase), sqlda(0), inda(0), queryType(-1), tc(ddb->d->tc)
395 {
396  localTransaction = (ddb->d->ibase == 0);
397 }
398 
400 {
401  commit();
402  if (!localTransaction)
403  trans = 0;
404 
405  if (stmt) {
406  isc_dsql_free_statement(status, &stmt, DSQL_drop);
407  stmt = 0;
408  }
409 
410  delDA(sqlda);
411  delDA(inda);
412 
413  queryType = -1;
414  q->cleanup();
415 }
416 
418 {
419  isc_blob_handle handle = 0;
420  ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata;
421  isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
422  if (!isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to create BLOB"),
424  int i = 0;
425  while (i < ba.size()) {
426  isc_put_segment(status, &handle, qMin(ba.size() - i, int(QIBaseChunkSize)),
427  const_cast<char*>(ba.data()) + i);
428  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to write BLOB")))
429  return false;
430  i += qMin(ba.size() - i, int(QIBaseChunkSize));
431  }
432  }
433  isc_close_blob(status, &handle);
434  return true;
435 }
436 
438 {
439  isc_blob_handle handle = 0;
440 
441  isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0);
442  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to open BLOB"),
444  return QVariant();
445 
446  unsigned short len = 0;
447  QByteArray ba;
448  int chunkSize = QIBaseChunkSize;
449  ba.resize(chunkSize);
450  int read = 0;
451  while (isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment) {
452  read += len;
453  ba.resize(read + chunkSize);
454  }
455  ba.resize(read);
456 
457  bool isErr = (status[1] == isc_segstr_eof ? false :
458  isError(QT_TRANSLATE_NOOP("QIBaseResult",
459  "Unable to read BLOB"),
461 
462  isc_close_blob(status, &handle);
463 
464  if (isErr)
465  return QVariant();
466 
467  ba.resize(read);
468  return ba;
469 }
470 
471 template<typename T>
472 static QList<QVariant> toList(char** buf, int count, T* = 0)
473 {
474  QList<QVariant> res;
475  for (int i = 0; i < count; ++i) {
476  res.append(*(T*)(*buf));
477  *buf += sizeof(T);
478  }
479  return res;
480 }
481 /* char** ? seems like bad influence from oracle ... */
482 template<>
483 QList<QVariant> toList<long>(char** buf, int count, long*)
484 {
485  QList<QVariant> res;
486  for (int i = 0; i < count; ++i) {
487  if (sizeof(int) == sizeof(long))
488  res.append(int((*(long*)(*buf))));
489  else
490  res.append((qint64)(*(long*)(*buf)));
491  *buf += sizeof(long);
492  }
493  return res;
494 }
495 
496 static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
497  short* numElements, ISC_ARRAY_DESC *arrayDesc,
498  QTextCodec *tc)
499 {
500  const short dim = arrayDesc->array_desc_dimensions - 1;
501  const unsigned char dataType = arrayDesc->array_desc_dtype;
502  QList<QVariant> valList;
503  unsigned short strLen = arrayDesc->array_desc_length;
504 
505  if (curDim != dim) {
506  for(int i = 0; i < numElements[curDim]; ++i)
507  buffer = readArrayBuffer(list, buffer, curDim + 1, numElements,
508  arrayDesc, tc);
509  } else {
510  switch(dataType) {
511  case blr_varying:
512  case blr_varying2:
513  strLen += 2; // for the two terminating null values
514  case blr_text:
515  case blr_text2: {
516  int o;
517  for (int i = 0; i < numElements[dim]; ++i) {
518  for(o = 0; o < strLen && buffer[o]!=0; ++o )
519  ;
520 
521  if (tc)
522  valList.append(tc->toUnicode(buffer, o));
523  else
524  valList.append(QString::fromUtf8(buffer, o));
525 
526  buffer += strLen;
527  }
528  break; }
529  case blr_long:
530  valList = toList<long>(&buffer, numElements[dim], static_cast<long *>(0));
531  break;
532  case blr_short:
533  valList = toList<short>(&buffer, numElements[dim]);
534  break;
535  case blr_int64:
536  valList = toList<qint64>(&buffer, numElements[dim]);
537  break;
538  case blr_float:
539  valList = toList<float>(&buffer, numElements[dim]);
540  break;
541  case blr_double:
542  valList = toList<double>(&buffer, numElements[dim]);
543  break;
544  case blr_timestamp:
545  for(int i = 0; i < numElements[dim]; ++i) {
546  valList.append(fromTimeStamp(buffer));
547  buffer += sizeof(ISC_TIMESTAMP);
548  }
549  break;
550  case blr_sql_time:
551  for(int i = 0; i < numElements[dim]; ++i) {
552  valList.append(fromTime(buffer));
553  buffer += sizeof(ISC_TIME);
554  }
555  break;
556  case blr_sql_date:
557  for(int i = 0; i < numElements[dim]; ++i) {
558  valList.append(fromDate(buffer));
559  buffer += sizeof(ISC_DATE);
560  }
561  break;
562  }
563  }
564  if (dim > 0)
565  list.append(valList);
566  else
567  list += valList;
568  return buffer;
569 }
570 
572 {
573  QList<QVariant> list;
574  ISC_ARRAY_DESC desc;
575 
576  if (!arr)
577  return list;
578 
579  QByteArray relname(sqlda->sqlvar[pos].relname, sqlda->sqlvar[pos].relname_length);
580  QByteArray sqlname(sqlda->sqlvar[pos].aliasname, sqlda->sqlvar[pos].aliasname_length);
581 
582  isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
583  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
585  return list;
586 
587 
588  int arraySize = 1, subArraySize;
589  short dimensions = desc.array_desc_dimensions;
590  QVarLengthArray<short> numElements(dimensions);
591 
592  for(int i = 0; i < dimensions; ++i) {
593  subArraySize = (desc.array_desc_bounds[i].array_bound_upper -
594  desc.array_desc_bounds[i].array_bound_lower + 1);
595  numElements[i] = subArraySize;
596  arraySize = subArraySize * arraySize;
597  }
598 
599  ISC_LONG bufLen;
600  QByteArray ba;
601  /* varying arrayelements are stored with 2 trailing null bytes
602  indicating the length of the string
603  */
604  if (desc.array_desc_dtype == blr_varying
605  || desc.array_desc_dtype == blr_varying2) {
606  desc.array_desc_length += 2;
607  bufLen = desc.array_desc_length * arraySize * sizeof(short);
608  } else {
609  bufLen = desc.array_desc_length * arraySize;
610  }
611 
612 
613  ba.resize(int(bufLen));
614  isc_array_get_slice(status, &ibase, &trans, arr, &desc, ba.data(), &bufLen);
615  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get array data"),
617  return list;
618 
619  readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc, tc);
620 
621  return QVariant(list);
622 }
623 
624 template<typename T>
625 static char* fillList(char *buffer, const QList<QVariant> &list, T* = 0)
626 {
627  for (int i = 0; i < list.size(); ++i) {
628  T val;
629  val = qvariant_cast<T>(list.at(i));
630  memcpy(buffer, &val, sizeof(T));
631  buffer += sizeof(T);
632  }
633  return buffer;
634 }
635 
636 template<>
637 char* fillList<float>(char *buffer, const QList<QVariant> &list, float*)
638 {
639  for (int i = 0; i < list.size(); ++i) {
640  double val;
641  float val2 = 0;
642  val = qvariant_cast<double>(list.at(i));
643  val2 = (float)val;
644  memcpy(buffer, &val2, sizeof(float));
645  buffer += sizeof(float);
646  }
647  return buffer;
648 }
649 
650 static char* qFillBufferWithString(char *buffer, const QString& string,
651  short buflen, bool varying, bool array,
652  QTextCodec *tc)
653 {
654  QByteArray str = encodeString(tc, string); // keep a copy of the string alive in this scope
655  if (varying) {
656  short tmpBuflen = buflen;
657  if (str.length() < buflen)
658  buflen = str.length();
659  if (array) { // interbase stores varying arrayelements different than normal varying elements
660  memcpy(buffer, str.data(), buflen);
661  memset(buffer + buflen, 0, tmpBuflen - buflen);
662  } else {
663  *(short*)buffer = buflen; // first two bytes is the length
664  memcpy(buffer + sizeof(short), str.data(), buflen);
665  }
666  buffer += tmpBuflen;
667  } else {
668  str = str.leftJustified(buflen, ' ', true);
669  memcpy(buffer, str.data(), buflen);
670  buffer += buflen;
671  }
672  return buffer;
673 }
674 
675 static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
676  QVariant::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc,
677  QString& error, QTextCodec *tc)
678 {
679  int i;
680  ISC_ARRAY_BOUND *bounds = arrayDesc->array_desc_bounds;
681  short dim = arrayDesc->array_desc_dimensions - 1;
682 
683  int elements = (bounds[curDim].array_bound_upper -
684  bounds[curDim].array_bound_lower + 1);
685 
686  if (list.size() != elements) { // size mismatch
687  error = QLatin1String("Expected size: %1. Supplied size: %2");
688  error = QLatin1String("Array size mismatch. Fieldname: %1 ")
689  + error.arg(elements).arg(list.size());
690  return 0;
691  }
692 
693  if (curDim != dim) {
694  for(i = 0; i < list.size(); ++i) {
695 
696  if (list.at(i).type() != QVariant::List) { // dimensions mismatch
697  error = QLatin1String("Array dimensons mismatch. Fieldname: %1");
698  return 0;
699  }
700 
701  buffer = createArrayBuffer(buffer, list.at(i).toList(), type, curDim + 1,
702  arrayDesc, error, tc);
703  if (!buffer)
704  return 0;
705  }
706  } else {
707  switch(type) {
708  case QVariant::Int:
709  case QVariant::UInt:
710  if (arrayDesc->array_desc_dtype == blr_short)
711  buffer = fillList<short>(buffer, list);
712  else
713  buffer = fillList<int>(buffer, list);
714  break;
715  case QVariant::Double:
716  if (arrayDesc->array_desc_dtype == blr_float)
717  buffer = fillList<float>(buffer, list, static_cast<float *>(0));
718  else
719  buffer = fillList<double>(buffer, list);
720  break;
721  case QVariant::LongLong:
722  buffer = fillList<qint64>(buffer, list);
723  break;
724  case QVariant::ULongLong:
725  buffer = fillList<quint64>(buffer, list);
726  break;
727  case QVariant::String:
728  for (i = 0; i < list.size(); ++i)
729  buffer = qFillBufferWithString(buffer, list.at(i).toString(),
730  arrayDesc->array_desc_length,
731  arrayDesc->array_desc_dtype == blr_varying,
732  true, tc);
733  break;
734  case QVariant::Date:
735  for (i = 0; i < list.size(); ++i) {
736  *((ISC_DATE*)buffer) = toDate(list.at(i).toDate());
737  buffer += sizeof(ISC_DATE);
738  }
739  break;
740  case QVariant::Time:
741  for (i = 0; i < list.size(); ++i) {
742  *((ISC_TIME*)buffer) = toTime(list.at(i).toTime());
743  buffer += sizeof(ISC_TIME);
744  }
745  break;
746 
747  case QVariant::DateTime:
748  for (i = 0; i < list.size(); ++i) {
749  *((ISC_TIMESTAMP*)buffer) = toTimeStamp(list.at(i).toDateTime());
750  buffer += sizeof(ISC_TIMESTAMP);
751  }
752  break;
753  default:
754  break;
755  }
756  }
757  return buffer;
758 }
759 
761 {
762  QString error;
763  ISC_QUAD *arrayId = (ISC_QUAD*) inda->sqlvar[column].sqldata;
764  ISC_ARRAY_DESC desc;
765 
766  QByteArray relname(inda->sqlvar[column].relname, inda->sqlvar[column].relname_length);
767  QByteArray sqlname(inda->sqlvar[column].aliasname, inda->sqlvar[column].aliasname_length);
768 
769  isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
770  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
772  return false;
773 
774  short arraySize = 1;
775  ISC_LONG bufLen;
776  QList<QVariant> subList = list;
777 
778  short dimensions = desc.array_desc_dimensions;
779  for(int i = 0; i < dimensions; ++i) {
780  arraySize *= (desc.array_desc_bounds[i].array_bound_upper -
781  desc.array_desc_bounds[i].array_bound_lower + 1);
782  }
783 
784  /* varying arrayelements are stored with 2 trailing null bytes
785  indicating the length of the string
786  */
787  if (desc.array_desc_dtype == blr_varying ||
788  desc.array_desc_dtype == blr_varying2)
789  desc.array_desc_length += 2;
790 
791  bufLen = desc.array_desc_length * arraySize;
792  QByteArray ba;
793  ba.resize(int(bufLen));
794 
795  if (list.size() > arraySize) {
796  error = QLatin1String("Array size missmatch: size of %1 is %2, size of provided list is %3");
797  error = error.arg(QLatin1String(sqlname)).arg(arraySize).arg(list.size());
799  return false;
800  }
801 
802  if (!createArrayBuffer(ba.data(), list,
803  qIBaseTypeName(desc.array_desc_dtype, inda->sqlvar[column].sqlscale < 0),
804  0, &desc, error, tc)) {
805  q->setLastError(QSqlError(error.arg(QLatin1String(sqlname)), QLatin1String(""),
807  return false;
808  }
809 
810  /* readjust the buffer size*/
811  if (desc.array_desc_dtype == blr_varying
812  || desc.array_desc_dtype == blr_varying2)
813  desc.array_desc_length -= 2;
814 
815  isc_array_put_slice(status, &ibase, &trans, arrayId, &desc, ba.data(), &bufLen);
816  return true;
817 }
818 
819 
821 {
822  char acBuffer[9];
823  char qType = isc_info_sql_stmt_type;
824  isc_dsql_sql_info(status, &stmt, 1, &qType, sizeof(acBuffer), acBuffer);
825  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get query info"),
827  return false;
828  int iLength = isc_vax_integer(&acBuffer[1], 2);
829  queryType = isc_vax_integer(&acBuffer[3], iLength);
830  return (queryType == isc_info_sql_stmt_select || queryType == isc_info_sql_stmt_exec_procedure);
831 }
832 
834 {
835  if (trans)
836  return true;
837  if (db->d->trans) {
838  localTransaction = false;
839  trans = db->d->trans;
840  return true;
841  }
842  localTransaction = true;
843 
844  isc_start_transaction(status, &trans, 1, &ibase, 0, NULL);
845  if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not start transaction"),
847  return false;
848 
849  return true;
850 }
851 
852 // does nothing if the transaction is on the
853 // driver level
855 {
856  if (!trans)
857  return false;
858  // don't commit driver's transaction, the driver will do it for us
859  if (!localTransaction)
860  return true;
861 
862  isc_commit_transaction(status, &trans);
863  trans = 0;
864  return !isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to commit transaction"),
866 }
867 
869 
871  QSqlCachedResult(db)
872 {
873  d = new QIBaseResultPrivate(this, db);
874 }
875 
877 {
878  delete d;
879 }
880 
881 bool QIBaseResult::prepare(const QString& query)
882 {
883 // qDebug("prepare: %s", qPrintable(query));
884  if (!driver() || !driver()->isOpen() || driver()->isOpenError())
885  return false;
886  d->cleanup();
887  setActive(false);
889 
890  createDA(d->sqlda);
891  if (d->sqlda == (XSQLDA*)0) {
892  qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
893  return false;
894  }
895 
896  createDA(d->inda);
897  if (d->inda == (XSQLDA*)0){
898  qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
899  return false;
900  }
901 
902  if (!d->transaction())
903  return false;
904 
905  isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt);
906  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not allocate statement"),
908  return false;
909  isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0,
910  const_cast<char*>(encodeString(d->tc, query).constData()), FBVERSION, d->sqlda);
911  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not prepare statement"),
913  return false;
914 
915  isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
916  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
917  "Could not describe input statement"), QSqlError::StatementError))
918  return false;
919  if (d->inda->sqld > d->inda->sqln) {
920  enlargeDA(d->inda, d->inda->sqld);
921  if (d->inda == (XSQLDA*)0) {
922  qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
923  return false;
924  }
925 
926  isc_dsql_describe_bind(d->status, &d->stmt, FBVERSION, d->inda);
927  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult",
928  "Could not describe input statement"), QSqlError::StatementError))
929  return false;
930  }
931  initDA(d->inda);
932  if (d->sqlda->sqld > d->sqlda->sqln) {
933  // need more field descriptors
934  enlargeDA(d->sqlda, d->sqlda->sqld);
935  if (d->sqlda == (XSQLDA*)0) {
936  qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
937  return false;
938  }
939 
940  isc_dsql_describe(d->status, &d->stmt, FBVERSION, d->sqlda);
941  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not describe statement"),
943  return false;
944  }
945  initDA(d->sqlda);
946 
947  setSelect(d->isSelect());
948  if (!isSelect()) {
949  free(d->sqlda);
950  d->sqlda = 0;
951  }
952 
953  return true;
954 }
955 
956 
958 {
959  bool ok = true;
960 
961  if (!d->trans)
962  d->transaction();
963 
964  if (!driver() || !driver()->isOpen() || driver()->isOpenError())
965  return false;
966  setActive(false);
968 
969  if (d->inda) {
971  int i;
972  if (values.count() > d->inda->sqld) {
973  qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters",
974  d->inda->sqld, values.count());
975  return false;
976  }
977  int para = 0;
978  for (i = 0; i < values.count(); ++i) {
979  para = i;
980  if (!d->inda->sqlvar[para].sqldata)
981  // skip unknown datatypes
982  continue;
983  const QVariant val(values[i]);
984  if (d->inda->sqlvar[para].sqltype & 1) {
985  if (val.isNull()) {
986  // set null indicator
987  *(d->inda->sqlvar[para].sqlind) = -1;
988  // and set the value to 0, otherwise it would count as empty string.
989  // it seems to be working with just setting sqlind to -1
990  //*((char*)d->inda->sqlvar[para].sqldata) = 0;
991  continue;
992  }
993  // a value of 0 means non-null.
994  *(d->inda->sqlvar[para].sqlind) = 0;
995  }
996  switch(d->inda->sqlvar[para].sqltype & ~1) {
997  case SQL_INT64:
998  if (d->inda->sqlvar[para].sqlscale < 0)
999  *((qint64*)d->inda->sqlvar[para].sqldata) =
1000  (qint64)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
1001  else
1002  *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
1003  break;
1004  case SQL_LONG:
1005  if (d->inda->sqlvar[para].sqlscale < 0)
1006  *((long*)d->inda->sqlvar[para].sqldata) =
1007  (long)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
1008  else
1009  *((long*)d->inda->sqlvar[para].sqldata) = (long)val.toLongLong();
1010  break;
1011  case SQL_SHORT:
1012  if (d->inda->sqlvar[para].sqlscale < 0)
1013  *((short*)d->inda->sqlvar[para].sqldata) =
1014  (short)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
1015  else
1016  *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();
1017  break;
1018  case SQL_FLOAT:
1019  *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();
1020  break;
1021  case SQL_DOUBLE:
1022  *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();
1023  break;
1024  case SQL_TIMESTAMP:
1025  *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
1026  break;
1027  case SQL_TYPE_TIME:
1028  *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
1029  break;
1030  case SQL_TYPE_DATE:
1031  *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());
1032  break;
1033  case SQL_VARYING:
1034  case SQL_TEXT:
1035  qFillBufferWithString(d->inda->sqlvar[para].sqldata, val.toString(),
1036  d->inda->sqlvar[para].sqllen,
1037  (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false, d->tc);
1038  break;
1039  case SQL_BLOB:
1040  ok &= d->writeBlob(para, val.toByteArray());
1041  break;
1042  case SQL_ARRAY:
1043  ok &= d->writeArray(para, val.toList());
1044  break;
1045  default:
1046  qWarning("QIBaseResult::exec: Unknown datatype %d",
1047  d->inda->sqlvar[para].sqltype & ~1);
1048  break;
1049  }
1050  }
1051  }
1052 
1053  if (ok) {
1054  if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) {
1055  isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
1056  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement")))
1057  return false;
1058  cleanup();
1059  }
1060  if (d->queryType == isc_info_sql_stmt_exec_procedure)
1061  isc_dsql_execute2(d->status, &d->trans, &d->stmt, FBVERSION, d->inda, d->sqlda);
1062  else
1063  isc_dsql_execute(d->status, &d->trans, &d->stmt, FBVERSION, d->inda);
1064  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to execute query")))
1065  return false;
1066 
1067  // Not all stored procedures necessarily return values.
1068  if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda && d->sqlda->sqld == 0)
1069  delDA(d->sqlda);
1070 
1071  if (d->sqlda)
1072  init(d->sqlda->sqld);
1073 
1074  if (!isSelect())
1075  d->commit();
1076 
1077  setActive(true);
1078  return true;
1079  }
1080  return false;
1081 }
1082 
1083 bool QIBaseResult::reset (const QString& query)
1084 {
1085  if (!prepare(query))
1086  return false;
1087  return exec();
1088 }
1089 
1091 {
1092  ISC_STATUS stat = 0;
1093 
1094  // Stored Procedures are special - they populate our d->sqlda when executing,
1095  // so we don't have to call isc_dsql_fetch
1096  if (d->queryType == isc_info_sql_stmt_exec_procedure) {
1097  // the first "fetch" shall succeed, all consecutive ones will fail since
1098  // we only have one row to fetch for stored procedures
1099  if (rowIdx != 0)
1100  stat = 100;
1101  } else {
1102  stat = isc_dsql_fetch(d->status, &d->stmt, FBVERSION, d->sqlda);
1103  }
1104 
1105  if (stat == 100) {
1106  // no more rows
1108  return false;
1109  }
1110  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not fetch next item"),
1112  return false;
1113  if (rowIdx < 0) // not interested in actual values
1114  return true;
1115 
1116  for (int i = 0; i < d->sqlda->sqld; ++i) {
1117  int idx = rowIdx + i;
1118  char *buf = d->sqlda->sqlvar[i].sqldata;
1119  int size = d->sqlda->sqlvar[i].sqllen;
1120  Q_ASSERT(buf);
1121 
1122  if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) {
1123  // null value
1124  QVariant v;
1125  v.convert(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype, d->sqlda->sqlvar[i].sqlscale < 0));
1126  if(v.type() == QVariant::Double) {
1127  switch(numericalPrecisionPolicy()) {
1130  break;
1133  break;
1134  case QSql::HighPrecision:
1136  break;
1137  }
1138  }
1139  row[idx] = v;
1140  continue;
1141  }
1142 
1143  switch(d->sqlda->sqlvar[i].sqltype & ~1) {
1144  case SQL_VARYING:
1145  // pascal strings - a short with a length information followed by the data
1146  if (d->tc)
1147  row[idx] = d->tc->toUnicode(buf + sizeof(short), *(short*)buf);
1148  else
1149  row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
1150  break;
1151  case SQL_INT64:
1152  if (d->sqlda->sqlvar[i].sqlscale < 0)
1153  row[idx] = *(qint64*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
1154  else
1155  row[idx] = QVariant(*(qint64*)buf);
1156  break;
1157  case SQL_LONG:
1158  if (d->sqlda->sqlvar[i].sqllen == 4)
1159  if (d->sqlda->sqlvar[i].sqlscale < 0)
1160  row[idx] = QVariant(*(qint32*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
1161  else
1162  row[idx] = QVariant(*(qint32*)buf);
1163  else
1164  row[idx] = QVariant(*(qint64*)buf);
1165  break;
1166  case SQL_SHORT:
1167  if (d->sqlda->sqlvar[i].sqlscale < 0)
1168  row[idx] = QVariant(long((*(short*)buf)) * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
1169  else
1170  row[idx] = QVariant(int((*(short*)buf)));
1171  break;
1172  case SQL_FLOAT:
1173  row[idx] = QVariant(double((*(float*)buf)));
1174  break;
1175  case SQL_DOUBLE:
1176  row[idx] = QVariant(*(double*)buf);
1177  break;
1178  case SQL_TIMESTAMP:
1179  row[idx] = fromTimeStamp(buf);
1180  break;
1181  case SQL_TYPE_TIME:
1182  row[idx] = fromTime(buf);
1183  break;
1184  case SQL_TYPE_DATE:
1185  row[idx] = fromDate(buf);
1186  break;
1187  case SQL_TEXT:
1188  if (d->tc)
1189  row[idx] = d->tc->toUnicode(buf, size);
1190  else
1191  row[idx] = QString::fromUtf8(buf, size);
1192  break;
1193  case SQL_BLOB:
1194  row[idx] = d->fetchBlob((ISC_QUAD*)buf);
1195  break;
1196  case SQL_ARRAY:
1197  row[idx] = d->fetchArray(i, (ISC_QUAD*)buf);
1198  break;
1199  default:
1200  // unknown type - don't even try to fetch
1201  row[idx] = QVariant();
1202  break;
1203  }
1204  if (d->sqlda->sqlvar[i].sqlscale < 0) {
1205  QVariant v = row[idx];
1206  switch(numericalPrecisionPolicy()) {
1208  if(v.convert(QVariant::Int))
1209  row[idx]=v;
1210  break;
1213  row[idx]=v;
1214  break;
1216  if(v.convert(QVariant::Double))
1217  row[idx]=v;
1218  break;
1219  case QSql::HighPrecision:
1220  if(v.convert(QVariant::String))
1221  row[idx]=v;
1222  break;
1223  }
1224  }
1225  }
1226 
1227  return true;
1228 }
1229 
1231 {
1232  return -1;
1233 
1234 #if 0
1235  static char sizeInfo[] = {isc_info_sql_records};
1236  char buf[64];
1237 
1238  //qDebug() << sizeInfo;
1239  if (!isActive() || !isSelect())
1240  return -1;
1241 
1242  char ct;
1243  short len;
1244  int val = 0;
1245 // while(val == 0) {
1246  isc_dsql_sql_info(d->status, &d->stmt, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
1247 // isc_database_info(d->status, &d->ibase, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf);
1248 
1249  for(int i = 0; i < 66; ++i)
1250  qDebug() << QString::number(buf[i]);
1251 
1252  for (char* c = buf + 3; *c != isc_info_end; /*nothing*/) {
1253  ct = *(c++);
1254  len = isc_vax_integer(c, 2);
1255  c += 2;
1256  val = isc_vax_integer(c, len);
1257  c += len;
1258  qDebug() << "size" << val;
1259  if (ct == isc_info_req_select_count)
1260  return val;
1261  }
1262  //qDebug() << "size -1";
1263  return -1;
1264 
1265  unsigned int i, result_size;
1266  if (buf[0] == isc_info_sql_records) {
1267  i = 3;
1268  result_size = isc_vax_integer(&buf[1],2);
1269  while (buf[i] != isc_info_end && i < result_size) {
1270  len = (short)isc_vax_integer(&buf[i+1],2);
1271  if (buf[i] == isc_info_req_select_count)
1272  return (isc_vax_integer(&buf[i+3],len));
1273  i += len+3;
1274  }
1275  }
1276 // }
1277  return -1;
1278 #endif
1279 }
1280 
1282 {
1283  static char acCountInfo[] = {isc_info_sql_records};
1284  char cCountType;
1285 
1286  switch (d->queryType) {
1287  case isc_info_sql_stmt_select:
1288  cCountType = isc_info_req_select_count;
1289  break;
1290  case isc_info_sql_stmt_update:
1291  cCountType = isc_info_req_update_count;
1292  break;
1293  case isc_info_sql_stmt_delete:
1294  cCountType = isc_info_req_delete_count;
1295  break;
1296  case isc_info_sql_stmt_insert:
1297  cCountType = isc_info_req_insert_count;
1298  break;
1299  default:
1300  qWarning() << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
1301  return -1;
1302  }
1303 
1304  char acBuffer[33];
1305  int iResult = -1;
1306  isc_dsql_sql_info(d->status, &d->stmt, sizeof(acCountInfo), acCountInfo, sizeof(acBuffer), acBuffer);
1307  if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get statement info"),
1309  return -1;
1310  for (char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; /*nothing*/) {
1311  char cType = *pcBuf++;
1312  short sLength = isc_vax_integer (pcBuf, 2);
1313  pcBuf += 2;
1314  int iValue = isc_vax_integer (pcBuf, sLength);
1315  pcBuf += sLength;
1316 
1317  if (cType == cCountType) {
1318  iResult = iValue;
1319  break;
1320  }
1321  }
1322  return iResult;
1323 }
1324 
1326 {
1327  QSqlRecord rec;
1328  if (!isActive() || !d->sqlda)
1329  return rec;
1330 
1331  XSQLVAR v;
1332  for (int i = 0; i < d->sqlda->sqld; ++i) {
1333  v = d->sqlda->sqlvar[i];
1334  QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
1335  qIBaseTypeName2(v.sqltype, v.sqlscale < 0));
1336  f.setLength(v.sqllen);
1337  f.setPrecision(qAbs(v.sqlscale));
1338  f.setRequiredStatus((v.sqltype & 1) == 0 ? QSqlField::Required : QSqlField::Optional);
1339  if(v.sqlscale < 0) {
1340  QSqlQuery q(new QIBaseResult(d->db));
1341  q.setForwardOnly(true);
1342  q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, a.RDB$NULL_FLAG "
1343  "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1344  "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1345  "AND a.RDB$RELATION_NAME = '") + QString::fromAscii(v.relname, v.relname_length).toUpper() + QLatin1String("' "
1346  "AND a.RDB$FIELD_NAME = '") + QString::fromAscii(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
1347  if(q.first()) {
1348  if(v.sqlscale < 0) {
1349  f.setLength(q.value(0).toInt());
1350  f.setPrecision(qAbs(q.value(1).toInt()));
1351  } else {
1352  f.setLength(q.value(2).toInt());
1353  f.setPrecision(0);
1354  }
1355  f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
1356  }
1357  }
1358  f.setSqlType(v.sqltype);
1359  rec.append(f);
1360  }
1361  return rec;
1362 }
1363 
1365 {
1366  return QVariant(qRegisterMetaType<isc_stmt_handle>("isc_stmt_handle"), &d->stmt);
1367 }
1368 
1369 /*********************************/
1370 
1372  : QSqlDriver(parent)
1373 {
1374  d = new QIBaseDriverPrivate(this);
1375 }
1376 
1377 QIBaseDriver::QIBaseDriver(isc_db_handle connection, QObject *parent)
1378  : QSqlDriver(parent)
1379 {
1380  d = new QIBaseDriverPrivate(this);
1381  d->ibase = connection;
1382  setOpen(true);
1383  setOpenError(false);
1384 }
1385 
1387 {
1388  delete d;
1389 }
1390 
1392 {
1393  switch (f) {
1394  case QuerySize:
1395  case NamedPlaceholders:
1396  case LastInsertId:
1397  case BatchOperations:
1398  case SimpleLocking:
1399  case FinishQuery:
1400  case MultipleResultSets:
1401  return false;
1402  case Transactions:
1403  case PreparedQueries:
1405  case Unicode:
1406  case BLOB:
1407  case EventNotifications:
1408  case LowPrecisionNumbers:
1409  return true;
1410  }
1411  return false;
1412 }
1413 
1414 bool QIBaseDriver::open(const QString & db,
1415  const QString & user,
1416  const QString & password,
1417  const QString & host,
1418  int /*port*/,
1419  const QString & connOpts)
1420 {
1421  if (isOpen())
1422  close();
1423 
1424  const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts));
1425 
1426  QString encString;
1427  QByteArray role;
1428  for (int i = 0; i < opts.count(); ++i) {
1429  QString tmp(opts.at(i).simplified());
1430  int idx;
1431  if ((idx = tmp.indexOf(QLatin1Char('='))) != -1) {
1432  QString val = tmp.mid(idx + 1).simplified();
1433  QString opt = tmp.left(idx).simplified();
1434  if (opt.toUpper() == QLatin1String("ISC_DPB_LC_CTYPE"))
1435  encString = val;
1436  else if (opt.toUpper() == QLatin1String("ISC_DPB_SQL_ROLE_NAME")) {
1437  role = val.toLocal8Bit();
1438  role.truncate(255);
1439  }
1440  }
1441  }
1442 
1443  // Use UNICODE_FSS when no ISC_DPB_LC_CTYPE is provided
1444  if (encString.isEmpty())
1445  encString = QLatin1String("UNICODE_FSS");
1446  else {
1447  d->tc = QTextCodec::codecForName(encString.toLocal8Bit());
1448  if (!d->tc) {
1449  qWarning("Unsupported encoding: %s. Using UNICODE_FFS for ISC_DPB_LC_CTYPE.", encString.toLocal8Bit().constData());
1450  encString = QLatin1String("UNICODE_FSS"); // Fallback to UNICODE_FSS
1451  }
1452  }
1453 
1454  QByteArray enc = encString.toLocal8Bit();
1455  QByteArray usr = user.toLocal8Bit();
1456  QByteArray pass = password.toLocal8Bit();
1457  enc.truncate(255);
1458  usr.truncate(255);
1459  pass.truncate(255);
1460 
1461  QByteArray ba;
1462  ba.reserve(usr.length() + pass.length() + enc.length() + role.length() + 9);
1463  ba.append(char(isc_dpb_version1));
1464  ba.append(char(isc_dpb_user_name));
1465  ba.append(char(usr.length()));
1466  ba.append(usr.data(), usr.length());
1467  ba.append(char(isc_dpb_password));
1468  ba.append(char(pass.length()));
1469  ba.append(pass.data(), pass.length());
1470  ba.append(char(isc_dpb_lc_ctype));
1471  ba.append(char(enc.length()));
1472  ba.append(enc.data(), enc.length());
1473 
1474  if (!role.isEmpty()) {
1475  ba.append(char(isc_dpb_sql_role_name));
1476  ba.append(char(role.length()));
1477  ba.append(role.data(), role.length());
1478  }
1479 
1480  QString ldb;
1481  if (!host.isEmpty())
1482  ldb += host + QLatin1Char(':');
1483  ldb += db;
1484  isc_attach_database(d->status, 0, const_cast<char *>(ldb.toLocal8Bit().constData()),
1485  &d->ibase, ba.size(), ba.data());
1486  if (d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Error opening database"),
1488  setOpenError(true);
1489  return false;
1490  }
1491 
1492  setOpen(true);
1493  return true;
1494 }
1495 
1497 {
1498  if (isOpen()) {
1499 
1500  if (d->eventBuffers.size()) {
1501  ISC_STATUS status[20];
1503  for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
1504  QIBaseEventBuffer *eBuffer = i.value();
1506  isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
1507  qFreeEventBuffer(eBuffer);
1508  }
1509  d->eventBuffers.clear();
1510 
1511 #if defined(FB_API_VER)
1512  // Workaround for Firebird crash
1513  QTime timer;
1514  timer.start();
1515  while (timer.elapsed() < 500)
1517 #endif
1518  }
1519 
1520  isc_detach_database(d->status, &d->ibase);
1521  d->ibase = 0;
1522  setOpen(false);
1523  setOpenError(false);
1524  }
1525 }
1526 
1528 {
1529  return new QIBaseResult(this);
1530 }
1531 
1533 {
1534  if (!isOpen() || isOpenError())
1535  return false;
1536  if (d->trans)
1537  return false;
1538 
1539  isc_start_transaction(d->status, &d->trans, 1, &d->ibase, 0, NULL);
1540  return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Could not start transaction"),
1542 }
1543 
1545 {
1546  if (!isOpen() || isOpenError())
1547  return false;
1548  if (!d->trans)
1549  return false;
1550 
1551  isc_commit_transaction(d->status, &d->trans);
1552  d->trans = 0;
1553  return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to commit transaction"),
1555 }
1556 
1558 {
1559  if (!isOpen() || isOpenError())
1560  return false;
1561  if (!d->trans)
1562  return false;
1563 
1564  isc_rollback_transaction(d->status, &d->trans);
1565  d->trans = 0;
1566  return !d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Unable to rollback transaction"),
1568 }
1569 
1571 {
1572  QStringList res;
1573  if (!isOpen())
1574  return res;
1575 
1576  QString typeFilter;
1577 
1578  if (type == QSql::SystemTables) {
1579  typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0");
1580  } else if (type == (QSql::SystemTables | QSql::Views)) {
1581  typeFilter += QLatin1String("RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL");
1582  } else {
1583  if (!(type & QSql::SystemTables))
1584  typeFilter += QLatin1String("RDB$SYSTEM_FLAG = 0 AND ");
1585  if (!(type & QSql::Views))
1586  typeFilter += QLatin1String("RDB$VIEW_BLR IS NULL AND ");
1587  if (!(type & QSql::Tables))
1588  typeFilter += QLatin1String("RDB$VIEW_BLR IS NOT NULL AND ");
1589  if (!typeFilter.isEmpty())
1590  typeFilter.chop(5);
1591  }
1592  if (!typeFilter.isEmpty())
1593  typeFilter.prepend(QLatin1String("where "));
1594 
1595  QSqlQuery q(createResult());
1596  q.setForwardOnly(true);
1597  if (!q.exec(QLatin1String("select rdb$relation_name from rdb$relations ") + typeFilter))
1598  return res;
1599  while(q.next())
1600  res << q.value(0).toString().simplified();
1601 
1602  return res;
1603 }
1604 
1605 QSqlRecord QIBaseDriver::record(const QString& tablename) const
1606 {
1607  QSqlRecord rec;
1608  if (!isOpen())
1609  return rec;
1610 
1611  QSqlQuery q(createResult());
1612  q.setForwardOnly(true);
1613  QString table = tablename;
1615  table = stripDelimiters(table, QSqlDriver::TableName);
1616  else
1617  table = table.toUpper();
1618  q.exec(QLatin1String("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
1619  "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
1620  "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
1621  "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE "
1622  "AND a.RDB$RELATION_NAME = '") + table + QLatin1String("' "
1623  "ORDER BY a.RDB$FIELD_POSITION"));
1624 
1625  while (q.next()) {
1626  int type = q.value(1).toInt();
1627  bool hasScale = q.value(3).toInt() < 0;
1628  QSqlField f(q.value(0).toString().simplified(), qIBaseTypeName(type, hasScale));
1629  if(hasScale) {
1630  f.setLength(q.value(4).toInt());
1631  f.setPrecision(qAbs(q.value(3).toInt()));
1632  } else {
1633  f.setLength(q.value(2).toInt());
1634  f.setPrecision(0);
1635  }
1636  f.setRequired(q.value(5).toInt() > 0 ? true : false);
1637  f.setSqlType(type);
1638 
1639  rec.append(f);
1640  }
1641  return rec;
1642 }
1643 
1645 {
1646  QSqlIndex index(table);
1647  if (!isOpen())
1648  return index;
1649 
1650  QString tablename = table;
1652  tablename = stripDelimiters(tablename, QSqlDriver::TableName);
1653  else
1654  tablename = tablename.toUpper();
1655 
1656  QSqlQuery q(createResult());
1657  q.setForwardOnly(true);
1658  q.exec(QLatin1String("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
1659  "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d "
1660  "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' "
1661  "AND a.RDB$RELATION_NAME = '") + tablename +
1662  QLatin1String(" 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME "
1663  "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME "
1664  "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME "
1665  "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE "
1666  "ORDER BY b.RDB$FIELD_POSITION"));
1667 
1668  while (q.next()) {
1669  QSqlField field(q.value(1).toString().simplified(), qIBaseTypeName(q.value(2).toInt(), q.value(3).toInt() < 0));
1670  index.append(field); //TODO: asc? desc?
1671  index.setName(q.value(0).toString());
1672  }
1673 
1674  return index;
1675 }
1676 
1677 QString QIBaseDriver::formatValue(const QSqlField &field, bool trimStrings) const
1678 {
1679  switch (field.type()) {
1680  case QVariant::DateTime: {
1681  QDateTime datetime = field.value().toDateTime();
1682  if (datetime.isValid())
1683  return QLatin1Char('\'') + QString::number(datetime.date().year()) + QLatin1Char('-') +
1684  QString::number(datetime.date().month()) + QLatin1Char('-') +
1685  QString::number(datetime.date().day()) + QLatin1Char(' ') +
1686  QString::number(datetime.time().hour()) + QLatin1Char(':') +
1687  QString::number(datetime.time().minute()) + QLatin1Char(':') +
1688  QString::number(datetime.time().second()) + QLatin1Char('.') +
1689  QString::number(datetime.time().msec()).rightJustified(3, QLatin1Char('0'), true) +
1690  QLatin1Char('\'');
1691  else
1692  return QLatin1String("NULL");
1693  }
1694  case QVariant::Time: {
1695  QTime time = field.value().toTime();
1696  if (time.isValid())
1697  return QLatin1Char('\'') + QString::number(time.hour()) + QLatin1Char(':') +
1698  QString::number(time.minute()) + QLatin1Char(':') +
1699  QString::number(time.second()) + QLatin1Char('.') +
1700  QString::number(time.msec()).rightJustified(3, QLatin1Char('0'), true) +
1701  QLatin1Char('\'');
1702  else
1703  return QLatin1String("NULL");
1704  }
1705  case QVariant::Date: {
1706  QDate date = field.value().toDate();
1707  if (date.isValid())
1708  return QLatin1Char('\'') + QString::number(date.year()) + QLatin1Char('-') +
1709  QString::number(date.month()) + QLatin1Char('-') +
1710  QString::number(date.day()) + QLatin1Char('\'');
1711  else
1712  return QLatin1String("NULL");
1713  }
1714  default:
1715  return QSqlDriver::formatValue(field, trimStrings);
1716  }
1717 }
1718 
1720 {
1721  return QVariant(qRegisterMetaType<isc_db_handle>("isc_db_handle"), &d->ibase);
1722 }
1723 
1724 #if defined(FB_API_VER) && FB_API_VER >= 20
1725 static ISC_EVENT_CALLBACK qEventCallback(char *result, ISC_USHORT length, const ISC_UCHAR *updated)
1726 #else
1727 static isc_callback qEventCallback(char *result, short length, char *updated)
1728 #endif
1729 {
1730  if (!updated)
1731  return 0;
1732 
1733 
1734  memcpy(result, updated, length);
1735  qMutex()->lock();
1736  QIBaseDriver *driver = qBufferDriverMap()->value(result);
1737  qMutex()->unlock();
1738 
1739  // We use an asynchronous call (i.e., queued connection) because the event callback
1740  // is executed in a different thread than the one in which the driver lives.
1741  if (driver)
1742  QMetaObject::invokeMethod(driver, "qHandleEventNotification", Qt::QueuedConnection, Q_ARG(void *, reinterpret_cast<void *>(result)));
1743 
1744  return 0;
1745 }
1746 
1748 {
1749  if (!isOpen()) {
1750  qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
1751  return false;
1752  }
1753 
1754  if (d->eventBuffers.contains(name)) {
1755  qWarning("QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
1756  qPrintable(name));
1757  return false;
1758  }
1759 
1760  QIBaseEventBuffer *eBuffer = new QIBaseEventBuffer;
1762  eBuffer->bufferLength = isc_event_block(&eBuffer->eventBuffer,
1763  &eBuffer->resultBuffer,
1764  1,
1765  name.toLocal8Bit().constData());
1766 
1767  qMutex()->lock();
1768  qBufferDriverMap()->insert(eBuffer->resultBuffer, this);
1769  qMutex()->unlock();
1770 
1771  d->eventBuffers.insert(name, eBuffer);
1772 
1773  ISC_STATUS status[20];
1774  isc_que_events(status,
1775  &d->ibase,
1776  &eBuffer->eventId,
1777  eBuffer->bufferLength,
1778  eBuffer->eventBuffer,
1779 #if defined (FB_API_VER) && FB_API_VER >= 20
1780  (ISC_EVENT_CALLBACK)qEventCallback,
1781 #else
1782  (isc_callback)qEventCallback,
1783 #endif
1784  eBuffer->resultBuffer);
1785 
1786  if (status[0] == 1 && status[1]) {
1787  setLastError(QSqlError(QString::fromLatin1("Could not subscribe to event notifications for %1.").arg(name)));
1788  d->eventBuffers.remove(name);
1789  qFreeEventBuffer(eBuffer);
1790  return false;
1791  }
1792 
1793  return true;
1794 }
1795 
1797 {
1798  if (!isOpen()) {
1799  qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
1800  return false;
1801  }
1802 
1803  if (!d->eventBuffers.contains(name)) {
1804  qWarning("QIBaseDriver::QIBaseSubscriptionState not subscribed to '%s'.",
1805  qPrintable(name));
1806  return false;
1807  }
1808 
1809  QIBaseEventBuffer *eBuffer = d->eventBuffers.value(name);
1810  ISC_STATUS status[20];
1812  isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
1813 
1814  if (status[0] == 1 && status[1]) {
1815  setLastError(QSqlError(QString::fromLatin1("Could not unsubscribe from event notifications for %1.").arg(name)));
1816  return false;
1817  }
1818 
1819  d->eventBuffers.remove(name);
1820  qFreeEventBuffer(eBuffer);
1821 
1822  return true;
1823 }
1824 
1826 {
1827  return QStringList(d->eventBuffers.keys());
1828 }
1829 
1830 void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
1831 {
1833  for (i = d->eventBuffers.constBegin(); i != d->eventBuffers.constEnd(); ++i) {
1834  QIBaseEventBuffer* eBuffer = i.value();
1835  if (reinterpret_cast<void *>(eBuffer->resultBuffer) != updatedResultBuffer)
1836  continue;
1837 
1838  ISC_ULONG counts[20];
1839  memset(counts, 0, sizeof(counts));
1840  isc_event_counts(counts, eBuffer->bufferLength, eBuffer->eventBuffer, eBuffer->resultBuffer);
1841  if (counts[0]) {
1842 
1844  emit notification(i.key());
1845  else if (eBuffer->subscriptionState == QIBaseEventBuffer::Starting)
1847 
1848  ISC_STATUS status[20];
1849  isc_que_events(status,
1850  &d->ibase,
1851  &eBuffer->eventId,
1852  eBuffer->bufferLength,
1853  eBuffer->eventBuffer,
1854 #if defined (FB_API_VER) && FB_API_VER >= 20
1855  (ISC_EVENT_CALLBACK)qEventCallback,
1856 #else
1857  (isc_callback)qEventCallback,
1858 #endif
1859  eBuffer->resultBuffer);
1860  if (status[0] == 1 && status[1]) {
1861  qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%s'",
1862  qPrintable(i.key()));
1863  }
1864 
1865  return;
1866  }
1867  }
1868 }
1869 
1871 {
1872  QString res = identifier;
1873  if(!identifier.isEmpty() && !identifier.startsWith(QLatin1Char('"')) && !identifier.endsWith(QLatin1Char('"')) ) {
1874  res.replace(QLatin1Char('"'), QLatin1String("\"\""));
1875  res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
1876  res.replace(QLatin1Char('.'), QLatin1String("\".\""));
1877  }
1878  return res;
1879 }
1880 
QVariant fetchBlob(ISC_QUAD *bId)
Definition: qsql_ibase.cpp:437
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
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
double d
Definition: qnumeric_p.h:62
const QSqlDriver * driver() const
Returns the driver associated with the result.
Definition: qsqlresult.cpp:389
isc_tr_handle trans
Definition: qsql_ibase.cpp:381
int type
Definition: qmetatype.cpp:239
void truncate(int pos)
Truncates the byte array at index position pos.
#define FBVERSION
Definition: qsql_ibase.cpp:62
bool isActive() const
Returns true if the result has records to be retrieved; otherwise returns false.
Definition: qsqlresult.cpp:340
int daysTo(const QDate &) const
Returns the number of days from this date to d (which is negative if d is earlier than this date)...
Definition: qdatetime.cpp:1111
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
QIBaseDriverPrivate * d
Definition: qsql_ibase.h:125
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool first()
Retrieves the first record in the result, if available, and positions the query on the retrieved reco...
Definition: qsqlquery.cpp:678
int qint32
Definition: qglobal.h:937
static ISC_DATE toDate(const QDate &t)
Definition: qsql_ibase.cpp:268
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
virtual void setOpen(bool o)
This function sets the open state of the database to open.
Definition: qsqldriver.cpp:283
bool gotoNext(QSqlCachedResult::ValueCache &row, int rowIdx)
char * fillList< float >(char *buffer, const QList< QVariant > &list, float *)
Definition: qsql_ibase.cpp:637
static char * qFillBufferWithString(char *buffer, const QString &string, short buflen, bool varying, bool array, QTextCodec *tc)
Definition: qsql_ibase.cpp:650
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
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QSqlRecord record() const
Returns the current record if the query is active; otherwise returns an empty QSqlRecord.
QIBaseResult * q
Definition: qsql_ibase.cpp:378
isc_tr_handle trans
Definition: qsql_ibase.cpp:331
DriverFeature
This enum contains a list of features a driver might support.
Definition: qsqldriver.h:75
QList< QVariant > toList< long >(char **buf, int count, long *)
Definition: qsql_ibase.cpp:483
bool isValid() const
Returns true if this date is valid; otherwise returns false.
Definition: qdatetime.cpp:340
bool commitTransaction()
This function is called to commit a transaction.
bool isNull() const
Returns true if this is a NULL variant, false otherwise.
Definition: qvariant.cpp:3102
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
QByteArray & append(char c)
Appends the character ch to this byte array.
void append(const QSqlField &field)
Appends the field field to the list of indexed fields.
Definition: qsqlindex.cpp:129
#define iType(varName, parent)
void start()
Sets this time to the current time.
Definition: qdatetime.cpp:2070
QVariant value() const
Returns the value of the field as a QVariant.
Definition: qsqlfield.h:71
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
int msecsTo(const QTime &) const
Returns the number of milliseconds from this time to t.
Definition: qdatetime.cpp:1832
#define error(msg)
QString & replace(int i, int len, QChar after)
Definition: qstring.cpp:2005
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void chop(int n)
Removes n characters from the end of the string.
Definition: qstring.cpp:4623
QString & prepend(QChar c)
Definition: qstring.h:261
QString toUpper() const Q_REQUIRED_RESULT
Returns an uppercase copy of the string.
Definition: qstring.cpp:5483
QIBaseDriver * q
Definition: qsql_ibase.cpp:329
int month() const
Returns the number corresponding to the month of this date, using the following convention: ...
Definition: qdatetime.cpp:382
The QSqlQuery class provides a means of executing and manipulating SQL statements.
Definition: qsqlquery.h:63
virtual ~QIBaseResult()
Definition: qsql_ibase.cpp:876
bool rollbackTransaction()
This function is called to rollback a transaction.
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
int size() const
Returns the number of (key, value) pairs in the map.
Definition: qmap.h:201
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has type() DateTime , Date , or String ; otherwise ...
Definition: qvariant.cpp:2349
static char * createArrayBuffer(char *buffer, const QList< QVariant > &list, QVariant::Type type, short curDim, ISC_ARRAY_DESC *arrayDesc, QString &error, QTextCodec *tc)
Definition: qsql_ibase.cpp:675
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
int day() const
Returns the day of the month (1 to 31) of this date.
Definition: qdatetime.cpp:395
bool exec()
Executes the query, returning true if successful; otherwise returns false.
Definition: qsql_ibase.cpp:957
QList< QVariant > toList() const
Returns the variant as a QVariantList if the variant has type() List or StringList ; otherwise return...
Definition: qvariant.cpp:2751
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
#define Q_ARG(type, data)
Definition: qobjectdefs.h:246
bool isValid() const
Returns true if both the date and the time are valid; otherwise returns false.
Definition: qdatetime.cpp:2346
#define QT_TRANSLATE_NOOP(scope, x)
Marks the string literal sourceText for dynamic translation in the given context; i...
Definition: qglobal.h:2487
The QDate class provides date functions.
Definition: qdatetime.h:55
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool toBool() const
Returns the variant as a bool if the variant has type() Bool.
Definition: qvariant.cpp:2691
int msec() const
Returns the millisecond part (0 to 999) of the time.
Definition: qdatetime.cpp:1611
const Key & key() const
Returns the current item&#39;s key.
Definition: qmap.h:324
bool unsubscribeFromNotificationImplementation(const QString &name)
const QIBaseDriver * db
Definition: qsql_ibase.cpp:379
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
EventLoopTimerRef timer
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
static char * readArrayBuffer(QList< QVariant > &list, char *buffer, short curDim, short *numElements, ISC_ARRAY_DESC *arrayDesc, QTextCodec *tc)
Definition: qsql_ibase.cpp:496
static QList< QVariant > toList(char **buf, int count, T *=0)
Definition: qsql_ibase.cpp:472
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
QVariant fetchArray(int pos, ISC_QUAD *arr)
Definition: qsql_ibase.cpp:571
bool hasFeature(DriverFeature f) const
Returns true if the driver supports feature feature; otherwise returns false.
isc_db_handle ibase
Definition: qsql_ibase.cpp:385
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has type() ByteArray or String (converted using QS...
Definition: qvariant.cpp:2383
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Processes all pending events for the calling thread according to the specified flags until there are ...
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
static QDateTime fromTimeStamp(char *buffer)
Definition: qsql_ibase.cpp:238
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
bool isOpenError() const
Returns true if the there was an error opening the database connection; otherwise returns false...
Definition: qsqldriver.cpp:192
ErrorType
This enum type describes the context in which the error occurred, e.
Definition: qsqlerror.h:56
Q_CORE_EXPORT void qDebug(const char *,...)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
static QTime fromTime(char *buffer)
Definition: qsql_ibase.cpp:258
QSqlRecord record(const QString &tablename) const
Returns a QSqlRecord populated with the names of the fields in table tableName.
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#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...
static bool getIBaseError(QString &msg, ISC_STATUS *status, ISC_LONG &sqlcode, QTextCodec *tc)
Definition: qsql_ibase.cpp:73
virtual ~QIBaseDriver()
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
QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb)
Definition: qsql_ibase.cpp:393
ISC_LONG bufferLength
Definition: qsql_ibase.cpp:304
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
QStringList tables(QSql::TableType) const
Returns a list of the names of the tables in the database.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
ISC_STATUS status[20]
Definition: qsql_ibase.cpp:333
static QByteArray encodeString(QTextCodec *tc, const QString &str)
Definition: qsql_ibase.cpp:289
const char * name
const T value(const Key &key) const
Returns the value associated with the key key.
Definition: qmap.h:499
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
void qHandleEventNotification(void *updatedResultBuffer)
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
QByteArray leftJustified(int width, char fill=' ', bool truncate=false) const
Returns a byte array of size width that contains this byte array padded by the fill character...
static char * fillList(char *buffer, const QList< QVariant > &list, T *=0)
Definition: qsql_ibase.cpp:625
static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
Definition: qsql_ibase.cpp:228
QVariant handle() const
Returns the low-level database handle for this result set wrapped in a QVariant or an invalid QVarian...
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
Q_CORE_EXPORT void qWarning(const char *,...)
int second() const
Returns the second part (0 to 59) of the time.
Definition: qdatetime.cpp:1600
static QVariant::Type qIBaseTypeName(int iType, bool hasScale)
Definition: qsql_ibase.cpp:167
QIBaseDriverPrivate(QIBaseDriver *d)
Definition: qsql_ibase.cpp:314
bool writeArray(int i, const QList< QVariant > &list)
Definition: qsql_ibase.cpp:760
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
Type
This enum type defines the types of variable that a QVariant can contain.
Definition: qvariant.h:95
friend class QIBaseDriverPrivate
Definition: qsql_ibase.h:83
int size()
Returns the size of the SELECT result, or -1 if it cannot be determined or if the query is not a SELE...
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
QList< Key > keys() const
Returns a list containing all the keys in the map in ascending order.
Definition: qmap.h:818
__int64 qint64
Definition: qglobal.h:942
int minute() const
Returns the minute part (0 to 59) of the time.
Definition: qdatetime.cpp:1589
bool writeBlob(int i, const QByteArray &ba)
Definition: qsql_ibase.cpp:417
QString formatValue(const QSqlField &field, bool trimStrings) const
Returns a string representation of the field value for the database.
quint16 values[128]
QVariant::Type type() const
Returns the field&#39;s type as stored in the database.
Definition: qsqlfield.cpp:394
isc_db_handle ibase
Definition: qsql_ibase.cpp:330
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the map.
Definition: qmap.h:374
bool subscribeToNotificationImplementation(const QString &name)
QByteArray toLocal8Bit() const Q_REQUIRED_RESULT
Returns the local 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4049
static void delDA(XSQLDA *&sqlda)
Definition: qsql_ibase.cpp:155
void setForwardOnly(bool forward)
Sets forward only mode to forward.
Definition: qsqlquery.cpp:835
bool convert(Type t)
Casts the variant to the requested type, t.
Definition: qvariant.cpp:2959
QIBaseResult(const QIBaseDriver *db)
Definition: qsql_ibase.cpp:870
int length() const
Same as size().
Definition: qbytearray.h:356
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QDate date() const
Returns the date part of the datetime.
Definition: qdatetime.cpp:2357
QString toUnicode(const QByteArray &) const
Converts a from the encoding of this codec to Unicode, and returns the result in a QString...
int remove(const Key &key)
Removes all the items that have the key key from the map.
Definition: qmap.h:662
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
int elapsed() const
Returns the number of milliseconds that have elapsed since the last time start() or restart() was cal...
Definition: qdatetime.cpp:2123
QDate toDate() const
Returns the variant as a QDate if the variant has type() Date , DateTime , or String ; otherwise retu...
Definition: qvariant.cpp:2311
The QMap::const_iterator class provides an STL-style const iterator for QMap and QMultiMap.
Definition: qmap.h:301
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the map...
Definition: qmap.h:380
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
QStringList subscribedToNotificationsImplementation() const
QString & append(QChar c)
Definition: qstring.cpp:1777
QIBaseResultPrivate * d
Definition: qsql_ibase.h:77
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
static void qFreeEventBuffer(QIBaseEventBuffer *eBuffer)
Definition: qsql_ibase.cpp:341
bool reset(const QString &query)
Sets the result to use the SQL statement query for subsequent data retrieval.
isc_stmt_handle stmt
Definition: qsql_ibase.cpp:384
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
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
QString escapeIdentifier(const QString &identifier, IdentifierType type) const
Returns the identifier escaped according to the database rules.
bool isError(const char *msg, QSqlError::ErrorType typ=QSqlError::UnknownError)
Definition: qsql_ibase.cpp:316
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
iterator insert(const Key &key, const T &value)
Inserts a new item with the key key and a value of value.
Definition: qmap.h:559
QSqlResult * createResult() const
Creates an empty SQL result on the database.
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QMap< void *, QIBaseDriver * > QIBaseBufferDriverMap
Definition: qsql_ibase.cpp:337
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...
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
void resize(int size)
Sets the size of the byte array to size bytes.
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QMap< QString, QIBaseEventBuffer * > eventBuffers
Definition: qsql_ibase.cpp:334
static void cleanup()
Definition: qpicture.cpp:1508
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 wrapped in a QVariant or an invalid variant if there is no hand...
static void enlargeDA(XSQLDA *&sqlda, int n)
Definition: qsql_ibase.cpp:108
const T & value() const
Returns the current item&#39;s value.
Definition: qmap.h:325
static QTextCodec * codecForName(const QByteArray &name)
Searches all installed QTextCodec objects and returns the one which best matches name; the match is c...
bool contains(const Key &key) const
Returns true if the map contains an item with key key; otherwise returns false.
Definition: qmap.h:553
T qvariant_cast(const QVariant &)
Definition: qvariant.h:571
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
double toDouble(bool *ok=0) const
Returns the variant as a double if the variant has type() Double , QMetaType::Float ...
Definition: qvariant.cpp:2710
virtual void setActive(bool a)
This function is provided for derived classes to set the internal active state to active...
Definition: qsqlresult.cpp:402
QSqlIndex primaryIndex(const QString &table) const
Returns the primary index for table tableName.
quint16 index
static const QTextHtmlElement elements[Html_NumElements]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
QIBaseSubscriptionState subscriptionState
Definition: qsql_ibase.cpp:308
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 ISC_TIME toTime(const QTime &t)
Definition: qsql_ibase.cpp:252
int year() const
Returns the year of this date.
Definition: qdatetime.cpp:353
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
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
QTime time() const
Returns the time part of the datetime.
Definition: qdatetime.cpp:2368
void init(int colCount)
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
int numRowsAffected()
Returns the number of rows affected by the last query executed, or -1 if it cannot be determined or i...
Q_GLOBAL_STATIC(QMutex, qMutex)
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
bool isError(const char *msg, QSqlError::ErrorType typ=QSqlError::UnknownError)
Definition: qsql_ibase.cpp:356
void reserve(int size)
Attempts to allocate memory for at least size bytes.
Definition: qbytearray.h:449
#define SQLDA_CURRENT_VERSION
Definition: qsql_ibase.cpp:65
#define qPrintable(string)
Definition: qglobal.h:1750
QVariant value(int i) const
Returns the value of field index in the current record.
Definition: qsqlquery.cpp:403
friend class QIBaseResultPrivate
Definition: qsql_ibase.h:59
QIBaseDriver(QObject *parent=0)
bool beginTransaction()
This function is called to begin a transaction.
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
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
static void initDA(XSQLDA *sqlda)
Definition: qsql_ibase.cpp:118
static QVariant::Type qIBaseTypeName2(int iType, bool hasScale)
Definition: qsql_ibase.cpp:199
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...
bool prepare(const QString &query)
Prepares the given query for execution; the query will normally use placeholders so that it can be ex...
Definition: qsql_ibase.cpp:881
static void createDA(XSQLDA *&sqlda)
Definition: qsql_ibase.cpp:97
void clear()
Removes all items from the map.
Definition: qmap.h:444
static isc_callback qEventCallback(char *result, short length, char *updated)
The QMap class is a template class that provides a skip-list-based dictionary.
Definition: qdatastream.h:67
static QDate fromDate(char *buffer)
Definition: qsql_ibase.cpp:277
Q_CORE_EXPORT void qCritical(const char *,...)
bool isValid() const
Returns true if the time is valid; otherwise returns false.
Definition: qdatetime.cpp:1566
int hour() const
Returns the hour part (0 to 23) of the time.
Definition: qdatetime.cpp:1578
ISC_STATUS status[20]
Definition: qsql_ibase.cpp:380
void notification(const QString &name)
This signal is emitted when the database posts an event notification that the driver subscribes to...