QGIS API Documentation 3.43.0-Master (56aa1fd18d7)
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#include "qgsvariantutils.h"
20
21#include <QRegularExpression>
22
23#include <cmath>
24#include <limits>
25
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
144 : mAllowFragments( other.mAllowFragments )
145 , mStatement( other.mStatement )
146{
148}
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
232 void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
233 void visit( const QgsSQLStatement::NodeTableDef &n ) override;
234
235 QSet<QString> tableNamesDeclared;
236 QSet<TableColumnPair> tableNamesReferenced;
237};
238
240{
241 if ( !n.tableName().isEmpty() )
242 tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
244}
245
247{
248 tableNamesDeclared.insert( n.alias().isEmpty() ? ( n.schema().isEmpty() ? n.name() : n.schema() + '.' + n.name() ) : n.alias() );
250}
251
252bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
253{
254 errorMsgOut.clear();
255 if ( !mRootNode )
256 {
257 errorMsgOut = tr( "No root node" );
258 return false;
259 }
261 mRootNode->accept( v );
262
263 for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
264 {
265 if ( !v.tableNamesDeclared.contains( pair.first ) )
266 {
267 if ( !errorMsgOut.isEmpty() )
268 errorMsgOut += QLatin1Char( ' ' );
269 errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
270 }
271 }
272
273 return errorMsgOut.isEmpty();
274}
275
277// nodes
278
280{
281 for ( QgsSQLStatement::Node *node : mList )
282 {
283 node->accept( v );
284 }
285}
286
288{
289 NodeList *nl = new NodeList;
290 const auto constMList = mList;
291 for ( Node *node : constMList )
292 {
293 nl->mList.append( node->clone() );
294 }
295
296 return nl;
297}
298
300{
301 QString msg;
302 bool first = true;
303 const auto constMList = mList;
304 for ( Node *n : constMList )
305 {
306 if ( !first ) msg += QLatin1String( ", " );
307 else first = false;
308 msg += n->dump();
309 }
310 return msg;
311}
312
313
314//
315
317{
318 return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
319}
320
322{
323 return new NodeUnaryOperator( mOp, mOperand->clone() );
324}
325
326//
327
329{
330 // see left/right in qgsexpressionparser.yy
331 switch ( mOp )
332 {
333 case boOr:
334 return 1;
335
336 case boAnd:
337 return 2;
338
339 case boEQ:
340 case boNE:
341 case boLE:
342 case boGE:
343 case boLT:
344 case boGT:
345 case boLike:
346 case boILike:
347 case boNotLike:
348 case boNotILike:
349 case boIs:
350 case boIsNot:
351 return 3;
352
353 case boPlus:
354 case boMinus:
355 return 4;
356
357 case boMul:
358 case boDiv:
359 case boIntDiv:
360 case boMod:
361 return 5;
362
363 case boPow:
364 return 6;
365
366 case boConcat:
367 return 7;
368 }
369 Q_ASSERT( false && "unexpected binary operator" );
370 return -1;
371}
372
374{
375 // see left/right in qgsexpressionparser.yy
376 switch ( mOp )
377 {
378 case boOr:
379 case boAnd:
380 case boEQ:
381 case boNE:
382 case boLE:
383 case boGE:
384 case boLT:
385 case boGT:
386 case boLike:
387 case boILike:
388 case boNotLike:
389 case boNotILike:
390 case boIs:
391 case boIsNot:
392 case boPlus:
393 case boMinus:
394 case boMul:
395 case boDiv:
396 case boIntDiv:
397 case boMod:
398 case boConcat:
399 return true;
400
401 case boPow:
402 return false;
403 }
404 Q_ASSERT( false && "unexpected binary operator" );
405 return false;
406}
407
409{
410 QgsSQLStatement::NodeBinaryOperator *lOp = dynamic_cast<QgsSQLStatement::NodeBinaryOperator *>( mOpLeft.get() );
411 QgsSQLStatement::NodeBinaryOperator *rOp = dynamic_cast<QgsSQLStatement::NodeBinaryOperator *>( mOpRight.get() );
412 QgsSQLStatement::NodeUnaryOperator *ruOp = dynamic_cast<QgsSQLStatement::NodeUnaryOperator *>( mOpRight.get() );
413
414 QString rdump( mOpRight->dump() );
415
416 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
417 if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
418 {
419 rdump.prepend( '(' ).append( ')' );
420 }
421
422 QString fmt;
423 if ( leftAssociative() )
424 {
425 fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
426 fmt += QLatin1String( " %2 " );
427 fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
428 }
429 else
430 {
431 fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
432 fmt += QLatin1String( " %2 " );
433 fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
434 }
435
436 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
437}
438
440{
441 return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
442}
443
444//
445
447{
448 return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
449}
450
452{
453 return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
454}
455
456//
457
459{
460 return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
461}
462
464{
465 return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
466}
467
468//
469
471{
472 return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
473}
474
476{
477 return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
478}
479
480//
481
483{
484 if ( QgsVariantUtils::isNull( mValue ) )
485 return QStringLiteral( "NULL" );
486
487 switch ( mValue.userType() )
488 {
489 case QMetaType::Type::Int:
490 return QString::number( mValue.toInt() );
491 case QMetaType::Type::LongLong:
492 return QString::number( mValue.toLongLong() );
493 case QMetaType::Type::Double:
494 return QString::number( mValue.toDouble() );
495 case QMetaType::Type::QString:
496 return quotedString( mValue.toString() );
497 case QMetaType::Type::Bool:
498 return mValue.toBool() ? "TRUE" : "FALSE";
499 default:
500 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
501 }
502}
503
505{
506 return new NodeLiteral( mValue );
507}
508
509//
510
512{
513 QString ret;
514 if ( mDistinct )
515 ret += QLatin1String( "DISTINCT " );
516 if ( !mTableName.isEmpty() )
517 {
518 ret += quotedIdentifierIfNeeded( mTableName );
519 ret += '.';
520 }
521 ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
522 return ret;
523}
524
526{
527 return cloneThis();
528}
529
531{
532 NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
533 newColumnRef->setDistinct( mDistinct );
534 return newColumnRef;
535}
536
537//
538
540{
541 QString ret;
542 ret += mColumnNode->dump();
543 if ( !mAlias.isEmpty() )
544 {
545 ret += QLatin1String( " AS " );
546 ret += quotedIdentifierIfNeeded( mAlias );
547 }
548 return ret;
549}
550
552{
553 NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
554 newObj->setAlias( mAlias );
555 return newObj;
556}
557
559{
560 return cloneThis();
561}
562//
563
565{
566 QString ret;
567 if ( !mSchema.isEmpty() )
568 ret += mSchema + '.';
569
570 ret += quotedIdentifierIfNeeded( mName );
571 if ( !mAlias.isEmpty() )
572 {
573 ret += QLatin1String( " AS " );
574 ret += quotedIdentifierIfNeeded( mAlias );
575 }
576 return ret;
577}
578
580{
581 return new NodeTableDef( mSchema, mName, mAlias );
582}
583
585{
586 return cloneThis();
587}
588
589//
590
592{
593 qDeleteAll( mTableList );
594 qDeleteAll( mColumns );
595 qDeleteAll( mJoins );
596 qDeleteAll( mOrderBy );
597}
598
600{
601 QString ret = QStringLiteral( "SELECT " );
602 if ( mDistinct )
603 ret += QLatin1String( "DISTINCT " );
604 bool bFirstColumn = true;
605 const auto constMColumns = mColumns;
606 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
607 {
608 if ( !bFirstColumn )
609 ret += QLatin1String( ", " );
610 bFirstColumn = false;
611 ret += column->dump();
612 }
613 ret += QLatin1String( " FROM " );
614 bool bFirstTable = true;
615 const auto constMTableList = mTableList;
616 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
617 {
618 if ( !bFirstTable )
619 ret += QLatin1String( ", " );
620 bFirstTable = false;
621 ret += table->dump();
622 }
623 const auto constMJoins = mJoins;
624 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
625 {
626 ret += ' ';
627 ret += join->dump();
628 }
629 if ( mWhere )
630 {
631 ret += QLatin1String( " WHERE " );
632 ret += mWhere->dump();
633 }
634 if ( !mOrderBy.isEmpty() )
635 {
636 ret += QLatin1String( " ORDER BY " );
637 bool bFirst = true;
638 const auto constMOrderBy = mOrderBy;
639 for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
640 {
641 if ( !bFirst )
642 ret += QLatin1String( ", " );
643 bFirst = false;
644 ret += orderBy->dump();
645 }
646 }
647 return ret;
648}
649
651{
652 QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
653 const auto constMColumns = mColumns;
654 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
655 {
656 newColumnList.push_back( column->cloneThis() );
657 }
658 QList<QgsSQLStatement::NodeTableDef *> newTableList;
659 const auto constMTableList = mTableList;
660 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
661 {
662 newTableList.push_back( table->cloneThis() );
663 }
664 QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
665 const auto constMJoins = mJoins;
666 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
667 {
668 newSelect->appendJoin( join->cloneThis() );
669 }
670 if ( mWhere )
671 {
672 newSelect->setWhere( mWhere->clone() );
673 }
674 QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
675 const auto constMOrderBy = mOrderBy;
676 for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
677 {
678 newOrderByList.push_back( columnSorted->cloneThis() );
679 }
680 newSelect->setOrderBy( newOrderByList );
681 return newSelect;
682}
683
684//
685
687{
688 QString ret;
689 if ( mType != jtDefault )
690 {
691 ret += JOIN_TYPE_TEXT[mType];
692 ret += QLatin1Char( ' ' );
693 }
694 ret += QLatin1String( "JOIN " );
695 ret += mTableDef->dump();
696 if ( mOnExpr )
697 {
698 ret += QLatin1String( " ON " );
699 ret += mOnExpr->dump();
700 }
701 else
702 {
703 ret += QLatin1String( " USING (" );
704 bool first = true;
705 const auto constMUsingColumns = mUsingColumns;
706 for ( QString column : constMUsingColumns )
707 {
708 if ( !first )
709 ret += QLatin1String( ", " );
710 first = false;
711 ret += quotedIdentifierIfNeeded( column );
712 }
713 ret += QLatin1Char( ')' );
714 }
715 return ret;
716}
717
719{
720 return cloneThis();
721}
722
724{
725 if ( mOnExpr )
726 return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
727 else
728 return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
729}
730
731//
732
734{
735 QString ret;
736 ret = mColumn->dump();
737 if ( !mAsc )
738 ret += QLatin1String( " DESC" );
739 return ret;
740}
741
743{
744 return cloneThis();
745}
746
748{
749 return new NodeColumnSorted( mColumn->cloneThis(), mAsc );
750}
751
752//
753
755{
756 QString ret( QStringLiteral( "CAST(" ) );
757 ret += mNode->dump();
758 ret += QLatin1String( " AS " );
759 ret += mType;
760 ret += ')';
761 return ret;
762}
763
765{
766 return new NodeCast( mNode->clone(), mType );
767}
768
769//
770// QgsSQLStatementFragment
771//
772
774 : QgsSQLStatement( fragment, true )
775{
776
777}
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.
An '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.
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.
An 'x IN (y, z)' operator.
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 * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
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.
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.
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< QgsSQLStatement::NodeSelectedColumn * > columns() const
Returns the list of columns.
void appendJoin(QgsSQLStatement::NodeJoin *join)
Append a join.
void setOrderBy(const QList< QgsSQLStatement::NodeColumnSorted * > &orderBy)
Sets order by columns.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
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.
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.
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.
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...
Parses SQL statements.
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)