QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgssqlstatement.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssqlstatement.cpp
3  -------------------
4  begin : April 2016
5  copyright : (C) 2011 by Martin Dobias
6  copyright : (C) 2016 by Even Rouault
7  email : even.rouault at spatialys.com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgssqlstatement.h"
18 
19 #include <cmath>
20 #include <limits>
21 
22 static const QRegExp IDENTIFIER_RE( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" );
23 
24 // from parser
25 extern QgsSQLStatement::Node *parse( const QString &str, QString &parserErrorMsg );
26 
28 // operators
29 
31 {
32  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
33  "OR", "AND",
34  "=", "<>", "<=", ">=", "<", ">", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
35  "+", "-", "*", "/", "//", "%", "^",
36  "||"
37 };
38 
40 {
41  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
42  "NOT", "-"
43 };
44 
45 const char *QgsSQLStatement::JOIN_TYPE_TEXT[] =
46 {
47  // this must correspond (number and order of element) to the declaration of the enum JoinType
48  "", "LEFT", "LEFT OUTER", "RIGHT", "RIGHT OUTER", "CROSS", "INNER", "FULL"
49 };
50 
52 
54 {
55  if ( !mStatement.isNull() )
56  return mStatement;
57  else
58  return dump();
59 }
60 
61 QString QgsSQLStatement::dump() const
62 {
63  if ( !mRootNode )
64  return tr( "(no root)" );
65 
66  return mRootNode->dump();
67 }
68 
69 QString QgsSQLStatement::quotedIdentifier( QString name )
70 {
71  return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
72 }
73 
74 QString QgsSQLStatement::quotedIdentifierIfNeeded( const QString &name )
75 {
76  // This might not be complete, but it must be at least what we recognize
77  static const char *const RESERVED_KEYWORDS[] =
78  {
79  "AND", "OR", "NOT", "LIKE", "IN", "IS", "BETWEEN", "NULL", "SELECT", "ALL", "DISTINCT", "CAST", "AS",
80  "FROM", "JOIN", "ON", "USING", "WHERE", "ORDER", "BY", "ASC", "DESC",
81  "LEFT", "RIGHT", "INNER", "OUTER", "CROSS", "FULL", "NATURAL", "UNION",
82  "OFFSET", "LIMIT", "GROUP", "HAVING"
83  };
84 
85  for ( size_t i = 0; i < sizeof( RESERVED_KEYWORDS ) / sizeof( RESERVED_KEYWORDS[0] ); ++i )
86  {
87  if ( name.compare( QString( RESERVED_KEYWORDS[i] ), Qt::CaseInsensitive ) == 0 )
88  {
89  return quotedIdentifier( name );
90  }
91  }
92  return IDENTIFIER_RE.exactMatch( name ) ? name : quotedIdentifier( name );
93 }
94 
96 {
97  if ( text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' )
98  {
99  // strip double quotes on start,end
100  text = text.mid( 1, text.length() - 2 );
101 
102  // make single "double quotes" from double "double quotes"
103  text.replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
104  }
105  return text;
106 }
107 
108 QString QgsSQLStatement::quotedString( QString text )
109 {
110  text.replace( '\'', QLatin1String( "''" ) );
111  text.replace( '\\', QLatin1String( "\\\\" ) );
112  text.replace( '\n', QLatin1String( "\\n" ) );
113  text.replace( '\t', QLatin1String( "\\t" ) );
114  return QStringLiteral( "'%1'" ).arg( text );
115 }
116 
117 QgsSQLStatement::QgsSQLStatement( const QString &expr )
118 {
120  mStatement = expr;
121 }
122 
124 {
126  mStatement = other.mStatement;
127 }
128 
130 {
131  if ( &other != this )
132  {
133  delete mRootNode;
134  mParserErrorString.clear();
136  mStatement = other.mStatement;
137  }
138  return *this;
139 }
140 
142 {
143  delete mRootNode;
144 }
145 
146 bool QgsSQLStatement::hasParserError() const { return !mParserErrorString.isNull(); }
147 
149 
151 {
152  if ( mRootNode )
153  mRootNode->accept( v );
154 }
155 
157 {
158  return mRootNode;
159 }
160 
162 {
163  Q_FOREACH ( QgsSQLStatement::NodeTableDef *table, n.tables() )
164  {
165  table->accept( *this );
166  }
167  Q_FOREACH ( QgsSQLStatement::NodeSelectedColumn *column, n.columns() )
168  {
169  column->accept( *this );
170  }
171  Q_FOREACH ( QgsSQLStatement::NodeJoin *join, n.joins() )
172  {
173  join->accept( *this );
174  }
175  QgsSQLStatement::Node *where = n.where();
176  if ( where )
177  where->accept( *this );
178  Q_FOREACH ( QgsSQLStatement::NodeColumnSorted *column, n.orderBy() )
179  {
180  column->accept( *this );
181  }
182 }
183 
185 {
186  n.tableDef()->accept( *this );
187  QgsSQLStatement::Node *expr = n.onExpr();
188  if ( expr )
189  expr->accept( *this );
190 }
191 
198 {
199  public:
200  typedef QPair<QString, QString> TableColumnPair;
201 
206 
207  void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
208  void visit( const QgsSQLStatement::NodeTableDef &n ) override;
209 
210  QSet<QString> tableNamesDeclared;
211  QSet<TableColumnPair> tableNamesReferenced;
212 };
213 
215 {
216  if ( !n.tableName().isEmpty() )
217  tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
219 }
220 
222 {
223  tableNamesDeclared.insert( n.alias().isEmpty() ? n.name() : n.alias() );
225 }
226 
227 bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
228 {
229  errorMsgOut.clear();
230  if ( !mRootNode )
231  {
232  errorMsgOut = tr( "No root node" );
233  return false;
234  }
236  mRootNode->accept( v );
237 
239  {
240  if ( !v.tableNamesDeclared.contains( pair.first ) )
241  {
242  if ( !errorMsgOut.isEmpty() )
243  errorMsgOut += QLatin1String( " " );
244  errorMsgOut += QString( tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ) ).arg( pair.first, pair.second );
245  }
246  }
247 
248  return errorMsgOut.isEmpty();
249 }
250 
252 // nodes
253 
255 {
256  for ( QgsSQLStatement::Node *node : mList )
257  {
258  node->accept( v );
259  }
260 }
261 
263 {
264  NodeList *nl = new NodeList;
265  Q_FOREACH ( Node *node, mList )
266  {
267  nl->mList.append( node->clone() );
268  }
269 
270  return nl;
271 }
272 
274 {
275  QString msg;
276  bool first = true;
277  Q_FOREACH ( Node *n, mList )
278  {
279  if ( !first ) msg += QLatin1String( ", " );
280  else first = false;
281  msg += n->dump();
282  }
283  return msg;
284 }
285 
286 
287 //
288 
290 {
291  return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
292 }
293 
295 {
296  return new NodeUnaryOperator( mOp, mOperand->clone() );
297 }
298 
299 //
300 
302 {
303  // see left/right in qgsexpressionparser.yy
304  switch ( mOp )
305  {
306  case boOr:
307  return 1;
308 
309  case boAnd:
310  return 2;
311 
312  case boEQ:
313  case boNE:
314  case boLE:
315  case boGE:
316  case boLT:
317  case boGT:
318  case boLike:
319  case boILike:
320  case boNotLike:
321  case boNotILike:
322  case boIs:
323  case boIsNot:
324  return 3;
325 
326  case boPlus:
327  case boMinus:
328  return 4;
329 
330  case boMul:
331  case boDiv:
332  case boIntDiv:
333  case boMod:
334  return 5;
335 
336  case boPow:
337  return 6;
338 
339  case boConcat:
340  return 7;
341  }
342  Q_ASSERT( false && "unexpected binary operator" );
343  return -1;
344 }
345 
347 {
348  // see left/right in qgsexpressionparser.yy
349  switch ( mOp )
350  {
351  case boOr:
352  case boAnd:
353  case boEQ:
354  case boNE:
355  case boLE:
356  case boGE:
357  case boLT:
358  case boGT:
359  case boLike:
360  case boILike:
361  case boNotLike:
362  case boNotILike:
363  case boIs:
364  case boIsNot:
365  case boPlus:
366  case boMinus:
367  case boMul:
368  case boDiv:
369  case boIntDiv:
370  case boMod:
371  case boConcat:
372  return true;
373 
374  case boPow:
375  return false;
376  }
377  Q_ASSERT( false && "unexpected binary operator" );
378  return false;
379 }
380 
382 {
386 
387  QString rdump( mOpRight->dump() );
388 
389  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
390  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
391  {
392  rdump.prepend( '(' ).append( ')' );
393  }
394 
395  QString fmt;
396  if ( leftAssociative() )
397  {
398  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
399  fmt += QLatin1String( " %2 " );
400  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
401  }
402  else
403  {
404  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
405  fmt += QLatin1String( " %2 " );
406  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
407  }
408 
409  return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
410 }
411 
413 {
414  return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
415 }
416 
417 //
418 
420 {
421  return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
422 }
423 
425 {
426  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
427 }
428 
429 //
430 
432 {
433  return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
434 }
435 
437 {
438  return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
439 }
440 
441 //
442 
444 {
445  return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
446 }
447 
449 {
450  return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
451 }
452 
453 //
454 
456 {
457  if ( mValue.isNull() )
458  return QStringLiteral( "NULL" );
459 
460  switch ( mValue.type() )
461  {
462  case QVariant::Int:
463  return QString::number( mValue.toInt() );
464  case QVariant::LongLong:
465  return QString::number( mValue.toLongLong() );
466  case QVariant::Double:
467  return QString::number( mValue.toDouble() );
468  case QVariant::String:
469  return quotedString( mValue.toString() );
470  case QVariant::Bool:
471  return mValue.toBool() ? "TRUE" : "FALSE";
472  default:
473  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
474  }
475 }
476 
478 {
479  return new NodeLiteral( mValue );
480 }
481 
482 //
483 
485 {
486  QString ret;
487  if ( mDistinct )
488  ret += QLatin1String( "DISTINCT " );
489  if ( !mTableName.isEmpty() )
490  {
491  ret += quotedIdentifierIfNeeded( mTableName );
492  ret += '.';
493  }
494  ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
495  return ret;
496 }
497 
499 {
500  return cloneThis();
501 }
502 
504 {
505  NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
506  newColumnRef->setDistinct( mDistinct );
507  return newColumnRef;
508 }
509 
510 //
511 
513 {
514  QString ret;
515  ret += mColumnNode->dump();
516  if ( !mAlias.isEmpty() )
517  {
518  ret += QLatin1String( " AS " );
519  ret += quotedIdentifierIfNeeded( mAlias );
520  }
521  return ret;
522 }
523 
525 {
526  NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
527  newObj->setAlias( mAlias );
528  return newObj;
529 }
530 
532 {
533  return cloneThis();
534 }
535 //
536 
538 {
539  QString ret;
540  ret = quotedIdentifierIfNeeded( mName );
541  if ( !mAlias.isEmpty() )
542  {
543  ret += QLatin1String( " AS " );
544  ret += quotedIdentifierIfNeeded( mAlias );
545  }
546  return ret;
547 }
548 
550 {
551  return new NodeTableDef( mName, mAlias );
552 }
553 
555 {
556  return cloneThis();
557 }
558 
559 //
560 
562 {
563  qDeleteAll( mTableList );
564  qDeleteAll( mColumns );
565  qDeleteAll( mJoins );
566  delete mWhere;
567  qDeleteAll( mOrderBy );
568 }
569 
571 {
572  QString ret = QStringLiteral( "SELECT " );
573  if ( mDistinct )
574  ret += QLatin1String( "DISTINCT " );
575  bool bFirstColumn = true;
576  Q_FOREACH ( QgsSQLStatement::NodeSelectedColumn *column, mColumns )
577  {
578  if ( !bFirstColumn )
579  ret += QLatin1String( ", " );
580  bFirstColumn = false;
581  ret += column->dump();
582  }
583  ret += QLatin1String( " FROM " );
584  bool bFirstTable = true;
585  Q_FOREACH ( QgsSQLStatement::NodeTableDef *table, mTableList )
586  {
587  if ( !bFirstTable )
588  ret += QLatin1String( ", " );
589  bFirstTable = false;
590  ret += table->dump();
591  }
592  Q_FOREACH ( QgsSQLStatement::NodeJoin *join, mJoins )
593  {
594  ret += ' ';
595  ret += join->dump();
596  }
597  if ( mWhere )
598  {
599  ret += QLatin1String( " WHERE " );
600  ret += mWhere->dump();
601  }
602  if ( !mOrderBy.isEmpty() )
603  {
604  ret += QLatin1String( " ORDER BY " );
605  bool bFirst = true;
606  Q_FOREACH ( QgsSQLStatement::NodeColumnSorted *orderBy, mOrderBy )
607  {
608  if ( !bFirst )
609  ret += QLatin1String( ", " );
610  bFirst = false;
611  ret += orderBy->dump();
612  }
613  }
614  return ret;
615 }
616 
618 {
619  QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
620  Q_FOREACH ( QgsSQLStatement::NodeSelectedColumn *column, mColumns )
621  {
622  newColumnList.push_back( column->cloneThis() );
623  }
624  QList<QgsSQLStatement::NodeTableDef *> newTableList;
625  Q_FOREACH ( QgsSQLStatement::NodeTableDef *table, mTableList )
626  {
627  newTableList.push_back( table->cloneThis() );
628  }
629  QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
630  Q_FOREACH ( QgsSQLStatement::NodeJoin *join, mJoins )
631  {
632  newSelect->appendJoin( join->cloneThis() );
633  }
634  if ( mWhere )
635  {
636  newSelect->setWhere( mWhere->clone() );
637  }
638  QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
639  Q_FOREACH ( QgsSQLStatement::NodeColumnSorted *columnSorted, mOrderBy )
640  {
641  newOrderByList.push_back( columnSorted->cloneThis() );
642  }
643  newSelect->setOrderBy( newOrderByList );
644  return newSelect;
645 }
646 
647 //
648 
650 {
651  QString ret;
652  if ( mType != jtDefault )
653  {
654  ret += JOIN_TYPE_TEXT[mType];
655  ret += QLatin1String( " " );
656  }
657  ret += QLatin1String( "JOIN " );
658  ret += mTableDef->dump();
659  if ( mOnExpr )
660  {
661  ret += QLatin1String( " ON " );
662  ret += mOnExpr->dump();
663  }
664  else
665  {
666  ret += QLatin1String( " USING (" );
667  bool first = true;
668  Q_FOREACH ( QString column, mUsingColumns )
669  {
670  if ( !first )
671  ret += QLatin1String( ", " );
672  first = false;
673  ret += quotedIdentifierIfNeeded( column );
674  }
675  ret += QLatin1String( ")" );
676  }
677  return ret;
678 }
679 
681 {
682  return cloneThis();
683 }
684 
686 {
687  if ( mOnExpr )
688  return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
689  else
690  return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
691 }
692 
693 //
694 
696 {
697  QString ret;
698  ret = mColumn->dump();
699  if ( !mAsc )
700  ret += QLatin1String( " DESC" );
701  return ret;
702 }
703 
705 {
706  return cloneThis();
707 }
708 
710 {
711  return new NodeColumnSorted( mColumn->cloneThis(), mAsc );
712 }
713 
714 //
715 
717 {
718  QString ret( QStringLiteral( "CAST(" ) );
719  ret += mNode->dump();
720  ret += QLatin1String( " AS " );
721  ret += mType;
722  ret += ')';
723  return ret;
724 }
725 
727 {
728  return new NodeCast( mNode->clone(), mType );
729 }
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString name() const
The name of the column.
QString parserErrorString() const
Returns parser error.
static const char * JOIN_TYPE_TEXT[]
QString alias() const
Table alias.
void setOrderBy(const QList< QgsSQLStatement::NodeColumnSorted * > &orderBy)
Sets order by columns.
void appendJoin(QgsSQLStatement::NodeJoin *join)
Append a join.
Function with a name and arguments node.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void accept(QgsSQLStatement::Visitor &v) const
Accept visitor.
virtual QString dump() const
Dump list.
QString dump() const override
Abstract virtual dump method.
static const char * BINARY_OPERATOR_TEXT[]
void acceptVisitor(QgsSQLStatement::Visitor &v) const
Entry function for the visitor pattern.
QList< QgsSQLStatement::NodeSelectedColumn * > columns() const
Returns the list of columns.
void visit(const QgsSQLStatement::NodeColumnRef &n) override
Visit NodeColumnRef.
QString statement() const
Returns the original, unmodified statement string.
const QgsSQLStatement::Node * rootNode() const
Returns root node of the statement. Root node is null is parsing has failed.
QString dump() const override
Abstract virtual dump method.
Binary logical/arithmetical operator (AND, OR, =, +, ...)
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
QString dump() const
Returns the statement string, constructed from the internal abstract syntax tree. ...
Abstract node class.
QgsSQLStatement::Node * mRootNode
void accept(QgsSQLStatement::Visitor &v) const override
Support the visitor pattern.
void setWhere(QgsSQLStatement::Node *where)
Sets where clause.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
A visitor that recursively explores all children.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void accept(QgsSQLStatement::Visitor &v) const override
Support the visitor pattern.
Class for parsing SQL statements.
bool doBasicValidationChecks(QString &errorMsgOut) const
Performs basic validity checks.
QString dump() const override
Abstract virtual dump method.
QPair< QString, QString > TableColumnPair
virtual QString dump() const =0
Abstract virtual dump method.
virtual QgsSQLStatement::Node * clone() const =0
Generate a clone of this node.
void accept(QgsSQLStatement::Visitor &v) const override
Support the visitor pattern.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::UnaryOperator op() const
Operator.
QgsSQLStatement::NodeList * clone() const
Creates a deep copy of this list. Ownership is transferred to the caller.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
Literal value (integer, integer64, double, string)
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::NodeJoin * cloneThis() const
Clone with same type return.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void setAlias(const QString &alias)
Sets alias name.
Unary logicial/arithmetical operator ( NOT, - )
QString dump() const override
Abstract virtual dump method.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QList< QgsSQLStatement::NodeColumnSorted * > orderBy() const
Returns the list of order by columns.
QSet< TableColumnPair > tableNamesReferenced
Reference to a column.
&#39;X BETWEEN y and z&#39; operator
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::NodeColumnSorted * cloneThis() const
Clone with same type return.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
int precedence() const
Precedence.
void accept(QgsSQLStatement::Visitor &v) const override
Support the visitor pattern.
QgsSQLStatement & operator=(const QgsSQLStatement &other)
Create a copy of this statement.
QgsSQLStatement::NodeTableDef * cloneThis() const
Clone with same type return.
static QString stripQuotedIdentifier(QString text)
Remove double quotes from an identifier.
virtual void accept(QgsSQLStatement::Visitor &v) const =0
Support the visitor pattern.
QgsSQLStatement::NodeSelectedColumn * cloneThis() const
Clone with same type return.
QString dump() const override
Abstract virtual dump method.
void setDistinct(bool distinct=true)
Sets whether this is prefixed by DISTINCT.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
static QString quotedIdentifierIfNeeded(const QString &name)
Returns a quoted column reference (in double quotes) if needed, or otherwise the original string...
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void visit(const QgsSQLStatement::NodeUnaryOperator &n) override
Visit NodeUnaryOperator.
static const char * UNARY_OPERATOR_TEXT[]
Support for visitor pattern - algorithms dealing with the statement may be implemented without modify...
QgsSQLStatement::Node * where() const
Returns the where clause.
QString name() const
Table name.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
QString dump() const override
Abstract virtual dump method.
QString dump() const override
Abstract virtual dump method.
static QString quotedIdentifier(QString name)
Returns a quoted column reference (in double quotes)
QgsSQLStatement::NodeColumnRef * cloneThis() const
Clone with same type return.
bool hasParserError() const
Returns true if an error occurred when parsing the input statement.
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg)
bool leftAssociative() const
Is left associative ?
&#39;x IN (y, z)&#39; operator
QString tableName() const
The name of the table. May be empty.
QgsSQLStatement(const QString &statement)
Creates a new statement based on the provided string.
QString mParserErrorString