QGIS API Documentation 3.99.0-Master (752b475928d)
Loading...
Searching...
No Matches
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#include "qgis.h"
23#include "qgsvariantutils.h"
24
25#include <QRegularExpression>
26
27// from parser
28extern QgsSQLStatement::Node *parse( const QString &str, QString &parserErrorMsg, bool allowFragments );
29
31// operators
32
34{
35 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
36 "OR", "AND",
37 "=", "<>", "<=", ">=", "<", ">", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT",
38 "+", "-", "*", "/", "//", "%", "^",
39 "||"
40};
41
43{
44 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
45 "NOT", "-"
46};
47
49{
50 // this must correspond (number and order of element) to the declaration of the enum JoinType
51 "", "LEFT", "LEFT OUTER", "RIGHT", "RIGHT OUTER", "CROSS", "INNER", "FULL"
52};
53
55
57{
58 if ( !mStatement.isNull() )
59 return mStatement;
60 else
61 return dump();
62}
63
64QString QgsSQLStatement::dump() const
65{
66 if ( !mRootNode )
67 return tr( "(no root)" );
68
69 return mRootNode->dump();
70}
71
72QString QgsSQLStatement::quotedIdentifier( QString name )
73{
74 return QStringLiteral( "\"%1\"" ).arg( name.replace( '\"', QLatin1String( "\"\"" ) ) );
75}
76
77QString QgsSQLStatement::quotedIdentifierIfNeeded( const QString &name )
78{
79 // This might not be complete, but it must be at least what we recognize
80 static const char *const RESERVED_KEYWORDS[] =
81 {
82 "AND", "OR", "NOT", "LIKE", "IN", "IS", "BETWEEN", "NULL", "SELECT", "ALL", "DISTINCT", "CAST", "AS",
83 "FROM", "JOIN", "ON", "USING", "WHERE", "ORDER", "BY", "ASC", "DESC",
84 "LEFT", "RIGHT", "INNER", "OUTER", "CROSS", "FULL", "NATURAL", "UNION",
85 "OFFSET", "LIMIT", "GROUP", "HAVING"
86 };
87
88 for ( size_t i = 0; i < sizeof( RESERVED_KEYWORDS ) / sizeof( RESERVED_KEYWORDS[0] ); ++i )
89 {
90 if ( name.compare( QString( RESERVED_KEYWORDS[i] ), Qt::CaseInsensitive ) == 0 )
91 {
92 return quotedIdentifier( name );
93 }
94 }
95 const thread_local QRegularExpression IDENTIFIER_RE( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" );
96 return IDENTIFIER_RE.match( name ).hasMatch() ? name : quotedIdentifier( name );
97}
98
100{
101 if ( text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' )
102 {
103 // strip double quotes on start,end
104 text = text.mid( 1, text.length() - 2 );
105
106 // make single "double quotes" from double "double quotes"
107 text.replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
108 }
109 return text;
110}
111
113{
114 if ( text.length() >= 2 && text[0] == '[' && text[text.length() - 1] == ']' )
115 {
116 // strip square brackets on start,end
117 text = text.mid( 1, text.length() - 2 );
118 }
119 return text;
120}
121
122QString QgsSQLStatement::quotedString( QString text )
123{
124 text.replace( '\'', QLatin1String( "''" ) );
125 text.replace( '\\', QLatin1String( "\\\\" ) );
126 text.replace( '\n', QLatin1String( "\\n" ) );
127 text.replace( '\t', QLatin1String( "\\t" ) );
128 return QStringLiteral( "'%1'" ).arg( text );
129}
130
132 : QgsSQLStatement( expr, false )
133{
134}
135
136QgsSQLStatement::QgsSQLStatement( const QString &expr, bool allowFragments )
137 : mAllowFragments( allowFragments )
138{
140 mStatement = expr;
141}
142
149
151{
152 if ( &other != this )
153 {
154 mParserErrorString.clear();
155 mStatement = other.mStatement;
158 }
159 return *this;
160}
161
166
168
170
172{
173 if ( mRootNode )
174 mRootNode->accept( v );
175}
176
178{
179 return mRootNode.get();
180}
181
183{
184 const auto constTables = n.tables();
185 for ( QgsSQLStatement::NodeTableDef *table : constTables )
186 {
187 table->accept( *this );
188 }
189 const auto constColumns = n.columns();
190 for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
191 {
192 column->accept( *this );
193 }
194 const auto constJoins = n.joins();
195 for ( QgsSQLStatement::NodeJoin *join : constJoins )
196 {
197 join->accept( *this );
198 }
199 QgsSQLStatement::Node *where = n.where();
200 if ( where )
201 where->accept( *this );
202 const auto constOrderBy = n.orderBy();
203 for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
204 {
205 column->accept( *this );
206 }
207}
208
210{
211 n.tableDef()->accept( *this );
212 QgsSQLStatement::Node *expr = n.onExpr();
213 if ( expr )
214 expr->accept( *this );
215}
216
223{
224 public:
225 typedef QPair<QString, QString> TableColumnPair;
226
231
233 void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
234 void visit( const QgsSQLStatement::NodeTableDef &n ) override;
235
236 QSet<QString> tableNamesDeclared;
237 QSet<TableColumnPair> tableNamesReferenced;
238};
239
246
248{
249 tableNamesDeclared.insert( n.alias().isEmpty() ? ( n.schema().isEmpty() ? n.name() : n.schema() + '.' + n.name() ) : n.alias() );
251}
252
253bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
254{
255 errorMsgOut.clear();
256 if ( !mRootNode )
257 {
258 errorMsgOut = tr( "No root node" );
259 return false;
260 }
262 mRootNode->accept( v );
263
264 for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
265 {
266 if ( !v.tableNamesDeclared.contains( pair.first ) )
267 {
268 if ( !errorMsgOut.isEmpty() )
269 errorMsgOut += QLatin1Char( ' ' );
270 errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
271 }
272 }
273
274 return errorMsgOut.isEmpty();
275}
276
278// nodes
279
281{
282 for ( QgsSQLStatement::Node *node : mList )
283 {
284 node->accept( v );
285 }
286}
287
289{
290 NodeList *nl = new NodeList;
291 const auto constMList = mList;
292 for ( Node *node : constMList )
293 {
294 nl->mList.append( node->clone() );
295 }
296
297 return nl;
298}
299
301{
302 QString msg;
303 bool first = true;
304 const auto constMList = mList;
305 for ( Node *n : constMList )
306 {
307 if ( !first ) msg += QLatin1String( ", " );
308 else first = false;
309 msg += n->dump();
310 }
311 return msg;
312}
313
314
315//
316
318{
319 return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
320}
321
326
327//
328
330{
331 // see left/right in qgsexpressionparser.yy
332 switch ( mOp )
333 {
334 case boOr:
335 return 1;
336
337 case boAnd:
338 return 2;
339
340 case boEQ:
341 case boNE:
342 case boLE:
343 case boGE:
344 case boLT:
345 case boGT:
346 case boLike:
347 case boILike:
348 case boNotLike:
349 case boNotILike:
350 case boIs:
351 case boIsNot:
352 return 3;
353
354 case boPlus:
355 case boMinus:
356 return 4;
357
358 case boMul:
359 case boDiv:
360 case boIntDiv:
361 case boMod:
362 return 5;
363
364 case boPow:
365 return 6;
366
367 case boConcat:
368 return 7;
369 }
370 Q_ASSERT( false && "unexpected binary operator" );
371 return -1;
372}
373
375{
376 // see left/right in qgsexpressionparser.yy
377 switch ( mOp )
378 {
379 case boOr:
380 case boAnd:
381 case boEQ:
382 case boNE:
383 case boLE:
384 case boGE:
385 case boLT:
386 case boGT:
387 case boLike:
388 case boILike:
389 case boNotLike:
390 case boNotILike:
391 case boIs:
392 case boIsNot:
393 case boPlus:
394 case boMinus:
395 case boMul:
396 case boDiv:
397 case boIntDiv:
398 case boMod:
399 case boConcat:
400 return true;
401
402 case boPow:
403 return false;
404 }
405 Q_ASSERT( false && "unexpected binary operator" );
406 return false;
407}
408
410{
414
415 QString rdump( mOpRight->dump() );
416
417 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
418 if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
419 {
420 rdump.prepend( '(' ).append( ')' );
421 }
422
423 QString fmt;
424 if ( leftAssociative() )
425 {
426 fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
427 fmt += QLatin1String( " %2 " );
428 fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
429 }
430 else
431 {
432 fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
433 fmt += QLatin1String( " %2 " );
434 fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
435 }
436
437 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
438}
439
444
445//
446
448{
449 return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
450}
451
453{
454 return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
455}
456
457//
458
460{
461 return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
462}
463
468
469//
470
472{
473 return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
474}
475
477{
478 return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
479}
480
481//
482
484{
486 return QStringLiteral( "NULL" );
487
488 switch ( mValue.userType() )
489 {
490 case QMetaType::Type::Int:
491 return QString::number( mValue.toInt() );
492 case QMetaType::Type::LongLong:
493 return QString::number( mValue.toLongLong() );
494 case QMetaType::Type::Double:
495 return QString::number( mValue.toDouble() );
496 case QMetaType::Type::QString:
497 return quotedString( mValue.toString() );
498 case QMetaType::Type::Bool:
499 return mValue.toBool() ? "TRUE" : "FALSE";
500 default:
501 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
502 }
503}
504
509
510//
511
513{
514 QString ret;
515 if ( mDistinct )
516 ret += QLatin1String( "DISTINCT " );
517 if ( !mTableName.isEmpty() )
518 {
520 ret += '.';
521 }
522 ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
523 return ret;
524}
525
530
532{
533 NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
534 newColumnRef->setDistinct( mDistinct );
535 return newColumnRef;
536}
537
538//
539
541{
542 QString ret;
543 ret += mColumnNode->dump();
544 if ( !mAlias.isEmpty() )
545 {
546 ret += QLatin1String( " AS " );
548 }
549 return ret;
550}
551
558
563//
564
566{
567 QString ret;
568 if ( !mSchema.isEmpty() )
569 ret += mSchema + '.';
570
572 if ( !mAlias.isEmpty() )
573 {
574 ret += QLatin1String( " AS " );
576 }
577 return ret;
578}
579
584
589
590//
591
593{
594 qDeleteAll( mTableList );
595 qDeleteAll( mColumns );
596 qDeleteAll( mJoins );
597 qDeleteAll( mOrderBy );
598}
599
601{
602 QString ret = QStringLiteral( "SELECT " );
603 if ( mDistinct )
604 ret += QLatin1String( "DISTINCT " );
605 bool bFirstColumn = true;
606 const auto constMColumns = mColumns;
607 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
608 {
609 if ( !bFirstColumn )
610 ret += QLatin1String( ", " );
611 bFirstColumn = false;
612 ret += column->dump();
613 }
614 ret += QLatin1String( " FROM " );
615 bool bFirstTable = true;
616 const auto constMTableList = mTableList;
617 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
618 {
619 if ( !bFirstTable )
620 ret += QLatin1String( ", " );
621 bFirstTable = false;
622 ret += table->dump();
623 }
624 const auto constMJoins = mJoins;
625 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
626 {
627 ret += ' ';
628 ret += join->dump();
629 }
630 if ( mWhere )
631 {
632 ret += QLatin1String( " WHERE " );
633 ret += mWhere->dump();
634 }
635 if ( !mOrderBy.isEmpty() )
636 {
637 ret += QLatin1String( " ORDER BY " );
638 bool bFirst = true;
639 const auto constMOrderBy = mOrderBy;
640 for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
641 {
642 if ( !bFirst )
643 ret += QLatin1String( ", " );
644 bFirst = false;
645 ret += orderBy->dump();
646 }
647 }
648 return ret;
649}
650
652{
653 QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
654 const auto constMColumns = mColumns;
655 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
656 {
657 newColumnList.push_back( column->cloneThis() );
658 }
659 QList<QgsSQLStatement::NodeTableDef *> newTableList;
660 const auto constMTableList = mTableList;
661 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
662 {
663 newTableList.push_back( table->cloneThis() );
664 }
665 QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
666 const auto constMJoins = mJoins;
667 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
668 {
669 newSelect->appendJoin( join->cloneThis() );
670 }
671 if ( mWhere )
672 {
673 newSelect->setWhere( mWhere->clone() );
674 }
675 QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
676 const auto constMOrderBy = mOrderBy;
677 for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
678 {
679 newOrderByList.push_back( columnSorted->cloneThis() );
680 }
681 newSelect->setOrderBy( newOrderByList );
682 return newSelect;
683}
684
685//
686
688{
689 QString ret;
690 if ( mType != jtDefault )
691 {
692 ret += JOIN_TYPE_TEXT[mType];
693 ret += QLatin1Char( ' ' );
694 }
695 ret += QLatin1String( "JOIN " );
696 ret += mTableDef->dump();
697 if ( mOnExpr )
698 {
699 ret += QLatin1String( " ON " );
700 ret += mOnExpr->dump();
701 }
702 else
703 {
704 ret += QLatin1String( " USING (" );
705 bool first = true;
706 const auto constMUsingColumns = mUsingColumns;
707 for ( QString column : constMUsingColumns )
708 {
709 if ( !first )
710 ret += QLatin1String( ", " );
711 first = false;
712 ret += quotedIdentifierIfNeeded( column );
713 }
714 ret += QLatin1Char( ')' );
715 }
716 return ret;
717}
718
723
725{
726 if ( mOnExpr )
727 return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
728 else
729 return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
730}
731
732//
733
735{
736 QString ret;
737 ret = mColumn->dump();
738 if ( !mAsc )
739 ret += QLatin1String( " DESC" );
740 return ret;
741}
742
747
752
753//
754
756{
757 QString ret( QStringLiteral( "CAST(" ) );
758 ret += mNode->dump();
759 ret += QLatin1String( " AS " );
760 ret += mType;
761 ret += ')';
762 return ret;
763}
764
766{
767 return new NodeCast( mNode->clone(), mType );
768}
769
770//
771// QgsSQLStatementFragment
772//
773
775 : QgsSQLStatement( fragment, true )
776{
777
778}
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.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
NodeBetweenOperator(QgsSQLStatement::Node *node, QgsSQLStatement::Node *minVal, QgsSQLStatement::Node *maxVal, bool notBetween=false)
Constructor.
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.
NodeBinaryOperator(QgsSQLStatement::BinaryOperator op, QgsSQLStatement::Node *opLeft, QgsSQLStatement::Node *opRight)
Constructor.
bool leftAssociative() const
Is left associative ?
NodeCast(QgsSQLStatement::Node *node, const QString &type)
Constructor.
QString dump() const override
Abstract virtual dump method.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
std::unique_ptr< Node > mNode
QString name() const
The name of the column.
NodeColumnRef(const QString &name, bool star)
Constructor with column name only.
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.
std::unique_ptr< NodeColumnRef > mColumn
NodeColumnSorted(QgsSQLStatement::NodeColumnRef *column, bool asc)
Constructor.
NodeFunction(const QString &name, QgsSQLStatement::NodeList *args)
Constructor.
QString dump() const override
Abstract virtual dump method.
std::unique_ptr< NodeList > mArgs
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
std::unique_ptr< NodeList > mList
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
std::unique_ptr< Node > mNode
NodeInOperator(QgsSQLStatement::Node *node, QgsSQLStatement::NodeList *list, bool notin=false)
Constructor.
QString dump() const override
Abstract virtual dump method.
QList< QString > mUsingColumns
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
std::unique_ptr< Node > mOnExpr
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
NodeJoin(QgsSQLStatement::NodeTableDef *tabledef, QgsSQLStatement::Node *onExpr, QgsSQLStatement::JoinType type)
Constructor with table definition, ON expression.
std::unique_ptr< NodeTableDef > mTableDef
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::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.
QString dump() const override
Abstract virtual dump method.
NodeLiteral(const QVariant &value)
Constructor.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
NodeSelect(const QList< QgsSQLStatement::NodeTableDef * > &tableList, const QList< QgsSQLStatement::NodeSelectedColumn * > &columns, bool distinct)
Constructor.
QList< QgsSQLStatement::NodeColumnSorted * > orderBy() const
Returns the list of order by columns.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
void setWhere(QgsSQLStatement::Node *where)
Sets where clause.
QList< NodeColumnSorted * > mOrderBy
QList< QgsSQLStatement::NodeSelectedColumn * > columns() const
Returns the list of columns.
QList< NodeSelectedColumn * > mColumns
void appendJoin(QgsSQLStatement::NodeJoin *join)
Append a join.
void setOrderBy(const QList< QgsSQLStatement::NodeColumnSorted * > &orderBy)
Sets order by columns.
std::unique_ptr< Node > mWhere
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
QList< NodeTableDef * > mTableList
QgsSQLStatement::Node * where() const
Returns the where clause.
QString dump() const override
Abstract virtual dump method.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
NodeSelectedColumn(QgsSQLStatement::Node *node)
Constructor.
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.
std::unique_ptr< Node > mColumnNode
QString name() const
Table name.
QString dump() const override
Abstract virtual dump method.
NodeTableDef(const QString &name)
Constructor with table name.
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.
QString schema() const
Returns the schema name.
QgsSQLStatement::NodeTableDef * cloneThis() const
Clone with same type return.
Unary logical/arithmetical operator ( NOT, - ).
QString dump() const override
Abstract virtual dump method.
NodeUnaryOperator(QgsSQLStatement::UnaryOperator op, QgsSQLStatement::Node *operand)
Constructor.
QgsSQLStatement::UnaryOperator op() const
Operator.
QgsSQLStatement::Node * clone() const override
Generate a clone of this node.
Abstract node class for SQL statement nodes.
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...
bool doBasicValidationChecks(QString &errorMsgOut) const
Performs basic validity checks.
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.
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)
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.
void acceptVisitor(QgsSQLStatement::Visitor &v) const
Entry function for the visitor pattern.
std::unique_ptr< QgsSQLStatement::Node > mRootNode
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[]
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)