QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 <QRegularExpression>
21 
22 #include <cmath>
23 #include <limits>
24 
25 
26 // from parser
27 extern QgsSQLStatement::Node *parse( const QString &str, QString &parserErrorMsg, bool allowFragments );
28 
30 // operators
31 
33 {
34  // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
35  "OR", "AND",
36  "=", "<>", "<=", ">=", "<", ">", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
37  "+", "-", "*", "/", "//", "%", "^",
38  "||"
39 };
40 
42 {
43  // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
44  "NOT", "-"
45 };
46 
47 const char *QgsSQLStatement::JOIN_TYPE_TEXT[] =
48 {
49  // this must correspond (number and order of element) to the declaration of the enum JoinType
50  "", "LEFT", "LEFT OUTER", "RIGHT", "RIGHT OUTER", "CROSS", "INNER", "FULL"
51 };
52 
54 
56 {
57  if ( !mStatement.isNull() )
58  return mStatement;
59  else
60  return dump();
61 }
62 
63 QString QgsSQLStatement::dump() const
64 {
65  if ( !mRootNode )
66  return tr( "(no root)" );
67 
68  return mRootNode->dump();
69 }
70 
71 QString QgsSQLStatement::quotedIdentifier( QString name )
72 {
73  return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
74 }
75 
76 QString QgsSQLStatement::quotedIdentifierIfNeeded( const QString &name )
77 {
78  // This might not be complete, but it must be at least what we recognize
79  static const char *const RESERVED_KEYWORDS[] =
80  {
81  "AND", "OR", "NOT", "LIKE", "IN", "IS", "BETWEEN", "NULL", "SELECT", "ALL", "DISTINCT", "CAST", "AS",
82  "FROM", "JOIN", "ON", "USING", "WHERE", "ORDER", "BY", "ASC", "DESC",
83  "LEFT", "RIGHT", "INNER", "OUTER", "CROSS", "FULL", "NATURAL", "UNION",
84  "OFFSET", "LIMIT", "GROUP", "HAVING"
85  };
86 
87  for ( size_t i = 0; i < sizeof( RESERVED_KEYWORDS ) / sizeof( RESERVED_KEYWORDS[0] ); ++i )
88  {
89  if ( name.compare( QString( RESERVED_KEYWORDS[i] ), Qt::CaseInsensitive ) == 0 )
90  {
91  return quotedIdentifier( name );
92  }
93  }
94  const thread_local QRegularExpression IDENTIFIER_RE( "^[A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*$" );
95  return IDENTIFIER_RE.match( name ).hasMatch() ? name : quotedIdentifier( name );
96 }
97 
99 {
100  if ( text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' )
101  {
102  // strip double quotes on start,end
103  text = text.mid( 1, text.length() - 2 );
104 
105  // make single "double quotes" from double "double quotes"
106  text.replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
107  }
108  return text;
109 }
110 
112 {
113  if ( text.length() >= 2 && text[0] == '[' && text[text.length() - 1] == ']' )
114  {
115  // strip square brackets on start,end
116  text = text.mid( 1, text.length() - 2 );
117  }
118  return text;
119 }
120 
121 QString QgsSQLStatement::quotedString( QString text )
122 {
123  text.replace( '\'', QLatin1String( "''" ) );
124  text.replace( '\\', QLatin1String( "\\\\" ) );
125  text.replace( '\n', QLatin1String( "\\n" ) );
126  text.replace( '\t', QLatin1String( "\\t" ) );
127  return QStringLiteral( "'%1'" ).arg( text );
128 }
129 
130 QgsSQLStatement::QgsSQLStatement( const QString &expr )
131  : QgsSQLStatement( expr, false )
132 {
133 }
134 
135 QgsSQLStatement::QgsSQLStatement( const QString &expr, bool allowFragments )
136  : mAllowFragments( allowFragments )
137 {
139  mStatement = expr;
140 }
141 
143 {
145  mStatement = other.mStatement;
146 }
147 
149 {
150  if ( &other != this )
151  {
152  delete mRootNode;
153  mParserErrorString.clear();
155  mStatement = other.mStatement;
156  }
157  return *this;
158 }
159 
161 {
162  delete mRootNode;
163 }
164 
165 bool QgsSQLStatement::hasParserError() const { return !mParserErrorString.isNull() || ( !mRootNode && !mAllowFragments ); }
166 
168 
170 {
171  if ( mRootNode )
172  mRootNode->accept( v );
173 }
174 
176 {
177  return mRootNode;
178 }
179 
181 {
182  const auto constTables = n.tables();
183  for ( QgsSQLStatement::NodeTableDef *table : constTables )
184  {
185  table->accept( *this );
186  }
187  const auto constColumns = n.columns();
188  for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
189  {
190  column->accept( *this );
191  }
192  const auto constJoins = n.joins();
193  for ( QgsSQLStatement::NodeJoin *join : constJoins )
194  {
195  join->accept( *this );
196  }
197  QgsSQLStatement::Node *where = n.where();
198  if ( where )
199  where->accept( *this );
200  const auto constOrderBy = n.orderBy();
201  for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
202  {
203  column->accept( *this );
204  }
205 }
206 
208 {
209  n.tableDef()->accept( *this );
210  QgsSQLStatement::Node *expr = n.onExpr();
211  if ( expr )
212  expr->accept( *this );
213 }
214 
221 {
222  public:
223  typedef QPair<QString, QString> TableColumnPair;
224 
229 
230  void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
231  void visit( const QgsSQLStatement::NodeTableDef &n ) override;
232 
233  QSet<QString> tableNamesDeclared;
234  QSet<TableColumnPair> tableNamesReferenced;
235 };
236 
238 {
239  if ( !n.tableName().isEmpty() )
240  tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
242 }
243 
245 {
246  tableNamesDeclared.insert( n.alias().isEmpty() ? n.name() : n.alias() );
248 }
249 
250 bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
251 {
252  errorMsgOut.clear();
253  if ( !mRootNode )
254  {
255  errorMsgOut = tr( "No root node" );
256  return false;
257  }
259  mRootNode->accept( v );
260 
261  for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
262  {
263  if ( !v.tableNamesDeclared.contains( pair.first ) )
264  {
265  if ( !errorMsgOut.isEmpty() )
266  errorMsgOut += QLatin1Char( ' ' );
267  errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
268  }
269  }
270 
271  return errorMsgOut.isEmpty();
272 }
273 
275 // nodes
276 
278 {
279  for ( QgsSQLStatement::Node *node : mList )
280  {
281  node->accept( v );
282  }
283 }
284 
286 {
287  NodeList *nl = new NodeList;
288  const auto constMList = mList;
289  for ( Node *node : constMList )
290  {
291  nl->mList.append( node->clone() );
292  }
293 
294  return nl;
295 }
296 
298 {
299  QString msg;
300  bool first = true;
301  const auto constMList = mList;
302  for ( Node *n : constMList )
303  {
304  if ( !first ) msg += QLatin1String( ", " );
305  else first = false;
306  msg += n->dump();
307  }
308  return msg;
309 }
310 
311 
312 //
313 
315 {
316  return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
317 }
318 
320 {
321  return new NodeUnaryOperator( mOp, mOperand->clone() );
322 }
323 
324 //
325 
327 {
328  // see left/right in qgsexpressionparser.yy
329  switch ( mOp )
330  {
331  case boOr:
332  return 1;
333 
334  case boAnd:
335  return 2;
336 
337  case boEQ:
338  case boNE:
339  case boLE:
340  case boGE:
341  case boLT:
342  case boGT:
343  case boLike:
344  case boILike:
345  case boNotLike:
346  case boNotILike:
347  case boIs:
348  case boIsNot:
349  return 3;
350 
351  case boPlus:
352  case boMinus:
353  return 4;
354 
355  case boMul:
356  case boDiv:
357  case boIntDiv:
358  case boMod:
359  return 5;
360 
361  case boPow:
362  return 6;
363 
364  case boConcat:
365  return 7;
366  }
367  Q_ASSERT( false && "unexpected binary operator" );
368  return -1;
369 }
370 
372 {
373  // see left/right in qgsexpressionparser.yy
374  switch ( mOp )
375  {
376  case boOr:
377  case boAnd:
378  case boEQ:
379  case boNE:
380  case boLE:
381  case boGE:
382  case boLT:
383  case boGT:
384  case boLike:
385  case boILike:
386  case boNotLike:
387  case boNotILike:
388  case boIs:
389  case boIsNot:
390  case boPlus:
391  case boMinus:
392  case boMul:
393  case boDiv:
394  case boIntDiv:
395  case boMod:
396  case boConcat:
397  return true;
398 
399  case boPow:
400  return false;
401  }
402  Q_ASSERT( false && "unexpected binary operator" );
403  return false;
404 }
405 
407 {
411 
412  QString rdump( mOpRight->dump() );
413 
414  // avoid dumping "IS (NOT ...)" as "IS NOT ..."
415  if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
416  {
417  rdump.prepend( '(' ).append( ')' );
418  }
419 
420  QString fmt;
421  if ( leftAssociative() )
422  {
423  fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
424  fmt += QLatin1String( " %2 " );
425  fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
426  }
427  else
428  {
429  fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
430  fmt += QLatin1String( " %2 " );
431  fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
432  }
433 
434  return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
435 }
436 
438 {
439  return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
440 }
441 
442 //
443 
445 {
446  return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
447 }
448 
450 {
451  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
452 }
453 
454 //
455 
457 {
458  return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
459 }
460 
462 {
463  return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
464 }
465 
466 //
467 
469 {
470  return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
471 }
472 
474 {
475  return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
476 }
477 
478 //
479 
481 {
482  if ( mValue.isNull() )
483  return QStringLiteral( "NULL" );
484 
485  switch ( mValue.type() )
486  {
487  case QVariant::Int:
488  return QString::number( mValue.toInt() );
489  case QVariant::LongLong:
490  return QString::number( mValue.toLongLong() );
491  case QVariant::Double:
492  return QString::number( mValue.toDouble() );
493  case QVariant::String:
494  return quotedString( mValue.toString() );
495  case QVariant::Bool:
496  return mValue.toBool() ? "TRUE" : "FALSE";
497  default:
498  return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
499  }
500 }
501 
503 {
504  return new NodeLiteral( mValue );
505 }
506 
507 //
508 
510 {
511  QString ret;
512  if ( mDistinct )
513  ret += QLatin1String( "DISTINCT " );
514  if ( !mTableName.isEmpty() )
515  {
516  ret += quotedIdentifierIfNeeded( mTableName );
517  ret += '.';
518  }
519  ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
520  return ret;
521 }
522 
524 {
525  return cloneThis();
526 }
527 
529 {
530  NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
531  newColumnRef->setDistinct( mDistinct );
532  return newColumnRef;
533 }
534 
535 //
536 
538 {
539  QString ret;
540  ret += mColumnNode->dump();
541  if ( !mAlias.isEmpty() )
542  {
543  ret += QLatin1String( " AS " );
544  ret += quotedIdentifierIfNeeded( mAlias );
545  }
546  return ret;
547 }
548 
550 {
551  NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
552  newObj->setAlias( mAlias );
553  return newObj;
554 }
555 
557 {
558  return cloneThis();
559 }
560 //
561 
563 {
564  QString ret;
565  ret = quotedIdentifierIfNeeded( mName );
566  if ( !mAlias.isEmpty() )
567  {
568  ret += QLatin1String( " AS " );
569  ret += quotedIdentifierIfNeeded( mAlias );
570  }
571  return ret;
572 }
573 
575 {
576  return new NodeTableDef( mName, mAlias );
577 }
578 
580 {
581  return cloneThis();
582 }
583 
584 //
585 
587 {
588  qDeleteAll( mTableList );
589  qDeleteAll( mColumns );
590  qDeleteAll( mJoins );
591  delete mWhere;
592  qDeleteAll( mOrderBy );
593 }
594 
596 {
597  QString ret = QStringLiteral( "SELECT " );
598  if ( mDistinct )
599  ret += QLatin1String( "DISTINCT " );
600  bool bFirstColumn = true;
601  const auto constMColumns = mColumns;
602  for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
603  {
604  if ( !bFirstColumn )
605  ret += QLatin1String( ", " );
606  bFirstColumn = false;
607  ret += column->dump();
608  }
609  ret += QLatin1String( " FROM " );
610  bool bFirstTable = true;
611  const auto constMTableList = mTableList;
612  for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
613  {
614  if ( !bFirstTable )
615  ret += QLatin1String( ", " );
616  bFirstTable = false;
617  ret += table->dump();
618  }
619  const auto constMJoins = mJoins;
620  for ( QgsSQLStatement::NodeJoin *join : constMJoins )
621  {
622  ret += ' ';
623  ret += join->dump();
624  }
625  if ( mWhere )
626  {
627  ret += QLatin1String( " WHERE " );
628  ret += mWhere->dump();
629  }
630  if ( !mOrderBy.isEmpty() )
631  {
632  ret += QLatin1String( " ORDER BY " );
633  bool bFirst = true;
634  const auto constMOrderBy = mOrderBy;
635  for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
636  {
637  if ( !bFirst )
638  ret += QLatin1String( ", " );
639  bFirst = false;
640  ret += orderBy->dump();
641  }
642  }
643  return ret;
644 }
645 
647 {
648  QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
649  const auto constMColumns = mColumns;
650  for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
651  {
652  newColumnList.push_back( column->cloneThis() );
653  }
654  QList<QgsSQLStatement::NodeTableDef *> newTableList;
655  const auto constMTableList = mTableList;
656  for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
657  {
658  newTableList.push_back( table->cloneThis() );
659  }
660  QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
661  const auto constMJoins = mJoins;
662  for ( QgsSQLStatement::NodeJoin *join : constMJoins )
663  {
664  newSelect->appendJoin( join->cloneThis() );
665  }
666  if ( mWhere )
667  {
668  newSelect->setWhere( mWhere->clone() );
669  }
670  QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
671  const auto constMOrderBy = mOrderBy;
672  for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
673  {
674  newOrderByList.push_back( columnSorted->cloneThis() );
675  }
676  newSelect->setOrderBy( newOrderByList );
677  return newSelect;
678 }
679 
680 //
681 
683 {
684  QString ret;
685  if ( mType != jtDefault )
686  {
687  ret += JOIN_TYPE_TEXT[mType];
688  ret += QLatin1Char( ' ' );
689  }
690  ret += QLatin1String( "JOIN " );
691  ret += mTableDef->dump();
692  if ( mOnExpr )
693  {
694  ret += QLatin1String( " ON " );
695  ret += mOnExpr->dump();
696  }
697  else
698  {
699  ret += QLatin1String( " USING (" );
700  bool first = true;
701  const auto constMUsingColumns = mUsingColumns;
702  for ( QString column : constMUsingColumns )
703  {
704  if ( !first )
705  ret += QLatin1String( ", " );
706  first = false;
707  ret += quotedIdentifierIfNeeded( column );
708  }
709  ret += QLatin1Char( ')' );
710  }
711  return ret;
712 }
713 
715 {
716  return cloneThis();
717 }
718 
720 {
721  if ( mOnExpr )
722  return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
723  else
724  return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
725 }
726 
727 //
728 
730 {
731  QString ret;
732  ret = mColumn->dump();
733  if ( !mAsc )
734  ret += QLatin1String( " DESC" );
735  return ret;
736 }
737 
739 {
740  return cloneThis();
741 }
742 
744 {
745  return new NodeColumnSorted( mColumn->cloneThis(), mAsc );
746 }
747 
748 //
749 
751 {
752  QString ret( QStringLiteral( "CAST(" ) );
753  ret += mNode->dump();
754  ret += QLatin1String( " AS " );
755  ret += mType;
756  ret += ')';
757  return ret;
758 }
759 
761 {
762  return new NodeCast( mNode->clone(), mType );
763 }
764 
765 //
766 // QgsSQLStatementFragment
767 //
768 
770  : QgsSQLStatement( fragment, true )
771 {
772 
773 }
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)