KDb

KDbNativeStatementBuilder.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2017 Jarosław Staniek <staniek@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KDbNativeStatementBuilder.h"
21#include "KDbConnection.h"
22#include "kdb_debug.h"
23#include "KDbDriverBehavior.h"
24#include "KDbDriver_p.h"
25#include "KDbExpression.h"
26#include "KDbLookupFieldSchema.h"
27#include "KDbOrderByColumn.h"
28#include "KDbQueryAsterisk.h"
29#include "KDbQuerySchema.h"
30#include "KDbQuerySchemaParameter.h"
31#include "KDbRelationship.h"
32
33KDbSelectStatementOptions::~KDbSelectStatementOptions()
34{
35}
36
37//================================================
38
39class Q_DECL_HIDDEN KDbNativeStatementBuilder::Private
40{
41public:
42 Private() {}
43 //! @todo use equivalent of QPointer<KDbConnection>
44 KDbConnection *connection;
46
47private:
48 Q_DISABLE_COPY(Private)
49};
50
51//================================================
52
55 : d(new Private)
56{
57 d->connection = connection;
58 d->dialect = dialect;
59}
60
61KDbNativeStatementBuilder::~KDbNativeStatementBuilder()
62{
63 delete d;
64}
65
66static bool selectStatementInternal(KDbEscapedString *target,
67 KDbConnection *connection,
69 KDbQuerySchema* querySchema,
70 const KDbSelectStatementOptions& options,
71 const QList<QVariant>& parameters)
72{
73 Q_ASSERT(target);
74 Q_ASSERT(querySchema);
75//"SELECT FROM ..." is theoretically allowed "
76//if (querySchema.fieldCount()<1)
77// return QString();
78// Each SQL identifier needs to be escaped in the generated query.
79
80 const KDbDriver *driver = dialect == KDb::DriverEscaping ? connection->driver() : nullptr;
81
82 if (!querySchema->statement().isEmpty()) {
83//! @todo replace with KDbNativeQuerySchema? It shouldn't be here.
84 *target = querySchema->statement();
85 return true;
86 }
87
88//! @todo looking at singleTable is visually nice but a field name can conflict
89//! with function or variable name...
90 int number = 0;
91 QList<KDbTableSchema*>* tables = querySchema->tables();
92 bool singleTable = tables->count() <= 1;
93 if (singleTable) {
94 //make sure we will have single table:
95 foreach(KDbField *f, *querySchema->fields()) {
96 if (querySchema->isColumnVisible(number) && f->table() && f->table()->lookupFieldSchema(*f)) {
97 //uups, no, there's at least one left join
98 singleTable = false;
99 break;
100 }
101 number++;
102 }
103 }
104
105 KDbEscapedString sql; //final sql string
106 sql.reserve(4096);
107 KDbEscapedString s_additional_joins; //additional joins needed for lookup fields
108 KDbEscapedString s_additional_fields; //additional fields to append to the fields list
109 int internalUniqueTableAliasNumber = 0; //used to build internalUniqueTableAliases
110 int internalUniqueQueryAliasNumber = 0; //used to build internalUniqueQueryAliases
111 number = 0;
112 QList<KDbQuerySchema*> subqueries_for_lookup_data; // subqueries will be added to FROM section
113 const QString kdb_subquery_prefix = QStringLiteral("__kdb_subquery_");
114 KDbQuerySchemaParameterValueListIterator paramValuesIt(parameters);
116 = parameters.isEmpty() ? nullptr : &paramValuesIt;
117 foreach(KDbField *f, *querySchema->fields()) {
118 if (querySchema->isColumnVisible(number)) {
119 if (!sql.isEmpty())
120 sql += ", ";
121
122 if (f->isQueryAsterisk()) {
123 KDbQueryAsterisk *asterisk = static_cast<KDbQueryAsterisk*>(f);
124 if (!singleTable && asterisk->isSingleTableAsterisk()) { //single-table *
125 sql.append(KDb::escapeIdentifier(driver, asterisk->table()->name())).append(".*");
126 } else {
127 /* All-tables asterisk
128 NOTE: do not output in this form because there can be extra tables
129 automatically added for obtaining lookup data what changes number of fields.
130 Reliable solution to that: for tables T1..Tn output T1.*,..Tn.*
131 Example for Northwind:
132 - instead of: SELECT * FROM orders LEFT OUTER JOIN
133 customers ON orders.customerid=customers.customerid
134 - use this: SELECT orders.*, customers.contactname FROM orders LEFT OUTER JOIN
135 customers ON orders.customerid=customers.customerid
136 */
137 KDbEscapedString s_tables;
138 for (KDbTableSchema *table : qAsConst(*tables)) {
139 if (!s_tables.isEmpty()) {
140 s_tables += ", ";
141 }
142 s_tables.append(KDb::escapeIdentifier(driver, table->name()) + QLatin1String(".*"));
143 }
144 sql += s_tables;
145 }
146 } else {
147 if (f->isExpression()) {
148 sql += f->expression().toString(driver, paramValuesItPtr);
149 } else {
150 if (!f->table()) {//sanity check
151 return false;
152 }
153
154 QString tableName;
155 int tablePosition = querySchema->tableBoundToColumn(number);
156 if (tablePosition >= 0) {
157 tableName = KDb::iifNotEmpty(querySchema->tableAlias(tablePosition),
158 f->table()->name());
159 }
160 if (options.addVisibleLookupColumns()) { // try to find table/alias name harder
161 if (tableName.isEmpty()) {
162 tableName = querySchema->tableAlias(f->table()->name());
163 }
164 if (tableName.isEmpty()) {
165 tableName = f->table()->name();
166 }
167 }
168 if (!singleTable && !tableName.isEmpty()) {
169 sql.append(KDb::escapeIdentifier(driver, tableName)).append('.');
170 }
171 sql += KDb::escapeIdentifier(driver, f->name());
172 }
173 const QString aliasString(querySchema->columnAlias(number));
174 if (!aliasString.isEmpty()) {
175 sql.append(" AS ").append(KDb::escapeIdentifier(driver, aliasString));
176 }
177//! @todo add option that allows to omit "AS" keyword
178 }
179 KDbLookupFieldSchema *lookupFieldSchema = (options.addVisibleLookupColumns() && f->table())
180 ? f->table()->lookupFieldSchema(*f) : nullptr;
181 if (lookupFieldSchema && lookupFieldSchema->boundColumn() >= 0) {
182 // Lookup field schema found
183 // Now we also need to fetch "visible" value from the lookup table, not only the value of binding.
184 // -> build LEFT OUTER JOIN clause for this purpose (LEFT, not INNER because the binding can be broken)
185 // "LEFT OUTER JOIN lookupTable ON thisTable.thisField=lookupTable.boundField"
186 KDbLookupFieldSchemaRecordSource recordSource = lookupFieldSchema->recordSource();
188 KDbTableSchema *lookupTable = connection->tableSchema(recordSource.name());
189 KDbFieldList* visibleColumns = nullptr;
190 KDbField *boundField = nullptr;
191 if (lookupTable
192 && lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
193 && (visibleColumns = lookupTable->subList(lookupFieldSchema->visibleColumns()))
194 && (boundField = lookupTable->field(lookupFieldSchema->boundColumn()))) {
195 //add LEFT OUTER JOIN
196 if (!s_additional_joins.isEmpty())
197 s_additional_joins += ' ';
198 const QString internalUniqueTableAlias(
199 QLatin1String("__kdb_") + lookupTable->name() + QLatin1Char('_')
200 + QString::number(internalUniqueTableAliasNumber++));
201 s_additional_joins += KDbEscapedString("LEFT OUTER JOIN %1 AS %2 ON %3.%4=%5.%6")
202 .arg(KDb::escapeIdentifier(driver, lookupTable->name()))
203 .arg(KDb::escapeIdentifier(driver, internalUniqueTableAlias))
204 .arg(KDb::escapeIdentifier(driver, querySchema->tableAliasOrName(f->table()->name())))
205 .arg(KDb::escapeIdentifier(driver, f->name()))
206 .arg(KDb::escapeIdentifier(driver, internalUniqueTableAlias))
207 .arg(KDb::escapeIdentifier(driver, boundField->name()));
208
209 //add visibleField to the list of SELECTed fields //if it is not yet present there
210 if (!s_additional_fields.isEmpty())
211 s_additional_fields += ", ";
212//! @todo Add lookup schema option for separator other than ' ' or even option for placeholders like "Name ? ?"
213//! @todo Add possibility for joining the values at client side.
214 s_additional_fields += visibleColumns->sqlFieldsList(
215 connection, QLatin1String(" || ' ' || "), internalUniqueTableAlias,
216 dialect);
217 }
218 delete visibleColumns;
219 } else if (recordSource.type() == KDbLookupFieldSchemaRecordSource::Type::Query) {
220 KDbQuerySchema *lookupQuery = connection->querySchema(recordSource.name());
221 if (!lookupQuery) {
222 kdbWarning() << "!lookupQuery";
223 return false;
224 }
225 const KDbQueryColumnInfo::Vector fieldsExpanded(
226 lookupQuery->fieldsExpanded(connection));
227 if (lookupFieldSchema->boundColumn() >= fieldsExpanded.count()) {
228 kdbWarning() << "lookupFieldSchema->boundColumn() >= fieldsExpanded.count()";
229 return false;
230 }
231 KDbQueryColumnInfo *boundColumnInfo = fieldsExpanded.at(lookupFieldSchema->boundColumn());
232 if (!boundColumnInfo) {
233 kdbWarning() << "!boundColumnInfo";
234 return false;
235 }
236 KDbField *boundField = boundColumnInfo->field();
237 if (!boundField) {
238 kdbWarning() << "!boundField";
239 return false;
240 }
241 //add LEFT OUTER JOIN
242 if (!s_additional_joins.isEmpty())
243 s_additional_joins += ' ';
244 KDbEscapedString internalUniqueQueryAlias(KDb::escapeIdentifier(
245 driver,
246 kdb_subquery_prefix + lookupQuery->name() + QLatin1Char('_')
247 + QString::number(internalUniqueQueryAliasNumber++)));
248 KDbNativeStatementBuilder builder(connection, dialect);
249 KDbEscapedString subSql;
250 if (!builder.generateSelectStatement(&subSql, lookupQuery, options,
251 parameters))
252 {
253 return false;
254 }
255 s_additional_joins += KDbEscapedString("LEFT OUTER JOIN (%1) AS %2 ON %3.%4=%5.%6")
256 .arg(subSql)
257 .arg(internalUniqueQueryAlias)
258 .arg(KDb::escapeIdentifier(driver, f->table()->name()))
259 .arg(KDb::escapeIdentifier(driver, f->name()))
260 .arg(internalUniqueQueryAlias)
261 .arg(KDb::escapeIdentifier(driver, boundColumnInfo->aliasOrName()));
262
263 if (!s_additional_fields.isEmpty())
264 s_additional_fields += ", ";
265 const QList<int> visibleColumns(lookupFieldSchema->visibleColumns());
266 KDbEscapedString expression;
267 foreach(int visibleColumnIndex, visibleColumns) {
268//! @todo Add lookup schema option for separator other than ' ' or even option for placeholders like "Name ? ?"
269//! @todo Add possibility for joining the values at client side.
270 if (fieldsExpanded.count() <= visibleColumnIndex) {
271 kdbWarning() << "fieldsExpanded.count() <= (*visibleColumnsIt) : "
272 << fieldsExpanded.count() << " <= " << visibleColumnIndex;
273 return false;
274 }
275 if (!expression.isEmpty())
276 expression += " || ' ' || ";
277 expression += (
278 internalUniqueQueryAlias + '.'
279 + KDb::escapeIdentifier(driver, fieldsExpanded.value(visibleColumnIndex)->aliasOrName())
280 );
281 }
282 s_additional_fields += expression;
283 }
284 else {
285 kdbWarning() << "unsupported record source type" << recordSource.typeName();
286 return false;
287 }
288 }
289 }
290 number++;
291 }
292
293 //add lookup fields
294 if (!s_additional_fields.isEmpty())
295 sql += (", " + s_additional_fields);
296
297 if (driver && options.alsoRetrieveRecordId()) { //append rowid column
298 //! @todo Check if the rowid isn't already part of regular SELECT columns, if so, don't add
300 if (!sql.isEmpty())
301 s = ", ";
302 if (querySchema->masterTable()) {
303 s += KDb::escapeIdentifier(driver, querySchema->tableAliasOrName(querySchema->masterTable()->name()));
304 s += '.';
305 }
306 s += KDbDriverPrivate::behavior(driver)->ROW_ID_FIELD_NAME;
307 sql += s;
308 }
309
310 if (sql.isEmpty()) {
311 sql.prepend("SELECT"); // "SELECT FROM ..." case
312 } else {
313 sql.prepend("SELECT ");
314 }
315 if (!tables->isEmpty() || !subqueries_for_lookup_data.isEmpty()) {
316 sql += " FROM ";
317 KDbEscapedString s_from;
318 number = 0;
319 foreach(KDbTableSchema *table, *tables) {
320 if (!s_from.isEmpty())
321 s_from += ", ";
322 s_from += KDb::escapeIdentifier(driver, table->name());
323 const QString aliasString(querySchema->tableAlias(number));
324 if (!aliasString.isEmpty())
325 s_from.append(" AS ").append(KDb::escapeIdentifier(driver, aliasString));
326 number++;
327 }
328 // add subqueries for lookup data
329 int subqueries_for_lookup_data_counter = 0;
330 foreach(KDbQuerySchema* subQuery, subqueries_for_lookup_data) {
331 if (!s_from.isEmpty())
332 s_from += ", ";
333 KDbEscapedString subSql;
334 if (!selectStatementInternal(&subSql, connection, dialect, subQuery, options, parameters)) {
335 return false;
336 }
337 s_from += '(' + subSql + ") AS "
339 driver,
340 kdb_subquery_prefix + QString::number(subqueries_for_lookup_data_counter++));
341 }
342 sql += s_from;
343 }
344 KDbEscapedString s_where;
345 s_where.reserve(4096);
346
347 //JOINS
348 if (!s_additional_joins.isEmpty()) {
349 sql += ' ' + s_additional_joins + ' ';
350 }
351
352//! @todo: we're using WHERE for joins now; use INNER/LEFT/RIGHT JOIN later
353
354 //WHERE
355 bool wasWhere = false; //for later use
356 foreach(KDbRelationship *rel, *querySchema->relationships()) {
357 if (s_where.isEmpty()) {
358 wasWhere = true;
359 } else
360 s_where += " AND ";
361 KDbEscapedString s_where_sub;
362 foreach(const KDbField::Pair &pair, *rel->fieldPairs()) {
363 if (!s_where_sub.isEmpty())
364 s_where_sub += " AND ";
365 s_where_sub +=
366 KDbEscapedString(KDb::escapeIdentifier(driver, pair.first->table()->name())) + '.' +
367 KDb::escapeIdentifier(driver, pair.first->name()) + " = " +
368 KDb::escapeIdentifier(driver, pair.second->table()->name()) + '.' +
369 KDb::escapeIdentifier(driver, pair.second->name());
370 }
371 if (rel->fieldPairs()->count() > 1) {
372 s_where_sub.prepend('(');
373 s_where_sub += ')';
374 }
375 s_where += s_where_sub;
376 }
377 //EXPLICITLY SPECIFIED WHERE EXPRESSION
378 if (!querySchema->whereExpression().isNull()) {
379 if (wasWhere) {
380 //! @todo () are not always needed
381 s_where = '(' + s_where + ") AND ("
382 + querySchema->whereExpression().toString(driver, paramValuesItPtr) + ')';
383 } else {
384 s_where = querySchema->whereExpression().toString(driver, paramValuesItPtr);
385 }
386 }
387 if (!s_where.isEmpty())
388 sql += " WHERE " + s_where;
389//! @todo (js) add other sql parts
390 //(use wasWhere here)
391
392 // ORDER BY
393 KDbEscapedString orderByString(querySchema->orderByColumnList()->toSqlString(
394 !singleTable /*includeTableName*/, connection, querySchema, dialect));
395 const QVector<int> pkeyFieldsOrder(querySchema->pkeyFieldsOrder(connection));
396 if (dialect == KDb::DriverEscaping && orderByString.isEmpty() && !pkeyFieldsOrder.isEmpty()) {
397 // Native only: add automatic ORDER BY if there is no explicitly defined one
398 // (especially helps when there are complex JOINs)
399 KDbOrderByColumnList automaticPKOrderBy;
400 const KDbQueryColumnInfo::Vector fieldsExpanded(querySchema->fieldsExpanded(connection));
401 foreach(int pkeyFieldsIndex, pkeyFieldsOrder) {
402 if (pkeyFieldsIndex < 0) // no field mentioned in this query
403 continue;
404 if (pkeyFieldsIndex >= fieldsExpanded.count()) {
405 kdbWarning() << "ORDER BY: (*it) >= fieldsExpanded.count() - "
406 << pkeyFieldsIndex << " >= " << fieldsExpanded.count();
407 continue;
408 }
409 KDbQueryColumnInfo *ci = fieldsExpanded[ pkeyFieldsIndex ];
410 automaticPKOrderBy.appendColumn(ci);
411 }
412 orderByString = automaticPKOrderBy.toSqlString(!singleTable /*includeTableName*/,
413 connection, querySchema, dialect);
414 }
415 if (!orderByString.isEmpty())
416 sql += (" ORDER BY " + orderByString);
417
418 //kdbDebug() << sql;
419 *target = sql;
420 return true;
421}
422
424 KDbQuerySchema* querySchema,
425 const KDbSelectStatementOptions& options,
426 const QList<QVariant>& parameters) const
427{
428 return selectStatementInternal(target, d->connection, d->dialect, querySchema, options, parameters);
429}
430
432 KDbQuerySchema* querySchema,
433 const QList<QVariant>& parameters) const
434{
435 return selectStatementInternal(target, d->connection, d->dialect, querySchema, KDbSelectStatementOptions(),
436 parameters);
437}
438
440 KDbTableSchema* tableSchema,
441 const KDbSelectStatementOptions& options) const
442{
443 return generateSelectStatement(target, tableSchema->query(), options);
444}
445
447 const KDbTableSchema& tableSchema) const
448{
449 if (!target) {
450 return false;
451 }
452 // Each SQL identifier needs to be escaped in the generated query.
453 const KDbDriver *driver = d->dialect == KDb::DriverEscaping ? d->connection->driver() : nullptr;
455 sql.reserve(4096);
456 sql = KDbEscapedString("CREATE TABLE ")
457 + KDb::escapeIdentifier(driver, tableSchema.name()) + " (";
458 bool first = true;
459 for (const KDbField *field : *tableSchema.fields()) {
460 if (first)
461 first = false;
462 else
463 sql += ", ";
464 KDbEscapedString v = KDbEscapedString(KDb::escapeIdentifier(driver, field->name())) + ' ';
465 const bool autoinc = field->isAutoIncrement();
466 const bool pk = field->isPrimaryKey() || (autoinc && driver && driver->behavior()->AUTO_INCREMENT_REQUIRES_PK);
467//! @todo warning: ^^^^^ this allows only one autonumber per table when AUTO_INCREMENT_REQUIRES_PK==true!
468 const KDbField::Type type = field->type(); // cache: evaluating type of expressions can be expensive
469 if (autoinc && d->connection->driver()->behavior()->SPECIAL_AUTO_INCREMENT_DEF) {
470 if (pk)
471 v.append(d->connection->driver()->behavior()->AUTO_INCREMENT_TYPE).append(' ')
472 .append(d->connection->driver()->behavior()->AUTO_INCREMENT_PK_FIELD_OPTION);
473 else
474 v.append(d->connection->driver()->behavior()->AUTO_INCREMENT_TYPE).append(' ')
475 .append(d->connection->driver()->behavior()->AUTO_INCREMENT_FIELD_OPTION);
476 } else {
477 if (autoinc && !d->connection->driver()->behavior()->AUTO_INCREMENT_TYPE.isEmpty())
478 v += d->connection->driver()->behavior()->AUTO_INCREMENT_TYPE;
479 else
480 v += d->connection->driver()->sqlTypeName(type, *field);
481
482 if (KDbField::isIntegerType(type) && field->isUnsigned()) {
483 v.append(' ').append(d->connection->driver()->behavior()->UNSIGNED_TYPE_KEYWORD);
484 }
485
486 if (KDbField::isFPNumericType(type) && field->precision() > 0) {
487 if (field->scale() > 0)
488 v += QString::fromLatin1("(%1,%2)").arg(field->precision()).arg(field->scale());
489 else
490 v += QString::fromLatin1("(%1)").arg(field->precision());
491 }
492 else if (type == KDbField::Text) {
493 int realMaxLen;
494 if (d->connection->driver()->behavior()->TEXT_TYPE_MAX_LENGTH == 0) {
495 realMaxLen = field->maxLength(); // allow to skip (N)
496 }
497 else { // max length specified by driver
498 if (field->maxLength() == 0) { // as long as possible
499 realMaxLen = d->connection->driver()->behavior()->TEXT_TYPE_MAX_LENGTH;
500 }
501 else { // not longer than specified by driver
502 realMaxLen = qMin(d->connection->driver()->behavior()->TEXT_TYPE_MAX_LENGTH, field->maxLength());
503 }
504 }
505 if (realMaxLen > 0) {
506 v += QString::fromLatin1("(%1)").arg(realMaxLen);
507 }
508 }
509
510 if (autoinc) {
511 v.append(' ').append(pk ? d->connection->driver()->behavior()->AUTO_INCREMENT_PK_FIELD_OPTION
512 : d->connection->driver()->behavior()->AUTO_INCREMENT_FIELD_OPTION);
513 }
514 else {
515 //! @todo here is automatically a single-field key created
516 if (pk)
517 v += " PRIMARY KEY";
518 }
519 if (!pk && field->isUniqueKey())
520 v += " UNIQUE";
521///@todo IS this ok for all engines?: if (!autoinc && !field->isPrimaryKey() && field->isNotNull())
522 if (!autoinc && !pk && field->isNotNull())
523 v += " NOT NULL"; //only add not null option if no autocommit is set
524 if (d->connection->driver()->supportsDefaultValue(*field) && field->defaultValue().isValid()) {
525 KDbEscapedString valToSql(d->connection->driver()->valueToSql(field, field->defaultValue()));
526 if (!valToSql.isEmpty()) //for sanity
527 v += " DEFAULT " + valToSql;
528 }
529 }
530 sql += v;
531 }
532 sql += ')';
533 *target = sql;
534 return true;
535}
Provides database connection, allowing queries and data modification.
KDbDriver * driver() const
KDbTableSchema * tableSchema(int tableId)
KDbQuerySchema * querySchema(int queryId)
QString AUTO_INCREMENT_FIELD_OPTION
"AUTO_INCREMENT" by default, used as add-in word to field definition May be also used as full definit...
QString AUTO_INCREMENT_PK_FIELD_OPTION
"AUTO_INCREMENT PRIMARY KEY" by default, used as add-in word to field definition May be also used as ...
QString AUTO_INCREMENT_TYPE
"" by default, used as type string for autoinc.
QString UNSIGNED_TYPE_KEYWORD
"UNSIGNED" by default
Database driver's abstraction.
Definition KDbDriver.h:50
virtual QString sqlTypeName(KDbField::Type type, const KDbField &field) const
virtual bool supportsDefaultValue(const KDbField &field) const
Definition KDbDriver.h:407
KDbDriverBehavior * behavior()
Returns structure that provides detailed information about driver's default behavior.
Definition KDbDriver.cpp:74
virtual KDbEscapedString valueToSql(KDbField::Type ftype, const QVariant &v) const
Specialized string for escaping.
bool isNull() const
KDbEscapedString toString(const KDbDriver *driver, KDbQuerySchemaParameterValueListIterator *params=nullptr, KDb::ExpressionCallStack *callStack=nullptr) const
virtual KDbField * field(int id)
KDbFieldList * subList(const QString &n1, const QString &n2=QString(), const QString &n3=QString(), const QString &n4=QString(), const QString &n5=QString(), const QString &n6=QString(), const QString &n7=QString(), const QString &n8=QString(), const QString &n9=QString(), const QString &n10=QString(), const QString &n11=QString(), const QString &n12=QString(), const QString &n13=QString(), const QString &n14=QString(), const QString &n15=QString(), const QString &n16=QString(), const QString &n17=QString(), const QString &n18=QString())
int fieldCount() const
KDbEscapedString sqlFieldsList(KDbConnection *conn, const QString &separator=QLatin1String(","), const QString &tableOrAlias=QString(), KDb::IdentifierEscapingType escapingType=KDb::DriverEscaping) const
KDbField::List * fields()
Meta-data for a field.
Definition KDbField.h:72
KDbTableSchema * table()
Definition KDbField.cpp:585
QString name() const
Definition KDbField.cpp:256
bool isQueryAsterisk() const
Definition KDbField.h:640
bool isExpression() const
bool isFPNumericType() const
Definition KDbField.h:335
bool isIntegerType() const
Definition KDbField.h:326
QPair< KDbField *, KDbField * > Pair
fields pair
Definition KDbField.h:80
KDbExpression expression()
Record source information that can be specified for the lookup field schema.
@ Table
table as lookup record source
@ Query
named query as lookup record source
Provides information about lookup field's setup.
QList< int > visibleColumns() const
KDbLookupFieldSchemaRecordSource recordSource() const
A builder for generating various types of native SQL statements.
KDbNativeStatementBuilder(KDbConnection *connection, KDb::IdentifierEscapingType dialect)
Creates a new native builder object.
bool generateCreateTableStatement(KDbEscapedString *target, const KDbTableSchema &tableSchema) const
bool generateSelectStatement(KDbEscapedString *target, KDbQuerySchema *querySchema, const KDbSelectStatementOptions &options, const QList< QVariant > &parameters=QList< QVariant >()) const
KDbOrderByColumnList provides list of sorted columns for a query schema.
KDbEscapedString toSqlString(bool includeTableNames, KDbConnection *conn, KDbQuerySchema *query, KDb::IdentifierEscapingType escapingType=KDb::DriverEscaping) const
Return an SQL string like "name ASC, 2 DESC" usable for building an SQL statement.
void appendColumn(KDbQueryColumnInfo *columnInfo, KDbOrderByColumn::SortOrder order=KDbOrderByColumn::SortOrder::Ascending)
KDbQueryAsterisk class encapsulates information about single asterisk in query definition.
bool isSingleTableAsterisk() const
const KDbTableSchema * table() const
Helper class that assigns additional information for the column in a query.
QString aliasOrName() const
An iterator for a list of values of query schema parameters Allows to iterate over parameters and ret...
KDbQuerySchema provides information about database query.
KDbQueryColumnInfo::Vector fieldsExpanded(KDbConnection *conn, FieldsExpandedMode mode=FieldsExpandedMode::Default) const
KDbExpression whereExpression() const
KDbEscapedString statement() const
QString columnAlias(int position) const
int tableBoundToColumn(int columnPosition) const
bool isColumnVisible(int position) const
KDbOrderByColumnList * orderByColumnList()
QString tableAliasOrName(const QString &tableName) const
QVector< int > pkeyFieldsOrder(KDbConnection *conn) const
QString tableAlias(int position) const
KDbTableSchema * masterTable() const
QList< KDbRelationship * > * relationships() const
QList< KDbTableSchema * > * tables() const
Options used in KDbNativeStatementBuilder::generateSelectStatement()
KDbLookupFieldSchema * lookupFieldSchema(const KDbField &field)
KDbQuerySchema * query()
KDB_EXPORT QString escapeIdentifier(const QString &string)
Definition KDb.cpp:1334
IdentifierEscapingType
Escaping type for identifiers.
Definition KDbGlobal.h:144
@ DriverEscaping
Identifiers are escaped by driver.
Definition KDbGlobal.h:145
T iifNotEmpty(const T &string, const T &stringIfEmpty)
Definition KDb.h:820
KIOCORE_EXPORT QString number(KIO::filesize_t size)
qsizetype count() const const
bool isEmpty() const const
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 12 2024 12:05:27 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.