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

source code of qtbase/src/sql/kernel/qsqlrecord.cpp