KDb

KDbNativeStatementBuilder.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003-2017 JarosÅ‚aw Staniek <[email protected]>
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 
33 KDbSelectStatementOptions::~KDbSelectStatementOptions()
34 {
35 }
36 
37 //================================================
38 
39 class Q_DECL_HIDDEN KDbNativeStatementBuilder::Private
40 {
41 public:
42  Private() {}
43  //! @todo use equivalent of QPointer<KDbConnection>
44  KDbConnection *connection;
46 
47 private:
48  Q_DISABLE_COPY(Private)
49 };
50 
51 //================================================
52 
55  : d(new Private)
56 {
57  d->connection = connection;
58  d->dialect = dialect;
59 }
60 
61 KDbNativeStatementBuilder::~KDbNativeStatementBuilder()
62 {
63  delete d;
64 }
65 
66 static 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();
187  if (recordSource.type() == KDbLookupFieldSchemaRecordSource::Type::Table) {
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;
454  KDbEscapedString sql;
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 }
KDB_EXPORT QString escapeIdentifier(const QString &string)
Definition: KDb.cpp:1334
KDbQueryColumnInfo::Vector fieldsExpanded(KDbConnection *conn, FieldsExpandedMode mode=FieldsExpandedMode::Default) const
QString columnAlias(int position) const
Provides information about lookup field's setup.
Options used in KDbNativeStatementBuilder::generateSelectStatement()
QString number(int n, int base)
QString tableAliasOrName(const QString &tableName) const
An iterator for a list of values of query schema parameters Allows to iterate over parameters and ret...
int tableBoundToColumn(int columnPosition) const
KDbQuerySchema * query()
KDbTableSchema * masterTable() const
bool isQueryAsterisk() const
Definition: KDbField.h:640
KDbTableSchema * table()
Definition: KDbField.cpp:585
int count(const T &value) const const
virtual KDbField * field(int id)
@ Text
Definition: KDbField.h:98
A builder for generating various types of native SQL statements.
Specialized string for escaping.
KDbExpression whereExpression() const
@ Query
named query as lookup record source
bool generateSelectStatement(KDbEscapedString *target, KDbQuerySchema *querySchema, const KDbSelectStatementOptions &options, const QList< QVariant > &parameters=QList< QVariant >()) const
QString name
KDbOrderByColumnList * orderByColumnList()
Database driver's abstraction.
Definition: KDbDriver.h:49
@ DriverEscaping
Identifiers are escaped by driver.
Definition: KDbGlobal.h:145
QVector< int > pkeyFieldsOrder(KDbConnection *conn) const
KDbExpression expression()
Definition: KDbField.cpp:1011
bool isFPNumericType() const
Definition: KDbField.h:335
QList< KDbTableSchema * > * tables() const
void appendColumn(KDbQueryColumnInfo *columnInfo, KDbOrderByColumn::SortOrder order=KDbOrderByColumn::SortOrder::Ascending)
QString aliasOrName() const
Record source information that can be specified for the lookup field schema.
bool isIntegerType() const
Definition: KDbField.h:326
KDbQuerySchema * querySchema(int queryId)
QList< KDbRelationship * > * relationships() const
@ Table
table as lookup record source
KDbLookupFieldSchemaRecordSource recordSource() const
bool isEmpty() const const
KDbEscapedString sqlFieldsList(KDbConnection *conn, const QString &separator=QLatin1String(","), const QString &tableOrAlias=QString(), KDb::IdentifierEscapingType escapingType=KDb::DriverEscaping) const
KDbEscapedString toString(const KDbDriver *driver, KDbQuerySchemaParameterValueListIterator *params=nullptr, KDb::ExpressionCallStack *callStack=nullptr) const
T iifNotEmpty(const T &string, const T &stringIfEmpty)
Definition: KDb.h:820
const KDbTableSchema * table() const
bool isEmpty() const const
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())
KDbDriverBehavior * behavior()
Returns structure that provides detailed information about driver's default behavior.
Definition: KDbDriver.cpp:74
KDbTableSchema * tableSchema(int tableId)
KDbField::List * fields()
KDbNativeStatementBuilder(KDbConnection *connection, KDb::IdentifierEscapingType dialect)
Creates a new native builder object.
KDbQuerySchema provides information about database query.
QList< int > visibleColumns() const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
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.
QString fromLatin1(const char *str, int size)
bool isNull() const
bool isSingleTableAsterisk() const
bool generateCreateTableStatement(KDbEscapedString *target, const KDbTableSchema &tableSchema) const
bool isColumnVisible(int position) const
Meta-data for a field.
Definition: KDbField.h:71
bool isExpression() const
Definition: KDbField.cpp:1006
int fieldCount() const
KDbEscapedString statement() const
KIOCORE_EXPORT QString number(KIO::filesize_t size)
KDbQueryAsterisk class encapsulates information about single asterisk in query definition.
KDbOrderByColumnList provides list of sorted columns for a query schema.
Provides database connection, allowing queries and data modification.
Definition: KDbConnection.h:51
QString name() const
Definition: KDbField.cpp:256
KDbDriver * driver() const
Helper class that assigns additional information for the column in a query.
IdentifierEscapingType
Escaping type for identifiers.
Definition: KDbGlobal.h:144
QString tableAlias(int position) const
KDbLookupFieldSchema * lookupFieldSchema(const KDbField &field)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Nov 29 2023 04:11:25 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.