1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qsqlrecord.h"
41 
42 #include "qdebug.h"
43 #include "qstringlist.h"
44 #include "qatomic.h"
45 #include "qsqlfield.h"
46 #include "qstring.h"
47 #include "qvector.h"
48 
49 QT_BEGIN_NAMESPACE
50 
51 class QSqlRecordPrivate
52 {
53 public:
54     QSqlRecordPrivate();
55     QSqlRecordPrivate(const QSqlRecordPrivate &other);
56 
contains(int index)57     inline bool contains(int index) { return index >= 0 && index < fields.count(); }
58     QString createField(int index, const QString &prefix) const;
59 
60     QVector<QSqlField> fields;
61     QAtomicInt ref;
62 };
63 
QSqlRecordPrivate()64 QSqlRecordPrivate::QSqlRecordPrivate() : ref(1)
65 {
66 }
67 
QSqlRecordPrivate(const QSqlRecordPrivate & other)68 QSqlRecordPrivate::QSqlRecordPrivate(const QSqlRecordPrivate &other): fields(other.fields), ref(1)
69 {
70 }
71 
72 /*! \internal
73     Just for compat
74 */
createField(int index,const QString & prefix) const75 QString QSqlRecordPrivate::createField(int index, const QString &prefix) const
76 {
77     QString f;
78     if (!prefix.isEmpty())
79         f = prefix + QLatin1Char('.');
80     f += fields.at(index).name();
81     return f;
82 }
83 
84 /*!
85     \class QSqlRecord
86     \brief The QSqlRecord class encapsulates a database record.
87 
88     \ingroup database
89     \ingroup shared
90     \inmodule QtSql
91 
92     The QSqlRecord class encapsulates the functionality and
93     characteristics of a database record (usually a row in a table or
94     view within the database). QSqlRecord supports adding and
95     removing fields as well as setting and retrieving field values.
96 
97     The values of a record's fields can be set by name or position
98     with setValue(); if you want to set a field to null use
99     setNull(). To find the position of a field by name use indexOf(),
100     and to find the name of a field at a particular position use
101     fieldName(). Use field() to retrieve a QSqlField object for a
102     given field. Use contains() to see if the record contains a
103     particular field name.
104 
105     When queries are generated to be executed on the database only
106     those fields for which isGenerated() is true are included in the
107     generated SQL.
108 
109     A record can have fields added with append() or insert(), replaced
110     with replace(), and removed with remove(). All the fields can be
111     removed with clear(). The number of fields is given by count();
112     all their values can be cleared (to null) using clearValues().
113 
114     \sa QSqlField, QSqlQuery::record()
115 */
116 
117 
118 /*!
119     Constructs an empty record.
120 
121     \sa isEmpty(), append(), insert()
122 */
123 
QSqlRecord()124 QSqlRecord::QSqlRecord()
125 {
126     d = new QSqlRecordPrivate();
127 }
128 
129 /*!
130     Constructs a copy of \a other.
131 
132     QSqlRecord is \l{implicitly shared}. This means you can make copies
133     of a record in \l{constant time}.
134 */
135 
QSqlRecord(const QSqlRecord & other)136 QSqlRecord::QSqlRecord(const QSqlRecord& other)
137 {
138     d = other.d;
139     d->ref.ref();
140 }
141 
142 /*!
143     Sets the record equal to \a other.
144 
145     QSqlRecord is \l{implicitly shared}. This means you can make copies
146     of a record in \l{constant time}.
147 */
148 
operator =(const QSqlRecord & other)149 QSqlRecord& QSqlRecord::operator=(const QSqlRecord& other)
150 {
151     qAtomicAssign(d, other.d);
152     return *this;
153 }
154 
155 /*!
156     Destroys the object and frees any allocated resources.
157 */
158 
~QSqlRecord()159 QSqlRecord::~QSqlRecord()
160 {
161     if (!d->ref.deref())
162         delete d;
163 }
164 
165 /*!
166     \fn bool QSqlRecord::operator!=(const QSqlRecord &other) const
167 
168     Returns \c true if this object is not identical to \a other;
169     otherwise returns \c false.
170 
171     \sa operator==()
172 */
173 
174 /*!
175     Returns \c true if this object is identical to \a other (i.e., has
176     the same fields in the same order); otherwise returns \c false.
177 
178     \sa operator!=()
179 */
operator ==(const QSqlRecord & other) const180 bool QSqlRecord::operator==(const QSqlRecord &other) const
181 {
182     return d->fields == other.d->fields;
183 }
184 
185 /*!
186     Returns the value of the field located at position \a index in
187     the record. If \a index is out of bounds, an invalid QVariant
188     is returned.
189 
190     \sa fieldName(), isNull()
191 */
192 
value(int index) const193 QVariant QSqlRecord::value(int index) const
194 {
195     return d->fields.value(index).value();
196 }
197 
198 /*!
199     \overload
200 
201     Returns the value of the field called \a name in the record. If
202     field \a name does not exist an invalid variant is returned.
203 
204     \sa indexOf()
205 */
206 
value(const QString & name) const207 QVariant QSqlRecord::value(const QString& name) const
208 {
209     return value(indexOf(name));
210 }
211 
212 /*!
213     Returns the name of the field at position \a index. If the field
214     does not exist, an empty string is returned.
215 
216     \sa indexOf()
217 */
218 
fieldName(int index) const219 QString QSqlRecord::fieldName(int index) const
220 {
221     return d->fields.value(index).name();
222 }
223 
224 /*!
225     Returns the position of the field called \a name within the
226     record, or -1 if it cannot be found. Field names are not
227     case-sensitive. If more than one field matches, the first one is
228     returned.
229 
230     \sa fieldName()
231 */
232 
indexOf(const QString & name) const233 int QSqlRecord::indexOf(const QString& name) const
234 {
235     QStringRef tableName;
236     QStringRef fieldName(&name);
237     const int idx = name.indexOf(QLatin1Char('.'));
238     if (idx != -1) {
239         tableName = name.leftRef(idx);
240         fieldName = name.midRef(idx + 1);
241     }
242     const int cnt = count();
243     for (int i = 0; i < cnt; ++i) {
244         // Check the passed in name first in case it is an alias using a dot.
245         // Then check if both the table and field match when there is a table name specified.
246         const auto &currentField = d->fields.at(i);
247         const auto &currentFieldName = currentField.name();
248         if (currentFieldName.compare(name, Qt::CaseInsensitive) == 0
249             || (idx != -1 && currentFieldName.compare(fieldName, Qt::CaseInsensitive) == 0
250                 && currentField.tableName().compare(tableName, Qt::CaseInsensitive) == 0)) {
251             return i;
252         }
253     }
254     return -1;
255 }
256 
257 /*!
258     Returns the field at position \a index. If the \a index
259     is out of range, function returns
260     a \l{default-constructed value}.
261  */
field(int index) const262 QSqlField QSqlRecord::field(int index) const
263 {
264     return d->fields.value(index);
265 }
266 
267 /*! \overload
268     Returns the field called \a name.
269  */
field(const QString & name) const270 QSqlField QSqlRecord::field(const QString &name) const
271 {
272     return field(indexOf(name));
273 }
274 
275 
276 /*!
277     Append a copy of field \a field to the end of the record.
278 
279     \sa insert(), replace(), remove()
280 */
281 
append(const QSqlField & field)282 void QSqlRecord::append(const QSqlField& field)
283 {
284     detach();
285     d->fields.append(field);
286 }
287 
288 /*!
289     Inserts the field \a field at position \a pos in the record.
290 
291     \sa append(), replace(), remove()
292  */
insert(int pos,const QSqlField & field)293 void QSqlRecord::insert(int pos, const QSqlField& field)
294 {
295    detach();
296    d->fields.insert(pos, field);
297 }
298 
299 /*!
300     Replaces the field at position \a pos with the given \a field. If
301     \a pos is out of range, nothing happens.
302 
303     \sa append(), insert(), remove()
304 */
305 
replace(int pos,const QSqlField & field)306 void QSqlRecord::replace(int pos, const QSqlField& field)
307 {
308     if (!d->contains(pos))
309         return;
310 
311     detach();
312     d->fields[pos] = field;
313 }
314 
315 /*!
316     Removes the field at position \a pos. If \a pos is out of range,
317     nothing happens.
318 
319     \sa append(), insert(), replace()
320 */
321 
remove(int pos)322 void QSqlRecord::remove(int pos)
323 {
324     if (!d->contains(pos))
325         return;
326 
327     detach();
328     d->fields.remove(pos);
329 }
330 
331 /*!
332     Removes all the record's fields.
333 
334     \sa clearValues(), isEmpty()
335 */
336 
clear()337 void QSqlRecord::clear()
338 {
339     detach();
340     d->fields.clear();
341 }
342 
343 /*!
344     Returns \c true if there are no fields in the record; otherwise
345     returns \c false.
346 
347     \sa append(), insert(), clear()
348 */
349 
isEmpty() const350 bool QSqlRecord::isEmpty() const
351 {
352     return d->fields.isEmpty();
353 }
354 
355 
356 /*!
357     Returns \c true if there is a field in the record called \a name;
358     otherwise returns \c false.
359 */
360 
contains(const QString & name) const361 bool QSqlRecord::contains(const QString& name) const
362 {
363     return indexOf(name) >= 0;
364 }
365 
366 /*!
367     Clears the value of all fields in the record and sets each field
368     to null.
369 
370     \sa setValue()
371 */
372 
clearValues()373 void QSqlRecord::clearValues()
374 {
375     detach();
376     int count = d->fields.count();
377     for (int i = 0; i < count; ++i)
378         d->fields[i].clear();
379 }
380 
381 /*!
382     Sets the generated flag for the field called \a name to \a
383     generated. If the field does not exist, nothing happens. Only
384     fields that have \a generated set to true are included in the SQL
385     that is generated by QSqlQueryModel for example.
386 
387     \sa isGenerated()
388 */
389 
setGenerated(const QString & name,bool generated)390 void QSqlRecord::setGenerated(const QString& name, bool generated)
391 {
392     setGenerated(indexOf(name), generated);
393 }
394 
395 /*!
396     \overload
397 
398     Sets the generated flag for the field \a index to \a generated.
399 
400     \sa isGenerated()
401 */
402 
setGenerated(int index,bool generated)403 void QSqlRecord::setGenerated(int index, bool generated)
404 {
405     if (!d->contains(index))
406         return;
407     detach();
408     d->fields[index].setGenerated(generated);
409 }
410 
411 /*!
412     \overload
413 
414     Returns \c true if the field \a index is null or if there is no field at
415     position \a index; otherwise returns \c false.
416 */
isNull(int index) const417 bool QSqlRecord::isNull(int index) const
418 {
419     return d->fields.value(index).isNull();
420 }
421 
422 /*!
423     Returns \c true if the field called \a name is null or if there is no
424     field called \a name; otherwise returns \c false.
425 
426     \sa setNull()
427 */
isNull(const QString & name) const428 bool QSqlRecord::isNull(const QString& name) const
429 {
430     return isNull(indexOf(name));
431 }
432 
433 /*!
434     Sets the value of field \a index to null. If the field does not exist,
435     nothing happens.
436 
437     \sa setValue()
438 */
setNull(int index)439 void QSqlRecord::setNull(int index)
440 {
441     if (!d->contains(index))
442         return;
443     detach();
444     d->fields[index].clear();
445 }
446 
447 /*!
448     \overload
449 
450     Sets the value of the field called \a name to null. If the field
451     does not exist, nothing happens.
452 */
setNull(const QString & name)453 void QSqlRecord::setNull(const QString& name)
454 {
455     setNull(indexOf(name));
456 }
457 
458 
459 /*!
460     Returns \c true if the record has a field called \a name and this
461     field is to be generated (the default); otherwise returns \c false.
462 
463     \sa setGenerated()
464 */
isGenerated(const QString & name) const465 bool QSqlRecord::isGenerated(const QString& name) const
466 {
467     return isGenerated(indexOf(name));
468 }
469 
470 /*! \overload
471 
472     Returns \c true if the record has a field at position \a index and this
473     field is to be generated (the default); otherwise returns \c false.
474 
475     \sa setGenerated()
476 */
isGenerated(int index) const477 bool QSqlRecord::isGenerated(int index) const
478 {
479     return d->fields.value(index).isGenerated();
480 }
481 
482 /*!
483     Returns the number of fields in the record.
484 
485     \sa isEmpty()
486 */
487 
count() const488 int QSqlRecord::count() const
489 {
490     return d->fields.count();
491 }
492 
493 /*!
494     Sets the value of the field at position \a index to \a val. If the
495     field does not exist, nothing happens.
496 
497     \sa setNull()
498 */
499 
setValue(int index,const QVariant & val)500 void QSqlRecord::setValue(int index, const QVariant& val)
501 {
502     if (!d->contains(index))
503         return;
504     detach();
505     d->fields[index].setValue(val);
506 }
507 
508 
509 /*!
510     \overload
511 
512     Sets the value of the field called \a name to \a val. If the field
513     does not exist, nothing happens.
514 */
515 
setValue(const QString & name,const QVariant & val)516 void QSqlRecord::setValue(const QString& name, const QVariant& val)
517 {
518     setValue(indexOf(name), val);
519 }
520 
521 
522 /*! \internal
523 */
detach()524 void QSqlRecord::detach()
525 {
526     qAtomicDetach(d);
527 }
528 
529 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QSqlRecord & r)530 QDebug operator<<(QDebug dbg, const QSqlRecord &r)
531 {
532     QDebugStateSaver saver(dbg);
533     dbg.nospace();
534     const int count = r.count();
535     dbg << "QSqlRecord(" << count << ')';
536     for (int i = 0; i < count; ++i) {
537         dbg.nospace();
538         dbg << '\n' << qSetFieldWidth(2) << Qt::right << i << Qt::left << qSetFieldWidth(0) << ':';
539         dbg.space();
540         dbg << r.field(i) << r.value(i).toString();
541     }
542     return dbg;
543 }
544 #endif
545 
546 /*!
547     \since 5.1
548     Returns a record containing the fields represented in \a keyFields set to values
549     that match by field name.
550 */
keyValues(const QSqlRecord & keyFields) const551 QSqlRecord QSqlRecord::keyValues(const QSqlRecord &keyFields) const
552 {
553     QSqlRecord retValues(keyFields);
554 
555     for (int i = retValues.count() - 1; i >= 0; --i)
556         retValues.setValue(i, value(retValues.fieldName(i)));
557 
558     return retValues;
559 }
560 
561 QT_END_NAMESPACE
562