QGIS API Documentation 3.41.0-Master (45a0abf3bec)
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#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 delete mRootNode;
155 mParserErrorString.clear();
156 mStatement = other.mStatement;
159 }
160 return *this;
161}
162
167
169
171
177
179{
180 return mRootNode;
181}
182
184{
185 const auto constTables = n.tables();
186 for ( QgsSQLStatement::NodeTableDef *table : constTables )
187 {
188 table->accept( *this );
189 }
190 const auto constColumns = n.columns();
191 for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
192 {
193 column->accept( *this );
194 }
195 const auto constJoins = n.joins();
196 for ( QgsSQLStatement::NodeJoin *join : constJoins )
197 {
198 join->accept( *this );
199 }
200 QgsSQLStatement::Node *where = n.where();
201 if ( where )
202 where->accept( *this );
203 const auto constOrderBy = n.orderBy();
204 for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
205 {
206 column->accept( *this );
207 }
208}
209
211{
212 n.tableDef()->accept( *this );
213 QgsSQLStatement::Node *expr = n.onExpr();
214 if ( expr )
215 expr->accept( *this );
216}
217
224{
225 public:
226 typedef QPair<QString, QString> TableColumnPair;
227
232
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
241{
242 if ( !n.tableName().isEmpty() )
243 tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
245}
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
323{
324 return new NodeUnaryOperator( mOp, mOperand->clone() );
325}
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
441{
442 return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
443}
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
465{
466 return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
467}
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{
485 if ( QgsVariantUtils::isNull( mValue ) )
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
506{
507 return new NodeLiteral( mValue );
508}
509
510//
511
513{
514 QString ret;
515 if ( mDistinct )
516 ret += QLatin1String( "DISTINCT " );
517 if ( !mTableName.isEmpty() )
518 {
519 ret += quotedIdentifierIfNeeded( mTableName );
520 ret += '.';
521 }
522 ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
523 return ret;
524}
525
527{
528 return cloneThis();
529}
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 " );
547 ret += quotedIdentifierIfNeeded( mAlias );
548 }
549 return ret;
550}
551
553{
554 NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
555 newObj->setAlias( mAlias );
556 return newObj;
557}
558
560{
561 return cloneThis();
562}
563//
564
566{
567 QString ret;
568 if ( !mSchema.isEmpty() )
569 ret += mSchema + '.';
570
571 ret += quotedIdentifierIfNeeded( mName );
572 if ( !mAlias.isEmpty() )
573 {
574 ret += QLatin1String( " AS " );
575 ret += quotedIdentifierIfNeeded( mAlias );
576 }
577 return ret;
578}
579
581{
582 return new NodeTableDef( mSchema, mName, mAlias );
583}
584
586{
587 return cloneThis();
588}
589
590//
591
593{
594 qDeleteAll( mTableList );
595 qDeleteAll( mColumns );
596 qDeleteAll( mJoins );
597 delete mWhere;
598 qDeleteAll( mOrderBy );
599}
600
602{
603 QString ret = QStringLiteral( "SELECT " );
604 if ( mDistinct )
605 ret += QLatin1String( "DISTINCT " );
606 bool bFirstColumn = true;
607 const auto constMColumns = mColumns;
608 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
609 {
610 if ( !bFirstColumn )
611 ret += QLatin1String( ", " );
612 bFirstColumn = false;
613 ret += column->dump();
614 }
615 ret += QLatin1String( " FROM " );
616 bool bFirstTable = true;
617 const auto constMTableList = mTableList;
618 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
619 {
620 if ( !bFirstTable )
621 ret += QLatin1String( ", " );
622 bFirstTable = false;
623 ret += table->dump();
624 }
625 const auto constMJoins = mJoins;
626 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
627 {
628 ret += ' ';
629 ret += join->dump();
630 }
631 if ( mWhere )
632 {
633 ret += QLatin1String( " WHERE " );
634 ret += mWhere->dump();
635 }
636 if ( !mOrderBy.isEmpty() )
637 {
638 ret += QLatin1String( " ORDER BY " );
639 bool bFirst = true;
640 const auto constMOrderBy = mOrderBy;
641 for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
642 {
643 if ( !bFirst )
644 ret += QLatin1String( ", " );
645 bFirst = false;
646 ret += orderBy->dump();
647 }
648 }
649 return ret;
650}
651
653{
654 QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
655 const auto constMColumns = mColumns;
656 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
657 {
658 newColumnList.push_back( column->cloneThis() );
659 }
660 QList<QgsSQLStatement::NodeTableDef *> newTableList;
661 const auto constMTableList = mTableList;
662 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
663 {
664 newTableList.push_back( table->cloneThis() );
665 }
666 QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
667 const auto constMJoins = mJoins;
668 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
669 {
670 newSelect->appendJoin( join->cloneThis() );
671 }
672 if ( mWhere )
673 {
674 newSelect->setWhere( mWhere->clone() );
675 }
676 QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
677 const auto constMOrderBy = mOrderBy;
678 for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
679 {
680 newOrderByList.push_back( columnSorted->cloneThis() );
681 }
682 newSelect->setOrderBy( newOrderByList );
683 return newSelect;
684}
685
686//
687
689{
690 QString ret;
691 if ( mType != jtDefault )
692 {
693 ret += JOIN_TYPE_TEXT[mType];
694 ret += QLatin1Char( ' ' );
695 }
696 ret += QLatin1String( "JOIN " );
697 ret += mTableDef->dump();
698 if ( mOnExpr )
699 {
700 ret += QLatin1String( " ON " );
701 ret += mOnExpr->dump();
702 }
703 else
704 {
705 ret += QLatin1String( " USING (" );
706 bool first = true;
707 const auto constMUsingColumns = mUsingColumns;
708 for ( QString column : constMUsingColumns )
709 {
710 if ( !first )
711 ret += QLatin1String( ", " );
712 first = false;
713 ret += quotedIdentifierIfNeeded( column );
714 }
715 ret += QLatin1Char( ')' );
716 }
717 return ret;
718}
719
721{
722 return cloneThis();
723}
724
726{
727 if ( mOnExpr )
728 return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
729 else
730 return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
731}
732
733//
734
736{
737 QString ret;
738 ret = mColumn->dump();
739 if ( !mAsc )
740 ret += QLatin1String( " DESC" );
741 return ret;
742}
743
745{
746 return cloneThis();
747}
748
750{
751 return new NodeColumnSorted( mColumn->cloneThis(), mAsc );
752}
753
754//
755
757{
758 QString ret( QStringLiteral( "CAST(" ) );
759 ret += mNode->dump();
760 ret += QLatin1String( " AS " );
761 ret += mType;
762 ret += ')';
763 return ret;
764}
765
767{
768 return new NodeCast( mNode->clone(), mType );
769}
770
771//
772// QgsSQLStatementFragment
773//
774
776 : QgsSQLStatement( fragment, true )
777{
778
779}
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.
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 * 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 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.
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.
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.
#define str(x)
Definition qgis.cpp:39
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)