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