QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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{
146 mStatement = other.mStatement;
147}
148
150{
151 if ( &other != this )
152 {
153 delete mRootNode;
154 mParserErrorString.clear();
156 mStatement = other.mStatement;
157 }
158 return *this;
159}
160
162{
163 delete mRootNode;
164}
165
167
169
171{
172 if ( mRootNode )
173 mRootNode->accept( v );
174}
175
177{
178 return mRootNode;
179}
180
182{
183 const auto constTables = n.tables();
184 for ( QgsSQLStatement::NodeTableDef *table : constTables )
185 {
186 table->accept( *this );
187 }
188 const auto constColumns = n.columns();
189 for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
190 {
191 column->accept( *this );
192 }
193 const auto constJoins = n.joins();
194 for ( QgsSQLStatement::NodeJoin *join : constJoins )
195 {
196 join->accept( *this );
197 }
198 QgsSQLStatement::Node *where = n.where();
199 if ( where )
200 where->accept( *this );
201 const auto constOrderBy = n.orderBy();
202 for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
203 {
204 column->accept( *this );
205 }
206}
207
209{
210 n.tableDef()->accept( *this );
211 QgsSQLStatement::Node *expr = n.onExpr();
212 if ( expr )
213 expr->accept( *this );
214}
215
222{
223 public:
224 typedef QPair<QString, QString> TableColumnPair;
225
230
231 void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
232 void visit( const QgsSQLStatement::NodeTableDef &n ) override;
233
234 QSet<QString> tableNamesDeclared;
235 QSet<TableColumnPair> tableNamesReferenced;
236};
237
239{
240 if ( !n.tableName().isEmpty() )
241 tableNamesReferenced.insert( TableColumnPair( n.tableName(), n.name() ) );
243}
244
246{
247 tableNamesDeclared.insert( n.alias().isEmpty() ? ( n.schema().isEmpty() ? n.name() : n.schema() + '.' + n.name() ) : n.alias() );
249}
250
251bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
252{
253 errorMsgOut.clear();
254 if ( !mRootNode )
255 {
256 errorMsgOut = tr( "No root node" );
257 return false;
258 }
260 mRootNode->accept( v );
261
262 for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
263 {
264 if ( !v.tableNamesDeclared.contains( pair.first ) )
265 {
266 if ( !errorMsgOut.isEmpty() )
267 errorMsgOut += QLatin1Char( ' ' );
268 errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
269 }
270 }
271
272 return errorMsgOut.isEmpty();
273}
274
276// nodes
277
279{
280 for ( QgsSQLStatement::Node *node : mList )
281 {
282 node->accept( v );
283 }
284}
285
287{
288 NodeList *nl = new NodeList;
289 const auto constMList = mList;
290 for ( Node *node : constMList )
291 {
292 nl->mList.append( node->clone() );
293 }
294
295 return nl;
296}
297
299{
300 QString msg;
301 bool first = true;
302 const auto constMList = mList;
303 for ( Node *n : constMList )
304 {
305 if ( !first ) msg += QLatin1String( ", " );
306 else first = false;
307 msg += n->dump();
308 }
309 return msg;
310}
311
312
313//
314
316{
317 return QStringLiteral( "%1 %2" ).arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
318}
319
321{
322 return new NodeUnaryOperator( mOp, mOperand->clone() );
323}
324
325//
326
328{
329 // see left/right in qgsexpressionparser.yy
330 switch ( mOp )
331 {
332 case boOr:
333 return 1;
334
335 case boAnd:
336 return 2;
337
338 case boEQ:
339 case boNE:
340 case boLE:
341 case boGE:
342 case boLT:
343 case boGT:
344 case boLike:
345 case boILike:
346 case boNotLike:
347 case boNotILike:
348 case boIs:
349 case boIsNot:
350 return 3;
351
352 case boPlus:
353 case boMinus:
354 return 4;
355
356 case boMul:
357 case boDiv:
358 case boIntDiv:
359 case boMod:
360 return 5;
361
362 case boPow:
363 return 6;
364
365 case boConcat:
366 return 7;
367 }
368 Q_ASSERT( false && "unexpected binary operator" );
369 return -1;
370}
371
373{
374 // see left/right in qgsexpressionparser.yy
375 switch ( mOp )
376 {
377 case boOr:
378 case boAnd:
379 case boEQ:
380 case boNE:
381 case boLE:
382 case boGE:
383 case boLT:
384 case boGT:
385 case boLike:
386 case boILike:
387 case boNotLike:
388 case boNotILike:
389 case boIs:
390 case boIsNot:
391 case boPlus:
392 case boMinus:
393 case boMul:
394 case boDiv:
395 case boIntDiv:
396 case boMod:
397 case boConcat:
398 return true;
399
400 case boPow:
401 return false;
402 }
403 Q_ASSERT( false && "unexpected binary operator" );
404 return false;
405}
406
408{
412
413 QString rdump( mOpRight->dump() );
414
415 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
416 if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
417 {
418 rdump.prepend( '(' ).append( ')' );
419 }
420
421 QString fmt;
422 if ( leftAssociative() )
423 {
424 fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
425 fmt += QLatin1String( " %2 " );
426 fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
427 }
428 else
429 {
430 fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
431 fmt += QLatin1String( " %2 " );
432 fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
433 }
434
435 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
436}
437
439{
440 return new NodeBinaryOperator( mOp, mOpLeft->clone(), mOpRight->clone() );
441}
442
443//
444
446{
447 return QStringLiteral( "%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
448}
449
451{
452 return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
453}
454
455//
456
458{
459 return QStringLiteral( "%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
460}
461
463{
464 return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
465}
466
467//
468
470{
471 return QStringLiteral( "%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); // function
472}
473
475{
476 return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
477}
478
479//
480
482{
483 if ( QgsVariantUtils::isNull( mValue ) )
484 return QStringLiteral( "NULL" );
485
486 switch ( mValue.type() )
487 {
488 case QVariant::Int:
489 return QString::number( mValue.toInt() );
490 case QVariant::LongLong:
491 return QString::number( mValue.toLongLong() );
492 case QVariant::Double:
493 return QString::number( mValue.toDouble() );
494 case QVariant::String:
495 return quotedString( mValue.toString() );
496 case QVariant::Bool:
497 return mValue.toBool() ? "TRUE" : "FALSE";
498 default:
499 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
500 }
501}
502
504{
505 return new NodeLiteral( mValue );
506}
507
508//
509
511{
512 QString ret;
513 if ( mDistinct )
514 ret += QLatin1String( "DISTINCT " );
515 if ( !mTableName.isEmpty() )
516 {
517 ret += quotedIdentifierIfNeeded( mTableName );
518 ret += '.';
519 }
520 ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
521 return ret;
522}
523
525{
526 return cloneThis();
527}
528
530{
531 NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
532 newColumnRef->setDistinct( mDistinct );
533 return newColumnRef;
534}
535
536//
537
539{
540 QString ret;
541 ret += mColumnNode->dump();
542 if ( !mAlias.isEmpty() )
543 {
544 ret += QLatin1String( " AS " );
545 ret += quotedIdentifierIfNeeded( mAlias );
546 }
547 return ret;
548}
549
551{
552 NodeSelectedColumn *newObj = new NodeSelectedColumn( mColumnNode->clone() );
553 newObj->setAlias( mAlias );
554 return newObj;
555}
556
558{
559 return cloneThis();
560}
561//
562
564{
565 QString ret;
566 if ( !mSchema.isEmpty() )
567 ret += mSchema + '.';
568
569 ret += quotedIdentifierIfNeeded( mName );
570 if ( !mAlias.isEmpty() )
571 {
572 ret += QLatin1String( " AS " );
573 ret += quotedIdentifierIfNeeded( mAlias );
574 }
575 return ret;
576}
577
579{
580 return new NodeTableDef( mSchema, mName, mAlias );
581}
582
584{
585 return cloneThis();
586}
587
588//
589
591{
592 qDeleteAll( mTableList );
593 qDeleteAll( mColumns );
594 qDeleteAll( mJoins );
595 delete mWhere;
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.
'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.
Reference to a column.
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.
QString mParserErrorString
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)
Create a copy of this statement.
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.
virtual ~QgsSQLStatement()
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)
Returns true if the specified variant should be considered a NULL value.
#define str(x)
Definition: qgis.cpp:37
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)