summaryrefslogtreecommitdiffstats
path: root/translations/qtmobility_ar.ts
blob: 427cbcfa440cbebd14fe3662253a6a7964c2c015 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="ar_SA">
<context>
    <name>AudioCaptureSession</name>
    <message>
        <location filename="../plugins/multimedia/audiocapture/audiocapturesession.cpp" line="+141"/>
        <source>RAW file format</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+2"/>
        <source>WAV file format</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>AudioEncoderControl</name>
    <message>
        <location filename="../plugins/multimedia/audiocapture/audioencodercontrol.cpp" line="+87"/>
        <source>PCM audio data</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QGstreamerAudioEncode</name>
    <message>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/maemo/qgstreameraudioencode_maemo.cpp" line="+68"/>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/qgstreameraudioencode.cpp" line="+83"/>
        <source>Raw PCM audio</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QGstreamerCaptureSession</name>
    <message>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/qgstreamercapturesession.cpp" line="+200"/>
        <source>Could not create an audio source element</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+244"/>
        <source>Failed to build media capture pipeline.</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QGstreamerPlayerSession</name>
    <message>
        <location filename="../plugins/multimedia/gstreamer/mediaplayer/qgstreamerplayersession.cpp" line="+271"/>
        <location line="+16"/>
        <source>Unable to play %1</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QGstreamerRecorderControl</name>
    <message>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/maemo/qgstreamerrecordercontrol_maemo.cpp" line="+108"/>
        <location line="+8"/>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp" line="+109"/>
        <location line="+11"/>
        <source>Service has not been started</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+92"/>
        <location filename="../plugins/multimedia/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp" line="+92"/>
        <source>Not compatible codecs and container format.</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QMediaPlayer</name>
    <message>
        <location filename="../src/multimedia/qmediaplayer.cpp" line="+475"/>
        <source>The QMediaPlayer object does not have a valid service</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QMediaPlaylist</name>
    <message>
        <location filename="../src/multimedia/qmediaplaylist.cpp" line="+449"/>
        <location line="+46"/>
        <source>Could not add items to read only playlist.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="-27"/>
        <location line="+46"/>
        <source>Playlist format is not supported</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+26"/>
        <source>The file could not be accessed.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+35"/>
        <source>Playlist format is not supported.</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QMessage</name>
    <message>
        <location filename="../src/messaging/qmessage_qmf.cpp" line="+597"/>
        <location filename="../src/messaging/qmessage_win.cpp" line="+534"/>
        <source>Subject</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+1"/>
        <location filename="../src/messaging/qmessage_win.cpp" line="+1"/>
        <source>Date</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+1"/>
        <location filename="../src/messaging/qmessage_win.cpp" line="+1"/>
        <source>From</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+7"/>
        <location filename="../src/messaging/qmessage_win.cpp" line="+1"/>
        <source>To</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+82"/>
        <location filename="../src/messaging/qmessage_win.cpp" line="+66"/>
        <source>On %1 you wrote:
&gt; </source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="../src/messaging/qmessage_win.cpp" line="-70"/>
        <source>Forwarded Message</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QNetworkConfigurationManagerPrivate</name>
    <message>
        <location filename="../src/bearer/qnetworkconfigmanager_p.cpp" line="+178"/>
        <source>Internet</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QNetworkSessionPrivate</name>
    <message>
        <location filename="../src/bearer/qnetworksession_p.cpp" line="+301"/>
        <location filename="../src/bearer/qnetworksession_s60_p.cpp" line="+265"/>
        <source>Unknown session error.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+2"/>
        <location filename="../src/bearer/qnetworksession_s60_p.cpp" line="+2"/>
        <source>The session was aborted by the user or system.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+2"/>
        <location filename="../src/bearer/qnetworksession_s60_p.cpp" line="+2"/>
        <source>The requested operation is not supported by the system.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+2"/>
        <location filename="../src/bearer/qnetworksession_s60_p.cpp" line="+2"/>
        <source>The specified configuration cannot be used.</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+2"/>
        <location filename="../src/bearer/qnetworksession_s60_p.cpp" line="+2"/>
        <source>Roaming was aborted or is not possible.</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QObject</name>
    <message>
        <location filename="../src/bearer/qnetworksession_maemo.cpp" line="+993"/>
        <source>Roaming error</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+3"/>
        <source>Session aborted by user or system</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+4"/>
        <source>Unidentified Error</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="../src/publishsubscribe/qsystemreadwritelock_unix.cpp" line="+237"/>
        <source>QSystemReadWriteLock::QSystemReadWriteLock: unable to make key file for key: %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+9"/>
        <source>QSystemReadWriteLock::QSystemReadWriteLock: ftok failed for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+13"/>
        <source>QSystemReadWriteLock::QSystemReadWriteLock: Unable to access semaphore set for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+6"/>
        <source>QSystemReadWriteLock:QSystemReadWriteLock: Unable to access semaphore set for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+32"/>
        <source>QSystemReadWriteLock::QSystemReadWriteLock: Unable to reset semaphore set for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+16"/>
        <source>QSystemReadWriteLock::QSystemReadWriteLock: Unable to increment NumInstances semaphore for key%1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+73"/>
        <source>QSystemReadWriteLock::lockForRead: Unable to lock for read for key %1(Lock had not been correctly initialized)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+18"/>
        <source>QSystemReadWriteLock::lockForRead: Unable to lock for read for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+18"/>
        <source>QSystemReadWriteLock::lockForWrite: Unable to lock for write for key %1(Lock had not been correctly initialized)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+14"/>
        <source>QSystemReadWriteLock::lockForWrite: Could not increment TotalWriters semaphore for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+11"/>
        <source>QSystemReadWriteLock::lockForWrite: Could not detect if all readers were finished for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+17"/>
        <source>QSystemReadWriteLock::lockForWrite: Could not decrement ActiveWriterSem semaphore for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+22"/>
        <source>QSystemReadWriteLock::unlock: Unable to unlock for key %1(Lock had not been correctly initialized)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+29"/>
        <source>QSystemSemaphoreWriteLock::unlock: Unable to check and update writer semaphores for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+9"/>
        <source>QSystemReadWriteLock::unlock: Unable to decrement ActiveReaders semaphore for key %1(%2)</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location filename="../src/publishsubscribe/qsystemreadwritelock_win.cpp" line="+105"/>
        <source>QSystemReadWriteLockPrivate::QSystemReadWriteLockPrivate: Unable to create/attach to shared memory</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+7"/>
        <source>QSystemReadWriteLockPrivate::QSystemReadWriteLockPrivate: Unable to initialize shared memory</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+75"/>
        <source>QSystemReadWriteLock::lockForRead(): cannot peform operation, lock initialization had not been successful</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+6"/>
        <source>QSystemReadWriteLock::lockForRead(): cannot perform operation, locking of shared memory was unsuccessful</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+32"/>
        <source>QSystemReadWriteLock::lockForWrite(): cannot peform operation, lock initialization had not been successful</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+6"/>
        <location line="+39"/>
        <source>QSystemReadWriteLock::lockForwrite(): cannot perform operation, locking of shared memory was unsuccessful</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="-6"/>
        <source>QSystemReadWriteLock::unlock(): cannot peform operation, lock initialization had not been successful</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>QXARecordSession</name>
    <message>
        <location filename="../plugins/multimedia/symbian/openmaxal/mediarecorder/qxarecordsession.cpp" line="+60"/>
        <location line="+11"/>
        <source>Service has not been started</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+31"/>
        <source>Unable to start Service</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+44"/>
        <location line="+48"/>
        <source>Generic error</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+17"/>
        <source>Unable to pause</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+17"/>
        <source>Unable to stop</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+26"/>
        <source>Resources Unavailable</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+76"/>
        <source>Invalid endpoint</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+126"/>
        <location line="+12"/>
        <source>Invalid container</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+70"/>
        <source>Invalid bitrate</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+13"/>
        <source>Invalid channel count</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+15"/>
        <source>Invalid codec</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+24"/>
        <source>Invalid encoding quality setting</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+9"/>
        <location line="+14"/>
        <location line="+14"/>
        <source>Invalid encoding mode setting</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="-23"/>
        <location line="+14"/>
        <source>Internal error</source>
        <translation type="unfinished"></translation>
    </message>
    <message>
        <location line="+19"/>
        <source>Invalid sample rate</source>
        <translation type="unfinished"></translation>
    </message>
</context>
<context>
    <name>S60MediaPlayerControl</name>
    <message>
        <location filename="../plugins/multimedia/symbian/mmf/mediaplayer/s60mediaplayercontrol.cpp" line="+229"/>
        <source>Media couldn&apos;t be resolved</source>
        <translation type="unfinished"></translation>
    </message>
</context>
</TS>
/span> t) { // *not* MYSQL_TYPE_TIME because its range is bigger than QTime // (see above) return t == MYSQL_TYPE_DATE || t == MYSQL_TYPE_DATETIME || t == MYSQL_TYPE_TIMESTAMP; } static bool qIsInteger(int t) { return t == QMetaType::Char || t == QMetaType::UChar || t == QMetaType::Short || t == QMetaType::UShort || t == QMetaType::Int || t == QMetaType::UInt || t == QMetaType::LongLong || t == QMetaType::ULongLong; } void QMYSQLResultPrivate::bindBlobs() { for (int i = 0; i < fields.size(); ++i) { const MYSQL_FIELD *fieldInfo = fields.at(i).myField; if (qIsBlob(inBinds[i].buffer_type) && meta && fieldInfo) { MYSQL_BIND *bind = &inBinds[i]; bind->buffer_length = fieldInfo->max_length; delete[] static_cast<char*>(bind->buffer); bind->buffer = new char[fieldInfo->max_length]; fields[i].outField = static_cast<char*>(bind->buffer); } } } bool QMYSQLResultPrivate::bindInValues() { if (!meta) meta = mysql_stmt_result_metadata(stmt); if (!meta) return false; fields.resize(mysql_num_fields(meta)); inBinds = new MYSQL_BIND[fields.size()]; memset(inBinds, 0, fields.size() * sizeof(MYSQL_BIND)); const MYSQL_FIELD *fieldInfo; int i = 0; while((fieldInfo = mysql_fetch_field(meta))) { MYSQL_BIND *bind = &inBinds[i]; QMyField &f = fields[i]; f.myField = fieldInfo; bind->buffer_length = f.bufLength = fieldInfo->length + 1; bind->buffer_type = fieldInfo->type; f.type = qDecodeMYSQLType(fieldInfo->type, fieldInfo->flags); if (qIsBlob(fieldInfo->type)) { // the size of a blob-field is available as soon as we call // mysql_stmt_store_result() // after mysql_stmt_exec() in QMYSQLResult::exec() bind->buffer_length = f.bufLength = 0; hasBlobs = true; } else if (qIsTimeOrDate(fieldInfo->type)) { bind->buffer_length = f.bufLength = sizeof(MYSQL_TIME); } else if (qIsInteger(f.type.id())) { bind->buffer_length = f.bufLength = 8; } else { bind->buffer_type = MYSQL_TYPE_STRING; } bind->is_null = &f.nullIndicator; bind->length = &f.bufLength; bind->is_unsigned = fieldInfo->flags & UNSIGNED_FLAG ? 1 : 0; char *field = bind->buffer_length ? new char[bind->buffer_length + 1]{} : nullptr; bind->buffer = f.outField = field; ++i; } return true; } QMYSQLResult::QMYSQLResult(const QMYSQLDriver* db) : QSqlResult(*new QMYSQLResultPrivate(this, db)) { } QMYSQLResult::~QMYSQLResult() { cleanup(); } QVariant QMYSQLResult::handle() const { Q_D(const QMYSQLResult); if (d->preparedQuery) return d->meta ? QVariant::fromValue(d->meta) : QVariant::fromValue(d->stmt); else return QVariant::fromValue(d->result); } void QMYSQLResult::cleanup() { Q_D(QMYSQLResult); if (d->result) mysql_free_result(d->result); // must iterate through leftover result sets from multi-selects or stored procedures // if this isn't done subsequent queries will fail with "Commands out of sync" while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) { MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql); if (res) mysql_free_result(res); } if (d->stmt) { if (mysql_stmt_close(d->stmt)) qWarning("QMYSQLResult::cleanup: unable to free statement handle"); d->stmt = 0; } if (d->meta) { mysql_free_result(d->meta); d->meta = 0; } int i; for (i = 0; i < d->fields.size(); ++i) delete[] d->fields[i].outField; if (d->outBinds) { delete[] d->outBinds; d->outBinds = 0; } if (d->inBinds) { delete[] d->inBinds; d->inBinds = 0; } d->hasBlobs = false; d->fields.clear(); d->result = nullptr; d->row = nullptr; setAt(-1); setActive(false); } bool QMYSQLResult::fetch(int i) { Q_D(QMYSQLResult); if (!driver()) return false; if (isForwardOnly()) { // fake a forward seek if (at() < i) { int x = i - at(); while (--x && fetchNext()) {}; return fetchNext(); } else { return false; } } if (at() == i) return true; if (d->preparedQuery) { mysql_stmt_data_seek(d->stmt, i); int nRC = mysql_stmt_fetch(d->stmt); if (nRC) { if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED) setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to fetch data"), QSqlError::StatementError, d->stmt)); return false; } } else { mysql_data_seek(d->result, i); d->row = mysql_fetch_row(d->result); if (!d->row) return false; } setAt(i); return true; } bool QMYSQLResult::fetchNext() { Q_D(QMYSQLResult); if (!driver()) return false; if (d->preparedQuery) { int nRC = mysql_stmt_fetch(d->stmt); if (nRC) { if (nRC == 1 || nRC == MYSQL_DATA_TRUNCATED) setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to fetch data"), QSqlError::StatementError, d->stmt)); return false; } } else { d->row = mysql_fetch_row(d->result); if (!d->row) return false; } setAt(at() + 1); return true; } bool QMYSQLResult::fetchLast() { Q_D(QMYSQLResult); if (!driver()) return false; if (isForwardOnly()) { // fake this since MySQL can't seek on forward only queries bool success = fetchNext(); // did we move at all? while (fetchNext()) {}; return success; } my_ulonglong numRows; if (d->preparedQuery) { numRows = mysql_stmt_num_rows(d->stmt); } else { numRows = mysql_num_rows(d->result); } if (at() == int(numRows)) return true; if (!numRows) return false; return fetch(numRows - 1); } bool QMYSQLResult::fetchFirst() { if (at() == 0) return true; if (isForwardOnly()) return (at() == QSql::BeforeFirstRow) ? fetchNext() : false; return fetch(0); } QVariant QMYSQLResult::data(int field) { Q_D(QMYSQLResult); if (!isSelect() || field >= d->fields.size()) { qWarning("QMYSQLResult::data: column %d out of range", field); return QVariant(); } if (!driver()) return QVariant(); my_ulonglong fieldLength = 0; const QMYSQLResultPrivate::QMyField &f = d->fields.at(field); QString val; if (d->preparedQuery) { if (f.nullIndicator) return QVariant(f.type); if (qIsInteger(f.type.id())) { QVariant variant(f.type, f.outField); // we never want to return char variants here, see QTBUG-53397 if (f.type.id() == QMetaType::UChar) return variant.toUInt(); else if (f.type.id() == QMetaType::Char) return variant.toInt(); return variant; } else if (qIsTimeOrDate(f.myField->type) && f.bufLength == sizeof(MYSQL_TIME)) { auto t = reinterpret_cast<const MYSQL_TIME *>(f.outField); QDate date; QTime time; if (f.type.id() != QMetaType::QTime) date = QDate(t->year, t->month, t->day); if (f.type.id() != QMetaType::QDate) time = QTime(t->hour, t->minute, t->second, t->second_part / 1000); if (f.type.id() == QMetaType::QDateTime) return QDateTime(date, time); else if (f.type.id() == QMetaType::QDate) return date; else return time; } if (f.type.id() != QMetaType::QByteArray) val = QString::fromUtf8(f.outField, f.bufLength); } else { if (d->row[field] == nullptr) { // NULL value return QVariant(f.type); } fieldLength = mysql_fetch_lengths(d->result)[field]; if (f.type.id() != QMetaType::QByteArray) val = QString::fromUtf8(d->row[field], fieldLength); } switch (f.type.id()) { case QMetaType::LongLong: return QVariant(val.toLongLong()); case QMetaType::ULongLong: return QVariant(val.toULongLong()); case QMetaType::Char: case QMetaType::Short: case QMetaType::Int: return QVariant(val.toInt()); case QMetaType::UChar: case QMetaType::UShort: case QMetaType::UInt: return QVariant(val.toUInt()); case QMetaType::Double: { QVariant v; bool ok=false; double dbl = val.toDouble(&ok); switch(numericalPrecisionPolicy()) { case QSql::LowPrecisionInt32: v=QVariant(dbl).toInt(); break; case QSql::LowPrecisionInt64: v = QVariant(dbl).toLongLong(); break; case QSql::LowPrecisionDouble: v = QVariant(dbl); break; case QSql::HighPrecision: default: v = val; ok = true; break; } if (ok) return v; return QVariant(); } case QMetaType::QDate: return qDateFromString(val); case QMetaType::QTime: return qTimeFromString(val); case QMetaType::QDateTime: return qDateTimeFromString(val); case QMetaType::QByteArray: { QByteArray ba; if (d->preparedQuery) { ba = QByteArray(f.outField, f.bufLength); } else { ba = QByteArray(d->row[field], fieldLength); } return QVariant(ba); } case QMetaType::QString: default: return QVariant(val); } Q_UNREACHABLE(); } bool QMYSQLResult::isNull(int field) { Q_D(const QMYSQLResult); if (field < 0 || field >= d->fields.size()) return true; if (d->preparedQuery) return d->fields.at(field).nullIndicator; else return d->row[field] == nullptr; } bool QMYSQLResult::reset (const QString& query) { Q_D(QMYSQLResult); if (!driver() || !driver()->isOpen() || driver()->isOpenError()) return false; d->preparedQuery = false; cleanup(); const QByteArray encQuery = query.toUtf8(); if (mysql_real_query(d->drv_d_func()->mysql, encQuery.data(), encQuery.size())) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute query"), QSqlError::StatementError, d->drv_d_func())); return false; } d->result = mysql_store_result(d->drv_d_func()->mysql); if (!d->result && mysql_field_count(d->drv_d_func()->mysql) > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store result"), QSqlError::StatementError, d->drv_d_func())); return false; } int numFields = mysql_field_count(d->drv_d_func()->mysql); setSelect(numFields != 0); d->fields.resize(numFields); d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql); if (isSelect()) { for(int i = 0; i < numFields; i++) { MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); } setAt(QSql::BeforeFirstRow); } setActive(true); return isActive(); } int QMYSQLResult::size() { Q_D(const QMYSQLResult); if (driver() && isSelect()) if (d->preparedQuery) return mysql_stmt_num_rows(d->stmt); else return int(mysql_num_rows(d->result)); else return -1; } int QMYSQLResult::numRowsAffected() { Q_D(const QMYSQLResult); return d->rowsAffected; } void QMYSQLResult::detachFromResultSet() { Q_D(QMYSQLResult); if (d->preparedQuery) { mysql_stmt_free_result(d->stmt); } } QVariant QMYSQLResult::lastInsertId() const { Q_D(const QMYSQLResult); if (!isActive() || !driver()) return QVariant(); if (d->preparedQuery) { quint64 id = mysql_stmt_insert_id(d->stmt); if (id) return QVariant(id); } else { quint64 id = mysql_insert_id(d->drv_d_func()->mysql); if (id) return QVariant(id); } return QVariant(); } QSqlRecord QMYSQLResult::record() const { Q_D(const QMYSQLResult); QSqlRecord info; MYSQL_RES *res; if (!isActive() || !isSelect() || !driver()) return info; res = d->preparedQuery ? d->meta : d->result; if (!mysql_errno(d->drv_d_func()->mysql)) { mysql_field_seek(res, 0); MYSQL_FIELD* field = mysql_fetch_field(res); while(field) { info.append(qToField(field)); field = mysql_fetch_field(res); } } mysql_field_seek(res, 0); return info; } bool QMYSQLResult::nextResult() { Q_D(QMYSQLResult); if (!driver()) return false; setAt(-1); setActive(false); if (d->result && isSelect()) mysql_free_result(d->result); d->result = 0; setSelect(false); for (int i = 0; i < d->fields.size(); ++i) delete[] d->fields[i].outField; d->fields.clear(); int status = mysql_next_result(d->drv_d_func()->mysql); if (status > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to execute next query"), QSqlError::StatementError, d->drv_d_func())); return false; } else if (status == -1) { return false; // No more result sets } d->result = mysql_store_result(d->drv_d_func()->mysql); int numFields = mysql_field_count(d->drv_d_func()->mysql); if (!d->result && numFields > 0) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to store next result"), QSqlError::StatementError, d->drv_d_func())); return false; } setSelect(numFields > 0); d->fields.resize(numFields); d->rowsAffected = mysql_affected_rows(d->drv_d_func()->mysql); if (isSelect()) { for (int i = 0; i < numFields; i++) { MYSQL_FIELD* field = mysql_fetch_field_direct(d->result, i); d->fields[i].type = qDecodeMYSQLType(field->type, field->flags); } } setActive(true); return true; } void QMYSQLResult::virtual_hook(int id, void *data) { QSqlResult::virtual_hook(id, data); } static MYSQL_TIME *toMySqlDate(QDate date, QTime time, int type) { Q_ASSERT(type == QMetaType::QTime || type == QMetaType::QDate || type == QMetaType::QDateTime); MYSQL_TIME *myTime = new MYSQL_TIME; memset(myTime, 0, sizeof(MYSQL_TIME)); if (type == QMetaType::QTime || type == QMetaType::QDateTime) { myTime->hour = time.hour(); myTime->minute = time.minute(); myTime->second = time.second(); myTime->second_part = time.msec() * 1000; } if (type == QMetaType::QDate || type == QMetaType::QDateTime) { myTime->year = date.year(); myTime->month = date.month(); myTime->day = date.day(); } return myTime; } bool QMYSQLResult::prepare(const QString& query) { Q_D(QMYSQLResult); if (!driver()) return false; cleanup(); if (!d->drv_d_func()->preparedQuerysEnabled) return QSqlResult::prepare(query); int r; if (query.isEmpty()) return false; if (!d->stmt) d->stmt = mysql_stmt_init(d->drv_d_func()->mysql); if (!d->stmt) { setLastError(qMakeError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), QSqlError::StatementError, d->drv_d_func())); return false; } const QByteArray encQuery = query.toUtf8(); r = mysql_stmt_prepare(d->stmt, encQuery.constData(), encQuery.size()); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to prepare statement"), QSqlError::StatementError, d->stmt)); cleanup(); return false; } if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)]; } setSelect(d->bindInValues()); d->preparedQuery = true; return true; } bool QMYSQLResult::exec() { Q_D(QMYSQLResult); if (!driver()) return false; if (!d->preparedQuery) return QSqlResult::exec(); if (!d->stmt) return false; int r = 0; QList<MYSQL_TIME *> timeVector; QList<QByteArray> stringVector; QList<my_bool> nullVector; const QList<QVariant> values = boundValues(); r = mysql_stmt_reset(d->stmt); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to reset statement"), QSqlError::StatementError, d->stmt)); return false; } if (mysql_stmt_param_count(d->stmt) > 0 && mysql_stmt_param_count(d->stmt) == (uint)values.size()) { nullVector.resize(values.size()); for (int i = 0; i < values.size(); ++i) { const QVariant &val = boundValues().at(i); void *data = const_cast<void *>(val.constData()); MYSQL_BIND* currBind = &d->outBinds[i]; nullVector[i] = static_cast<my_bool>(QSqlResultPrivate::isVariantNull(val)); currBind->is_null = &nullVector[i]; currBind->length = 0; currBind->is_unsigned = 0; switch (val.userType()) { case QMetaType::QByteArray: currBind->buffer_type = MYSQL_TYPE_BLOB; currBind->buffer = const_cast<char *>(val.toByteArray().constData()); currBind->buffer_length = val.toByteArray().size(); break; case QMetaType::QTime: case QMetaType::QDate: case QMetaType::QDateTime: { MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.userType()); timeVector.append(myTime); currBind->buffer = myTime; switch (val.userType()) { case QMetaType::QTime: currBind->buffer_type = MYSQL_TYPE_TIME; myTime->time_type = MYSQL_TIMESTAMP_TIME; break; case QMetaType::QDate: currBind->buffer_type = MYSQL_TYPE_DATE; myTime->time_type = MYSQL_TIMESTAMP_DATE; break; case QMetaType::QDateTime: currBind->buffer_type = MYSQL_TYPE_DATETIME; myTime->time_type = MYSQL_TIMESTAMP_DATETIME; break; default: break; } currBind->buffer_length = sizeof(MYSQL_TIME); currBind->length = 0; break; } case QMetaType::UInt: case QMetaType::Int: currBind->buffer_type = MYSQL_TYPE_LONG; currBind->buffer = data; currBind->buffer_length = sizeof(int); currBind->is_unsigned = (val.userType() != QMetaType::Int); break; case QMetaType::Bool: currBind->buffer_type = MYSQL_TYPE_TINY; currBind->buffer = data; currBind->buffer_length = sizeof(bool); currBind->is_unsigned = false; break; case QMetaType::Double: currBind->buffer_type = MYSQL_TYPE_DOUBLE; currBind->buffer = data; currBind->buffer_length = sizeof(double); break; case QMetaType::LongLong: case QMetaType::ULongLong: currBind->buffer_type = MYSQL_TYPE_LONGLONG; currBind->buffer = data; currBind->buffer_length = sizeof(qint64); currBind->is_unsigned = (val.userType() == QMetaType::ULongLong); break; case QMetaType::QString: default: { QByteArray ba = val.toString().toUtf8(); stringVector.append(ba); currBind->buffer_type = MYSQL_TYPE_STRING; currBind->buffer = const_cast<char *>(ba.constData()); currBind->buffer_length = ba.size(); break; } } } r = mysql_stmt_bind_param(d->stmt, d->outBinds); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to bind value"), QSqlError::StatementError, d->stmt)); qDeleteAll(timeVector); return false; } } r = mysql_stmt_execute(d->stmt); qDeleteAll(timeVector); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to execute statement"), QSqlError::StatementError, d->stmt)); return false; } //if there is meta-data there is also data setSelect(d->meta); d->rowsAffected = mysql_stmt_affected_rows(d->stmt); if (isSelect()) { my_bool update_max_length = true; r = mysql_stmt_bind_result(d->stmt, d->inBinds); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); return false; } if (d->hasBlobs) mysql_stmt_attr_set(d->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length); r = mysql_stmt_store_result(d->stmt); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to store statement results"), QSqlError::StatementError, d->stmt)); return false; } if (d->hasBlobs) { // mysql_stmt_store_result() with STMT_ATTR_UPDATE_MAX_LENGTH set to true crashes // when called without a preceding call to mysql_stmt_bind_result() // in versions < 4.1.8 d->bindBlobs(); r = mysql_stmt_bind_result(d->stmt, d->inBinds); if (r != 0) { setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult", "Unable to bind outvalues"), QSqlError::StatementError, d->stmt)); return false; } } setAt(QSql::BeforeFirstRow); } setActive(true); return true; } ///////////////////////////////////////////////////////// static int qMySqlConnectionCount = 0; static bool qMySqlInitHandledByUser = false; static void qLibraryInit() { #ifndef Q_NO_MYSQL_EMBEDDED if (qMySqlInitHandledByUser || qMySqlConnectionCount > 1) return; if (mysql_library_init(0, 0, 0)) { qWarning("QMYSQLDriver::qServerInit: unable to start server."); } #endif // Q_NO_MYSQL_EMBEDDED #if defined(MARIADB_BASE_VERSION) || defined(MARIADB_VERSION_ID) qAddPostRoutine([]() { mysql_server_end(); }); #endif } static void qLibraryEnd() { #if !defined(MARIADB_BASE_VERSION) && !defined(MARIADB_VERSION_ID) # if !defined(Q_NO_MYSQL_EMBEDDED) mysql_library_end(); # endif #endif } QMYSQLDriver::QMYSQLDriver(QObject * parent) : QSqlDriver(*new QMYSQLDriverPrivate, parent) { init(); qLibraryInit(); } /*! Create a driver instance with the open connection handle, \a con. The instance's parent (owner) is \a parent. */ QMYSQLDriver::QMYSQLDriver(MYSQL * con, QObject * parent) : QSqlDriver(*new QMYSQLDriverPrivate, parent) { Q_D(QMYSQLDriver); init(); if (con) { d->mysql = con; setOpen(true); setOpenError(false); if (qMySqlConnectionCount == 1) qMySqlInitHandledByUser = true; } else { qLibraryInit(); } } void QMYSQLDriver::init() { Q_D(QMYSQLDriver); d->mysql = 0; qMySqlConnectionCount++; } QMYSQLDriver::~QMYSQLDriver() { qMySqlConnectionCount--; if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser) qLibraryEnd(); } bool QMYSQLDriver::hasFeature(DriverFeature f) const { Q_D(const QMYSQLDriver); switch (f) { case Transactions: if (d->mysql) { if ((d->mysql->server_capabilities & CLIENT_TRANSACTIONS) == CLIENT_TRANSACTIONS) return true; } return false; case NamedPlaceholders: case BatchOperations: case SimpleLocking: case EventNotifications: case FinishQuery: case CancelQuery: return false; case QuerySize: case BLOB: case LastInsertId: case Unicode: case LowPrecisionNumbers: return true; case PreparedQueries: case PositionalPlaceholders: return d->preparedQuerysEnabled; case MultipleResultSets: return true; } return false; } static void setOptionFlag(uint &optionFlags, const QString &opt) { if (opt == "CLIENT_COMPRESS"_L1) optionFlags |= CLIENT_COMPRESS; else if (opt == "CLIENT_FOUND_ROWS"_L1) optionFlags |= CLIENT_FOUND_ROWS; else if (opt == "CLIENT_IGNORE_SPACE"_L1) optionFlags |= CLIENT_IGNORE_SPACE; else if (opt == "CLIENT_INTERACTIVE"_L1) optionFlags |= CLIENT_INTERACTIVE; else if (opt == "CLIENT_NO_SCHEMA"_L1) optionFlags |= CLIENT_NO_SCHEMA; else if (opt == "CLIENT_ODBC"_L1) optionFlags |= CLIENT_ODBC; else if (opt == "CLIENT_SSL"_L1) qWarning("QMYSQLDriver: SSL_KEY, SSL_CERT and SSL_CA should be used instead of CLIENT_SSL."); else qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData()); } bool QMYSQLDriver::open(const QString& db, const QString& user, const QString& password, const QString& host, int port, const QString& connOpts) { Q_D(QMYSQLDriver); if (isOpen()) close(); /* This is a hack to get MySQL's stored procedure support working. Since a stored procedure _may_ return multiple result sets, we have to enable CLIEN_MULTI_STATEMENTS here, otherwise _any_ stored procedure call will fail. */ unsigned int optionFlags = CLIENT_MULTI_STATEMENTS; const QStringList opts(connOpts.split(u';', Qt::SkipEmptyParts)); QString unixSocket; QString sslCert; QString sslCA; QString sslKey; QString sslCAPath; QString sslCipher; my_bool reconnect=false; uint connectTimeout = 0; uint readTimeout = 0; uint writeTimeout = 0; // extract the real options from the string for (int i = 0; i < opts.count(); ++i) { QString tmp(opts.at(i).simplified()); qsizetype idx; if ((idx = tmp.indexOf(u'=')) != -1) { QString val = tmp.mid(idx + 1).simplified(); QString opt = tmp.left(idx).simplified(); if (opt == "UNIX_SOCKET"_L1) unixSocket = val; else if (opt == "MYSQL_OPT_RECONNECT"_L1) { if (val == "TRUE"_L1 || val == "1"_L1 || val.isEmpty()) reconnect = true; } else if (opt == "MYSQL_OPT_CONNECT_TIMEOUT"_L1) connectTimeout = val.toInt(); else if (opt == "MYSQL_OPT_READ_TIMEOUT"_L1) readTimeout = val.toInt(); else if (opt == "MYSQL_OPT_WRITE_TIMEOUT"_L1) writeTimeout = val.toInt(); else if (opt == "SSL_KEY"_L1) sslKey = val; else if (opt == "SSL_CERT"_L1) sslCert = val; else if (opt == "SSL_CA"_L1) sslCA = val; else if (opt == "SSL_CAPATH"_L1) sslCAPath = val; else if (opt == "SSL_CIPHER"_L1) sslCipher = val; else if (val == "TRUE"_L1 || val == "1"_L1) setOptionFlag(optionFlags, tmp.left(idx).simplified()); else qWarning("QMYSQLDriver::open: Illegal connect option value '%s'", tmp.toLocal8Bit().constData()); } else { setOptionFlag(optionFlags, tmp); } } if (!(d->mysql = mysql_init(nullptr))) { setLastError(qMakeError(tr("Unable to allocate a MYSQL object"), QSqlError::ConnectionError, d)); setOpenError(true); return false; } // try utf8 with non BMP first, utf8 (BMP only) if that fails static const char wanted_charsets[][8] = { "utf8mb4", "utf8" }; #ifdef MARIADB_VERSION_ID MARIADB_CHARSET_INFO *cs = nullptr; for (const char *p : wanted_charsets) { cs = mariadb_get_charset_by_name(p); if (cs) { d->mysql->charset = cs; break; } } #else // dummy struct { const char *csname; } *cs = nullptr; #endif if (!sslKey.isNull() || !sslCert.isNull() || !sslCA.isNull() || !sslCAPath.isNull() || !sslCipher.isNull()) { mysql_ssl_set(d->mysql, sslKey.isNull() ? nullptr : sslKey.toUtf8().constData(), sslCert.isNull() ? nullptr : sslCert.toUtf8().constData(), sslCA.isNull() ? nullptr : sslCA.toUtf8().constData(), sslCAPath.isNull() ? nullptr : sslCAPath.toUtf8().constData(), sslCipher.isNull() ? nullptr : sslCipher.toUtf8().constData()); } if (connectTimeout != 0) mysql_options(d->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connectTimeout); if (readTimeout != 0) mysql_options(d->mysql, MYSQL_OPT_READ_TIMEOUT, &readTimeout); if (writeTimeout != 0) mysql_options(d->mysql, MYSQL_OPT_WRITE_TIMEOUT, &writeTimeout); MYSQL *mysql = mysql_real_connect(d->mysql, host.isNull() ? nullptr : host.toUtf8().constData(), user.isNull() ? nullptr : user.toUtf8().constData(), password.isNull() ? nullptr : password.toUtf8().constData(), db.isNull() ? nullptr : db.toUtf8().constData(), (port > -1) ? port : 0, unixSocket.isNull() ? nullptr : unixSocket.toUtf8().constData(), optionFlags); if (mysql != d->mysql) { setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d)); mysql_close(d->mysql); d->mysql = nullptr; setOpenError(true); return false; } // now ask the server to match the charset we selected if (!cs || mysql_set_character_set(d->mysql, cs->csname) != 0) { bool ok = false; for (const char *p : wanted_charsets) { if (mysql_set_character_set(d->mysql, p) == 0) { ok = true; break; } } if (!ok) qWarning("MySQL: Unable to set the client character set to utf8 (\"%s\"). Using '%s' instead.", mysql_error(d->mysql), mysql_character_set_name(d->mysql)); } if (!db.isEmpty() && mysql_select_db(d->mysql, db.toUtf8().constData())) { setLastError(qMakeError(tr("Unable to open database '%1'").arg(db), QSqlError::ConnectionError, d)); mysql_close(d->mysql); setOpenError(true); return false; } if (reconnect) mysql_options(d->mysql, MYSQL_OPT_RECONNECT, &reconnect); d->preparedQuerysEnabled = checkPreparedQueries(d->mysql); #if QT_CONFIG(thread) mysql_thread_init(); #endif setOpen(true); setOpenError(false); return true; } void QMYSQLDriver::close() { Q_D(QMYSQLDriver); if (isOpen()) { #if QT_CONFIG(thread) mysql_thread_end(); #endif mysql_close(d->mysql); d->mysql = nullptr; setOpen(false); setOpenError(false); } } QSqlResult *QMYSQLDriver::createResult() const { return new QMYSQLResult(this); } QStringList QMYSQLDriver::tables(QSql::TableType type) const { Q_D(const QMYSQLDriver); QStringList tl; QSqlQuery q(createResult()); if (type & QSql::Tables) { QString sql = "select table_name from information_schema.tables where table_schema = '"_L1 + QLatin1StringView(d->mysql->db) + "' and table_type = 'BASE TABLE'"_L1; q.exec(sql); while (q.next()) tl.append(q.value(0).toString()); } if (type & QSql::Views) { QString sql = "select table_name from information_schema.tables where table_schema = '"_L1 + QLatin1StringView(d->mysql->db) + "' and table_type = 'VIEW'"_L1; q.exec(sql); while (q.next()) tl.append(q.value(0).toString()); } return tl; } QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const { QSqlIndex idx; if (!isOpen()) return idx; QSqlQuery i(createResult()); QString stmt("show index from %1;"_L1); QSqlRecord fil = record(tablename); i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName))); while (i.isActive() && i.next()) { if (i.value(2).toString() == "PRIMARY"_L1) { idx.append(fil.field(i.value(4).toString())); idx.setCursorName(i.value(0).toString()); idx.setName(i.value(2).toString()); } } return idx; } QSqlRecord QMYSQLDriver::record(const QString& tablename) const { Q_D(const QMYSQLDriver); QString table=tablename; if (isIdentifierEscaped(table, QSqlDriver::TableName)) table = stripDelimiters(table, QSqlDriver::TableName); QSqlRecord info; if (!isOpen()) return info; MYSQL_RES* r = mysql_list_fields(d->mysql, table.toUtf8().constData(), 0); if (!r) { return info; } MYSQL_FIELD* field; while ((field = mysql_fetch_field(r))) info.append(qToField(field)); mysql_free_result(r); return info; } QVariant QMYSQLDriver::handle() const { Q_D(const QMYSQLDriver); return QVariant::fromValue(d->mysql); } bool QMYSQLDriver::beginTransaction() { Q_D(QMYSQLDriver); if (!isOpen()) { qWarning("QMYSQLDriver::beginTransaction: Database not open"); return false; } if (mysql_query(d->mysql, "BEGIN WORK")) { setLastError(qMakeError(tr("Unable to begin transaction"), QSqlError::StatementError, d)); return false; } return true; } bool QMYSQLDriver::commitTransaction() { Q_D(QMYSQLDriver); if (!isOpen()) { qWarning("QMYSQLDriver::commitTransaction: Database not open"); return false; } if (mysql_query(d->mysql, "COMMIT")) { setLastError(qMakeError(tr("Unable to commit transaction"), QSqlError::StatementError, d)); return false; } return true; } bool QMYSQLDriver::rollbackTransaction() { Q_D(QMYSQLDriver); if (!isOpen()) { qWarning("QMYSQLDriver::rollbackTransaction: Database not open"); return false; } if (mysql_query(d->mysql, "ROLLBACK")) { setLastError(qMakeError(tr("Unable to rollback transaction"), QSqlError::StatementError, d)); return false; } return true; } QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const { Q_D(const QMYSQLDriver); QString r; if (field.isNull()) { r = QStringLiteral("NULL"); } else { switch (field.metaType().id()) { case QMetaType::Double: r = QString::number(field.value().toDouble(), 'g', field.precision()); break; case QMetaType::QString: // Escape '\' characters r = QSqlDriver::formatValue(field, trimStrings); r.replace("\\"_L1, "\\\\"_L1); break; case QMetaType::QByteArray: if (isOpen()) { const QByteArray ba = field.value().toByteArray(); // buffer has to be at least length*2+1 bytes QVarLengthArray<char, 512> buffer(ba.size() * 2 + 1); auto escapedSize = mysql_real_escape_string(d->mysql, buffer.data(), ba.data(), ba.size()); r.reserve(escapedSize + 3); r = u'\'' + QString::fromUtf8(buffer.data(), escapedSize) + u'\''; break; } else { qWarning("QMYSQLDriver::formatValue: Database not open"); } Q_FALLTHROUGH(); case QMetaType::QDateTime: if (QDateTime dt = field.value().toDateTime(); dt.isValid()) { // MySQL format doesn't like the "Z" at the end, but does allow // "+00:00" starting in version 8.0.19. However, if we got here, // it's because the MySQL server is too old for prepared queries // in the first place, so it won't understand timezones either. // Besides, MYSQL_TIME does not support timezones, so match it. r = u'\'' + dt.date().toString(Qt::ISODate) + u'T' + dt.time().toString(Qt::ISODate) + u'\''; } break; default: r = QSqlDriver::formatValue(field, trimStrings); } } return r; } QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType) const { QString res = identifier; if (!identifier.isEmpty() && !identifier.startsWith(u'`') && !identifier.endsWith(u'`') ) { res.prepend(u'`').append(u'`'); res.replace(u'.', "`.`"_L1); } return res; } bool QMYSQLDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const { Q_UNUSED(type); return identifier.size() > 2 && identifier.startsWith(u'`') //left delimited && identifier.endsWith(u'`'); //right delimited } QT_END_NAMESPACE #include "moc_qsql_mysql_p.cpp"