QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 #include "qgis.h"
19 
20 #include <cmath>
21 #include <limits>
22 
23 
24 // from parser
25 extern QgsSQLStatement::Node *parse( const QString &str, QString &parserErrorMsg, bool allowFragments );
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  static const QRegExp IDENTIFIER_RE( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" );
93  return IDENTIFIER_RE.exactMatch( name ) ? name : quotedIdentifier( name );
94 }
95 
97 {
98  if ( text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' )
99  {
100  // strip double quotes on start,end
101  text = text.mid( 1, text.length() - 2 );
102 
103  // make single "double quotes" from double "double quotes"
104  text.replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
105  }
106  return text;
107 }
108 
110 {
111  if ( text.length() >= 2 && text[0] == '[' && text[text.length() - 1] == ']' )
112  {
113  // strip square brackets on start,end
114  text = text.mid( 1, text.length() - 2 );
115  }
116  return text;
117 }
118 
119 QString QgsSQLStatement::quotedString( QString text )
120 {
121  text.replace( '\'', QLatin1String( "''" ) );
122  text.replace( '\\', QLatin1String( "\\\\" ) );
123  text.replace( '\n', QLatin1String( "\\n" ) );
124  text.replace( '\t', QLatin1String( "\\t" ) );
125  return QStringLiteral( "'%1'" ).arg( text );
126 }
127 
128 QgsSQLStatement::QgsSQLStatement( const QString &expr )
129  : QgsSQLStatement( expr, false )
130 {
131 }
132 
133 QgsSQLStatement::QgsSQLStatement( const QString &expr, bool allowFragments )
134  : mAllowFragments( allowFragments )
135 {
137  mStatement = expr;
138 }
139 
141 {
143  mStatement = other.mStatement;
144 }
145 
147 {
148  if ( &other != this )
149  {
150  delete mRootNode;
151  mParserErrorString.clear();
153  mStatement = other.mStatement;
154  }
155  return *this;
156 }
157 
159 {
160  delete mRootNode;
161 }
162 
163 bool QgsSQLStatement::hasParserError() const { return !mParserErrorString.isNull() || ( !mRootNode && !mAllowFragments ); }
164 
166 
168 {
169  if ( mRootNode )
170  mRootNode->accept( v );
171 }
172 
174 {
175  return mRootNode;
176 }
177 
179 {
180  const auto constTables = n.tables();
181  for ( QgsSQLStatement::NodeTableDef *table : constTables )
182  {
183  table->accept( *this );
184  }
185  const auto constColumns = n.columns();
186  for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
187  {
188  column->accept( *this );
189  }
190  const auto constJoins = n.joins();
191  for ( QgsSQLStatement::NodeJoin *join : constJoins )
192  {
193  join->accept( *this );
194  }
195  QgsSQLStatement::Node *where = n.where();
196  if ( where )
197  where->accept( *this );
198  const auto constOrderBy = n.orderBy();
199  for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
200  {
201  column->accept( *this );
202  }
203 }
204 
206 {
207  n.tableDef()->accept( *this );
208  QgsSQLStatement::Node *expr = n.onExpr();
209  if ( expr )
210  expr->accept( *this );
211 }
212 
219 {
220  public:
221  typedef QPair<QString, QString> TableColumnPair;
222 
227 
228  void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
229  void visit( const QgsSQLStatement::NodeTableDef &n ) override;
230 
231  QSet<QString> tableNamesDeclared;
232  QSet<TableColumnPair> tableNamesReferenced;
233 };
234 
236 {
237  if ( !n.tableName().isEmpty() )
238  tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
240 }
241 
243 {
244  tableNamesDeclared.insert( n.alias().isEmpty() ? n.name() : n.alias() );
246 }
247 
248 bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
249 {
250  errorMsgOut.clear();
251  if ( !mRootNode )
252  {
253  errorMsgOut = tr( "No root node" );
254  return false;
255  }
257  mRootNode->accept( v );
258 
259  for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
260  {
261  if ( !v.tableNamesDeclared.contains( pair.first ) )
262  {
263  if ( !errorMsgOut.isEmpty() )
264  errorMsgOut += QLatin1Char( ' ' );
265  errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
266  }
267  }
268 
269  return errorMsgOut.isEmpty();
270 }
271 
273 // nodes
274 
276 {
277  for ( QgsSQLStatement::Node *node : mList )
278  {
279  node->accept( v );
280  }
281 }
282 
284 {
285  NodeList *nl = new NodeList;
286  const auto constMList = mList;
287  for ( Node *node : constMList )
288  {
289  nl->mList.append( node->clone() );
290  }
291 
292  return nl;
293 }
294 
296 {
297  QString msg;
298  bool first = true;
299  const auto constMList = mList;
300  for ( Node *n : constMList )
301  {
302  if ( !first ) msg += QLatin1String( ", " );
303  else first = false;
304  msg += n->dump();
305  }
306  return msg;
307 }
308 
309 
310 //
311 
313 {
314  return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
315 }
316 
318 {
319  return new NodeUnaryOperator( mOp, mOperand->clone() );
320 }
321 
322 //
323 
325 {
326  // see left/right in qgsexpressionparser.yy
327  switch ( mOp )
328  {
329  case boOr:
330  return 1;
331 
332  case boAnd:
333  return 2;
334 
335  case boEQ:
336  case boNE:
337  case boLE:
338  case boGE:
339  case boLT:
340  case boGT:
341  case boLike:
342  case boILike:
343  case boNotLike:
344  case boNotILike:
345  case boIs:
346  case boIsNot:
347  return 3;
348 
349  case boPlus:
350  case boMinus:
351  return 4;
352 
353  case boMul:
354  case boDiv:
355  case boIntDiv:
356  case boMod:
357  return 5;
358 
359  case boPow:
360  return 6;
361 
362  case boConcat:
363  return 7;
364  }
365  Q_ASSERT( false && "unexpected binary operator" );
366  return -1;
367 }
368 
370 {
371  // see left/right in qgsexpressionparser.yy
372  switch ( mOp )
373  {
374  case boOr:
375  case boAnd:
376  case boEQ:
377  case boNE:
378  case boLE:
379  case boGE:
380  case boLT:
381  case boGT:
382  case boLike:
383  case boILike:
384  case boNotLike:
385  case boNotILike:
386  case boIs:
387  case boIsNot:
388  case boPlus:
389  case boMinus:
390  case boMul:
391  case boDiv:
392  case boIntDiv:
393  case boMod:
394  case boConcat:
395  return true;
396 
397  case boPow:
398  return false;
399  }
400  Q_ASSERT( false && "unexpected binary operator" );
401  return false;
402 }
403 
405 {
409 
410  QString rdump( mOpRight->dump() );
411 
412  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
413  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
414  {
415  rdump.prepend( '(' ).append( ')' );
416  }
417 
418  QString fmt;
419  if ( leftAssociative() )
420  {
421  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
422  fmt += QLatin1String( " %2 " );
423  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
424  }
425  else
426  {
427  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
428  fmt += QLatin1String( " %2 " );
429  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
430  }
431 
432  return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
433 }
434 
436 {
437  return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
438 }
439 
440 //
441 
443 {
444  return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
445 }
446 
448 {
449  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
450 }
451 
452 //
453 
455 {
456  return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
457 }
458 
460 {
461  return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
462 }
463 
464 //
465 
467 {
468  return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
469 }
470 
472 {
473  return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
474 }
475 
476 //
477 
479 {
480  if ( mValue.isNull() )
481  return QStringLiteral( "NULL" );
482 
483  switch ( mValue.type() )
484  {
485  case QVariant::Int:
486  return QString::number( mValue.toInt() );
487  case QVariant::LongLong:
488  return QString::number( mValue.toLongLong() );
489  case QVariant::Double:
490  return QString::number( mValue.toDouble() );
491  case QVariant::String:
492  return quotedString( mValue.toString() );
493  case QVariant::Bool:
494  return mValue.toBool() ? "TRUE" : "FALSE";
495  default:
496  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
497  }
498 }
499 
501 {
502  return new NodeLiteral( mValue );
503 }
504 
505 //
506 
508 {
509  QString ret;
510  if ( mDistinct )
511  ret += QLatin1String( "DISTINCT " );
512  if ( !mTableName.isEmpty() )
513  {
514  ret += quotedIdentifierIfNeeded( mTableName );
515  ret += '.';
516  }
517  ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
518  return ret;
519 }
520 
522 {
523  return cloneThis();
524 }
525 
527 {
528  NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
529  newColumnRef->setDistinct( mDistinct );
530  return newColumnRef;
531 }
532 
533 //
534 
536 {
537  QString ret;
538  ret += mColumnNode->dump();
539  if ( !mAlias.isEmpty() )
540  {
541  ret += QLatin1String( " AS " );
542  ret += quotedIdentifierIfNeeded( mAlias );
543  }
544  return ret;
545 }
546 
548 {
549  NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
550  newObj->setAlias( mAlias );
551  return newObj;
552 }
553 
555 {
556  return cloneThis();
557 }
558 //
559 
561 {
562  QString ret;
563  ret = quotedIdentifierIfNeeded( mName );
564  if ( !mAlias.isEmpty() )
565  {
566  ret += QLatin1String( " AS " );
567  ret += quotedIdentifierIfNeeded( mAlias );
568  }
569  return ret;
570 }
571 
573 {
574  return new NodeTableDef( mName, mAlias );
575 }
576 
578 {
579  return cloneThis();
580 }
581 
582 //
583 
585 {
586  qDeleteAll( mTableList );
587  qDeleteAll( mColumns );
588  qDeleteAll( mJoins );
589  delete mWhere;
590  qDeleteAll( mOrderBy );
591 }
592 
594 {
595  QString ret = QStringLiteral( "SELECT " );
596  if ( mDistinct )
597  ret += QLatin1String( "DISTINCT " );
598  bool bFirstColumn = true;
599  const auto constMColumns = mColumns;
600  for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
601  {
602  if ( !bFirstColumn )
603  ret += QLatin1String( ", " );
604  bFirstColumn = false;
605  ret += column->dump();
606  }
607  ret += QLatin1String( " FROM " );
608  bool bFirstTable = true;
609  const auto constMTableList = mTableList;
610  for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
611  {
612  if ( !bFirstTable )
613  ret += QLatin1String( ", " );
614  bFirstTable = false;
615  ret += table->dump();
616  }
617  const auto constMJoins = mJoins;
618  for ( QgsSQLStatement::NodeJoin *join : constMJoins )
619  {
620  ret += ' ';
621  ret += join->dump();
622  }
623  if ( mWhere )
624  {
625  ret += QLatin1String( " WHERE " );
626  ret += mWhere->dump();
627  }
628  if ( !mOrderBy.isEmpty() )
629  {
630  ret += QLatin1String( " ORDER BY " );
631  bool bFirst = true;
632  const auto constMOrderBy = mOrderBy;
633  for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
634  {
635  if ( !bFirst )
636  ret += QLatin1String( ", " );
637  bFirst = false;
638  ret += orderBy->dump();
639  }
640  }
641  return ret;
642 }
643 
645 {
646  QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
647  const auto constMColumns = mColumns;
648  for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
649  {
650  newColumnList.push_back( column->cloneThis() );
651  }
652  QList<QgsSQLStatement::NodeTableDef *> newTableList;
653  const auto constMTableList = mTableList;
654  for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
655  {
656  newTableList.push_back( table->cloneThis() );
657  }
658  QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
659  const auto constMJoins = mJoins;
660  for ( QgsSQLStatement::NodeJoin *join : constMJoins )
661  {
662  newSelect->appendJoin( join->cloneThis() );
663  }
664  if ( mWhere )
665  {
666  newSelect->setWhere( mWhere->clone() );
667  }
668  QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
669  const auto constMOrderBy = mOrderBy;
670  for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
671  {
672  newOrderByList.push_back( columnSorted->cloneThis() );
673  }
674  newSelect->setOrderBy( newOrderByList );
675  return newSelect;
676 }
677 
678 //
679 
681 {
682  QString ret;
683  if ( mType != jtDefault )
684  {
685  ret += JOIN_TYPE_TEXT[mType];
686  ret += QLatin1Char( ' ' );
687  }
688  ret += QLatin1String( "JOIN " );
689  ret += mTableDef->dump();
690  if ( mOnExpr )
691  {
692  ret += QLatin1String( " ON " );
693  ret += mOnExpr->dump();
694  }
695  else
696  {
697  ret += QLatin1String( " USING (" );
698  bool first = true;
699  const auto constMUsingColumns = mUsingColumns;
700  for ( QString column : constMUsingColumns )
701  {
702  if ( !first )
703  ret += QLatin1String( ", " );
704  first = false;
705  ret += quotedIdentifierIfNeeded( column );
706  }
707  ret += QLatin1Char( ')' );
708  }
709  return ret;
710 }
711 
713 {
714  return cloneThis();
715 }
716 
718 {
719  if ( mOnExpr )
720  return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
721  else
722  return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
723 }
724 
725 //
726 
728 {
729  QString ret;
730  ret = mColumn->dump();
731  if ( !mAsc )
732  ret += QLatin1String( " DESC" );
733  return ret;
734 }
735 
737 {
738  return cloneThis();
739 }
740 
742 {
743  return new NodeColumnSorted( mColumn->cloneThis(), mAsc );
744 }
745 
746 //
747 
749 {
750  QString ret( QStringLiteral( "CAST(" ) );
751  ret += mNode->dump();
752  ret += QLatin1String( " AS " );
753  ret += mType;
754  ret += ')';
755  return ret;
756 }
757 
759 {
760  return new NodeCast( mNode->clone(), mType );
761 }
762 
763 //
764 // QgsSQLStatementFragment
765 //
766 
768  : QgsSQLStatement( fragment, true )
769 {
770 
771 }
QgsSQLStatementCollectTableNames()=default
Constructor for QgsSQLStatementCollectTableNames.
QSet< TableColumnPair > tableNamesReferenced
QPair< QString, QString > TableColumnPair
void visit(const QgsSQLStatement::NodeColumnRef &n) override
Visit NodeColumnRef.
QgsSQLStatementFragment(const QString &fragment)
Constructor for QgsSQLStatementFragment of the specified fragment.
'X BETWEEN y and z' operator
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString dump() const override
Abstract virtual dump method.
Binary logical/arithmetical operator (AND, OR, =, +, ...)
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString dump() const override
Abstract virtual dump method.
bool leftAssociative() const
Is left associative ?
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
Reference to a column.
QString name() const
The name of the column.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString tableName() const
The name of the table. May be empty.
QString dump() const override
Abstract virtual dump method.
void setDistinct(bool distinct=true)
Sets whether this is prefixed by DISTINCT.
QgsSQLStatement::NodeColumnRef * cloneThis() const
Clone with same type return.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::NodeColumnSorted * cloneThis() const
Clone with same type return.
QString dump() const override
Abstract virtual dump method.
Function with a name and arguments node.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::NodeJoin * cloneThis() const
Clone with same type return.
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
QgsSQLStatement::NodeList * clone() const
Creates a deep copy of this list. Ownership is transferred to the caller.
void accept(QgsSQLStatement::Visitor &v) const
Accept visitor.
virtual QString dump() const
Dump list.
Literal value (integer, integer64, double, string)
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QgsSQLStatement::Node * where() const
Returns the where clause.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void setWhere(QgsSQLStatement::Node *where)
Sets where clause.
void appendJoin(QgsSQLStatement::NodeJoin *join)
Append a join.
void setOrderBy(const QList< QgsSQLStatement::NodeColumnSorted * > &orderBy)
Sets order by columns.
QList< QgsSQLStatement::NodeSelectedColumn * > columns() const
Returns the list of columns.
QList< QgsSQLStatement::NodeColumnSorted * > orderBy() const
Returns the list of order by columns.
QString dump() const override
Abstract virtual dump method.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
void setAlias(const QString &alias)
Sets alias name.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::NodeSelectedColumn * cloneThis() const
Clone with same type return.
QString name() const
Table name.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void accept(QgsSQLStatement::Visitor &v) const override
Support the visitor pattern.
QString alias() const
Table alias.
QgsSQLStatement::NodeTableDef * cloneThis() const
Clone with same type return.
Unary logicial/arithmetical operator ( NOT, - )
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::UnaryOperator op() const
Operator.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
Abstract node class.
virtual QString dump() const =0
Abstract virtual dump method.
virtual void accept(QgsSQLStatement::Visitor &v) const =0
Support the visitor pattern.
A visitor that recursively explores all children.
void visit(const QgsSQLStatement::NodeUnaryOperator &n) override
Visit NodeUnaryOperator.
Support for visitor pattern - algorithms dealing with the statement may be implemented without modify...
Class for parsing SQL statements.
bool doBasicValidationChecks(QString &errorMsgOut) const
Performs basic validity checks.
QgsSQLStatement::Node * mRootNode
static QString stripQuotedIdentifier(QString text)
Remove double quotes from an identifier.
static QString quotedIdentifierIfNeeded(const QString &name)
Returns a quoted column reference (in double quotes) if needed, or otherwise the original string.
QString mParserErrorString
static QString quotedIdentifier(QString name)
Returns a quoted column reference (in double quotes)
QString parserErrorString() const
Returns parser error.
static const char * JOIN_TYPE_TEXT[]
QgsSQLStatement & operator=(const QgsSQLStatement &other)
Create a copy of this statement.
static QString stripMsQuotedIdentifier(QString text)
Remove double quotes from an Microsoft style identifier.
static const char * BINARY_OPERATOR_TEXT[]
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
QString dump() const
Returns the statement string, constructed from the internal abstract syntax tree.
virtual ~QgsSQLStatement()
void acceptVisitor(QgsSQLStatement::Visitor &v) const
Entry function for the visitor pattern.
bool hasParserError() const
Returns true if an error occurred when parsing the input statement.
const QgsSQLStatement::Node * rootNode() const
Returns the root node of the statement.
QString statement() const
Returns the original, unmodified statement string.
QgsSQLStatement(const QString &statement)
Creates a new statement based on the provided string.
static const char * UNARY_OPERATOR_TEXT[]
#define str(x)
Definition: qgis.cpp:37
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)