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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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