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