QGIS API Documentation 4.1.0-Master (3b8ef1f72a3)
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 "qgsexpression.h"
24#include "qgsvariantutils.h"
25
26#include <QRegularExpression>
27#include <QString>
28
29using namespace Qt::StringLiterals;
30
31// from parser
32extern QgsSQLStatement::Node *parse( const QString &str, QString &parserErrorMsg, bool allowFragments );
33
35// operators
36
38 // this must correspond (number and order of element) to the declaration of the enum BinaryOperator
39 "OR", "AND", "=", "<>", "<=", ">=", "<", ">", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT", "+", "-", "*", "/", "//", "%", "^", "||"
40};
41
43 // this must correspond (number and order of element) to the declaration of the enum UnaryOperator
44 "NOT",
45 "-"
46};
47
48const char *QgsSQLStatement::JOIN_TYPE_TEXT[] = {
49 // this must correspond (number and order of element) to the declaration of the enum JoinType
50 "",
51 "LEFT",
52 "LEFT OUTER",
53 "RIGHT",
54 "RIGHT OUTER",
55 "CROSS",
56 "INNER",
57 "FULL"
58};
59
61
63{
64 if ( !mStatement.isNull() )
65 return mStatement;
66 else
67 return dump();
68}
69
70QString QgsSQLStatement::dump() const
71{
72 if ( !mRootNode )
73 return tr( "(no root)" );
74
75 return mRootNode->dump();
76}
77
78QString QgsSQLStatement::quotedIdentifier( QString name )
79{
80 return u"\"%1\""_s.arg( name.replace( '\"', "\"\""_L1 ) );
81}
82
83QString QgsSQLStatement::quotedIdentifierIfNeeded( const QString &name )
84{
85 // This might not be complete, but it must be at least what we recognize
86 static const char *const RESERVED_KEYWORDS[] = { "AND", "OR", "NOT", "LIKE", "IN", "IS", "BETWEEN", "NULL", "SELECT", "ALL", "DISTINCT", "CAST",
87 "AS", "FROM", "JOIN", "ON", "USING", "WHERE", "ORDER", "BY", "ASC", "DESC", "LEFT", "RIGHT",
88 "INNER", "OUTER", "CROSS", "FULL", "NATURAL", "UNION", "OFFSET", "LIMIT", "GROUP", "HAVING" };
89
90 for ( size_t i = 0; i < sizeof( RESERVED_KEYWORDS ) / sizeof( RESERVED_KEYWORDS[0] ); ++i )
91 {
92 if ( name.compare( QString( RESERVED_KEYWORDS[i] ), Qt::CaseInsensitive ) == 0 )
93 {
94 return quotedIdentifier( name );
95 }
96 }
97 const thread_local QRegularExpression IDENTIFIER_RE( "^[A-Za-z_\\x80-\\xff][A-Za-z0-9_\\x80-\\xff]*$" );
98 return IDENTIFIER_RE.match( name ).hasMatch() ? name : quotedIdentifier( name );
99}
100
102{
103 if ( text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' )
104 {
105 // strip double quotes on start,end
106 text = text.mid( 1, text.length() - 2 );
107
108 // make single "double quotes" from double "double quotes"
109 text.replace( "\"\""_L1, "\""_L1 );
110 }
111 return text;
112}
113
115{
116 if ( text.length() >= 2 && text[0] == '[' && text[text.length() - 1] == ']' )
117 {
118 // strip square brackets on start,end
119 text = text.mid( 1, text.length() - 2 );
120 }
121 return text;
122}
123
124QString QgsSQLStatement::quotedString( QString text )
125{
126 text.replace( '\'', "''"_L1 );
127 text.replace( '\\', "\\\\"_L1 );
128 text.replace( '\n', "\\n"_L1 );
129 text.replace( '\t', "\\t"_L1 );
130 return u"'%1'"_s.arg( text );
131}
132
134 : QgsSQLStatement( expr, false )
135{}
136
137QgsSQLStatement::QgsSQLStatement( const QString &expr, bool allowFragments )
138 : mAllowFragments( allowFragments )
139{
141 mStatement = expr;
142}
143
150
152{
153 if ( &other != this )
154 {
155 mParserErrorString.clear();
156 mStatement = other.mStatement;
159 }
160 return *this;
161}
162
165
167{
168 return !mParserErrorString.isNull() || ( !mRootNode && !mAllowFragments );
169}
170
172{
173 return mParserErrorString;
174}
175
177{
178 if ( mRootNode )
179 mRootNode->accept( v );
180}
181
183{
184 return mRootNode.get();
185}
186
188{
189 const auto constTables = n.tables();
190 for ( QgsSQLStatement::NodeTableDef *table : constTables )
191 {
192 table->accept( *this );
193 }
194 const auto constColumns = n.columns();
195 for ( QgsSQLStatement::NodeSelectedColumn *column : constColumns )
196 {
197 column->accept( *this );
198 }
199 const auto constJoins = n.joins();
200 for ( QgsSQLStatement::NodeJoin *join : constJoins )
201 {
202 join->accept( *this );
203 }
204 QgsSQLStatement::Node *where = n.where();
205 if ( where )
206 where->accept( *this );
207 const auto constOrderBy = n.orderBy();
208 for ( QgsSQLStatement::NodeColumnSorted *column : constOrderBy )
209 {
210 column->accept( *this );
211 }
212}
213
215{
216 n.tableDef()->accept( *this );
217 QgsSQLStatement::Node *expr = n.onExpr();
218 if ( expr )
219 expr->accept( *this );
220}
221
228{
229 public:
230 typedef QPair<QString, QString> TableColumnPair;
231
236
238 void visit( const QgsSQLStatement::NodeColumnRef &n ) override;
239 void visit( const QgsSQLStatement::NodeTableDef &n ) override;
240
241 QSet<QString> tableNamesDeclared;
242 QSet<TableColumnPair> tableNamesReferenced;
243};
244
251
253{
254 tableNamesDeclared.insert( n.alias().isEmpty() ? ( n.schema().isEmpty() ? n.name() : n.schema() + '.' + n.name() ) : n.alias() );
256}
257
258bool QgsSQLStatement::doBasicValidationChecks( QString &errorMsgOut ) const
259{
260 errorMsgOut.clear();
261 if ( !mRootNode )
262 {
263 errorMsgOut = tr( "No root node" );
264 return false;
265 }
267 mRootNode->accept( v );
268
269 for ( const QgsSQLStatementCollectTableNames::TableColumnPair &pair : std::as_const( v.tableNamesReferenced ) )
270 {
271 if ( !v.tableNamesDeclared.contains( pair.first ) )
272 {
273 if ( !errorMsgOut.isEmpty() )
274 errorMsgOut += ' '_L1;
275 errorMsgOut += tr( "Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
276 }
277 }
278
279 return errorMsgOut.isEmpty();
280}
281
283// nodes
284
286{
287 for ( QgsSQLStatement::Node *node : mList )
288 {
289 node->accept( v );
290 }
291}
292
294{
295 NodeList *nl = new NodeList;
296 const auto constMList = mList;
297 for ( Node *node : constMList )
298 {
299 nl->mList.append( node->clone() );
300 }
301
302 return nl;
303}
304
306{
307 QString msg;
308 bool first = true;
309 const auto constMList = mList;
310 for ( Node *n : constMList )
311 {
312 if ( !first )
313 msg += ", "_L1;
314 else
315 first = false;
316 msg += n->dump();
317 }
318 return msg;
319}
320
321
322//
323
325{
326 return u"%1 %2"_s.arg( UNARY_OPERATOR_TEXT[mOp], mOperand->dump() );
327}
328
333
338
339//
340
342{
343 // see left/right in qgsexpressionparser.yy
344 switch ( mOp )
345 {
346 case boOr:
347 return 1;
348
349 case boAnd:
350 return 2;
351
352 case boEQ:
353 case boNE:
354 case boLE:
355 case boGE:
356 case boLT:
357 case boGT:
358 case boLike:
359 case boILike:
360 case boNotLike:
361 case boNotILike:
362 case boIs:
363 case boIsNot:
364 return 3;
365
366 case boPlus:
367 case boMinus:
368 return 4;
369
370 case boMul:
371 case boDiv:
372 case boIntDiv:
373 case boMod:
374 return 5;
375
376 case boPow:
377 return 6;
378
379 case boConcat:
380 return 7;
381 }
382 Q_ASSERT( false && "unexpected binary operator" );
383 return -1;
384}
385
387{
388 // see left/right in qgsexpressionparser.yy
389 switch ( mOp )
390 {
391 case boOr:
392 case boAnd:
393 case boEQ:
394 case boNE:
395 case boLE:
396 case boGE:
397 case boLT:
398 case boGT:
399 case boLike:
400 case boILike:
401 case boNotLike:
402 case boNotILike:
403 case boIs:
404 case boIsNot:
405 case boPlus:
406 case boMinus:
407 case boMul:
408 case boDiv:
409 case boIntDiv:
410 case boMod:
411 case boConcat:
412 return true;
413
414 case boPow:
415 return false;
416 }
417 Q_ASSERT( false && "unexpected binary operator" );
418 return false;
419}
420
425
427{
431
432 QString rdump( mOpRight->dump() );
433
434 // avoid dumping "IS (NOT ...)" as "IS NOT ..."
435 if ( mOp == boIs && ruOp && ruOp->op() == uoNot )
436 {
437 rdump.prepend( '(' ).append( ')' );
438 }
439
440 QString fmt;
441 if ( leftAssociative() )
442 {
443 fmt += lOp && ( lOp->precedence() < precedence() ) ? "(%1)" : "%1";
444 fmt += " %2 "_L1;
445 fmt += rOp && ( rOp->precedence() <= precedence() ) ? "(%3)" : "%3";
446 }
447 else
448 {
449 fmt += lOp && ( lOp->precedence() <= precedence() ) ? "(%1)" : "%1";
450 fmt += " %2 "_L1;
451 fmt += rOp && ( rOp->precedence() < precedence() ) ? "(%3)" : "%3";
452 }
453
454 return fmt.arg( mOpLeft->dump(), BINARY_OPERATOR_TEXT[mOp], rdump );
455}
456
461
462//
463
465{
466 return u"%1 %2IN (%3)"_s.arg( mNode->dump(), mNotIn ? "NOT " : "", mList->dump() );
467}
468
470{
471 return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
472}
473
474//
475
477{
478 return u"%1 %2BETWEEN %3 AND %4"_s.arg( mNode->dump(), mNotBetween ? "NOT " : "", mMinVal->dump(), mMaxVal->dump() );
479}
480
485
486//
487
489{
490 return u"%1(%2)"_s.arg( mName, mArgs ? mArgs->dump() : QString() ); // function
491}
492
494{
495 return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
496}
497
498//
499
501{
503 return u"NULL"_s;
504
505 switch ( mValue.userType() )
506 {
507 case QMetaType::Type::Int:
508 return QString::number( mValue.toInt() );
509 case QMetaType::Type::LongLong:
510 return QString::number( mValue.toLongLong() );
511 case QMetaType::Type::Double:
512 return QString::number( mValue.toDouble() );
513 case QMetaType::Type::QString:
514 return quotedString( mValue.toString() );
515 case QMetaType::Type::Bool:
516 return mValue.toBool() ? "TRUE" : "FALSE";
517 default:
518 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
519 }
520}
521
526
528{
530 return u"NULL"_s;
531
532 switch ( mValue.userType() )
533 {
534 case QMetaType::Type::Int:
535 return QString::number( mValue.toInt() );
536 case QMetaType::Type::Double:
537 return qgsDoubleToString( mValue.toDouble() );
538 case QMetaType::Type::LongLong:
539 return QString::number( mValue.toLongLong() );
540 case QMetaType::Type::QString:
541 return QgsExpression::quotedString( mValue.toString() );
542 case QMetaType::Type::QTime:
543 return QgsExpression::quotedString( mValue.toTime().toString( Qt::ISODate ) );
544 case QMetaType::Type::QDate:
545 return QgsExpression::quotedString( mValue.toDate().toString( Qt::ISODate ) );
546 case QMetaType::Type::QDateTime:
547 return QgsExpression::quotedString( mValue.toDateTime().toString( Qt::ISODate ) );
548 case QMetaType::Type::Bool:
549 return mValue.toBool() ? u"TRUE"_s : u"FALSE"_s;
550 default:
551 return tr( "[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
552 }
553}
554
555//
556
558{
559 QString ret;
560 if ( mDistinct )
561 ret += "DISTINCT "_L1;
562 if ( !mTableName.isEmpty() )
563 {
565 ret += '.';
566 }
567 ret += ( mStar ) ? mName : quotedIdentifierIfNeeded( mName );
568 return ret;
569}
570
575
577{
578 NodeColumnRef *newColumnRef = new NodeColumnRef( mTableName, mName, mStar );
579 newColumnRef->setDistinct( mDistinct );
580 return newColumnRef;
581}
582
583//
584
586{
587 QString ret;
588 ret += mColumnNode->dump();
589 if ( !mAlias.isEmpty() )
590 {
591 ret += " AS "_L1;
593 }
594 return ret;
595}
596
603
608//
609
611{
612 QString ret;
613 if ( !mSchema.isEmpty() )
614 ret += mSchema + '.';
615
617 if ( !mAlias.isEmpty() )
618 {
619 ret += " AS "_L1;
621 }
622 return ret;
623}
624
629
634
635//
636
638{
639 qDeleteAll( mTableList );
640 qDeleteAll( mColumns );
641 qDeleteAll( mJoins );
642 qDeleteAll( mOrderBy );
643}
644
646{
647 QString ret = u"SELECT "_s;
648 if ( mDistinct )
649 ret += "DISTINCT "_L1;
650 bool bFirstColumn = true;
651 const auto constMColumns = mColumns;
652 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
653 {
654 if ( !bFirstColumn )
655 ret += ", "_L1;
656 bFirstColumn = false;
657 ret += column->dump();
658 }
659 ret += " FROM "_L1;
660 bool bFirstTable = true;
661 const auto constMTableList = mTableList;
662 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
663 {
664 if ( !bFirstTable )
665 ret += ", "_L1;
666 bFirstTable = false;
667 ret += table->dump();
668 }
669 const auto constMJoins = mJoins;
670 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
671 {
672 ret += ' ';
673 ret += join->dump();
674 }
675 if ( mWhere )
676 {
677 ret += " WHERE "_L1;
678 ret += mWhere->dump();
679 }
680 if ( !mOrderBy.isEmpty() )
681 {
682 ret += " ORDER BY "_L1;
683 bool bFirst = true;
684 const auto constMOrderBy = mOrderBy;
685 for ( QgsSQLStatement::NodeColumnSorted *orderBy : constMOrderBy )
686 {
687 if ( !bFirst )
688 ret += ", "_L1;
689 bFirst = false;
690 ret += orderBy->dump();
691 }
692 }
693 return ret;
694}
695
697{
698 QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
699 const auto constMColumns = mColumns;
700 for ( QgsSQLStatement::NodeSelectedColumn *column : constMColumns )
701 {
702 newColumnList.push_back( column->cloneThis() );
703 }
704 QList<QgsSQLStatement::NodeTableDef *> newTableList;
705 const auto constMTableList = mTableList;
706 for ( QgsSQLStatement::NodeTableDef *table : constMTableList )
707 {
708 newTableList.push_back( table->cloneThis() );
709 }
710 QgsSQLStatement::NodeSelect *newSelect = new NodeSelect( newTableList, newColumnList, mDistinct );
711 const auto constMJoins = mJoins;
712 for ( QgsSQLStatement::NodeJoin *join : constMJoins )
713 {
714 newSelect->appendJoin( join->cloneThis() );
715 }
716 if ( mWhere )
717 {
718 newSelect->setWhere( mWhere->clone() );
719 }
720 QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
721 const auto constMOrderBy = mOrderBy;
722 for ( QgsSQLStatement::NodeColumnSorted *columnSorted : constMOrderBy )
723 {
724 newOrderByList.push_back( columnSorted->cloneThis() );
725 }
726 newSelect->setOrderBy( newOrderByList );
727 return newSelect;
728}
729
730//
731
733{
734 QString ret;
735 if ( mType != jtDefault )
736 {
737 ret += JOIN_TYPE_TEXT[mType];
738 ret += ' '_L1;
739 }
740 ret += "JOIN "_L1;
741 ret += mTableDef->dump();
742 if ( mOnExpr )
743 {
744 ret += " ON "_L1;
745 ret += mOnExpr->dump();
746 }
747 else
748 {
749 ret += " USING ("_L1;
750 bool first = true;
751 const auto constMUsingColumns = mUsingColumns;
752 for ( QString column : constMUsingColumns )
753 {
754 if ( !first )
755 ret += ", "_L1;
756 first = false;
757 ret += quotedIdentifierIfNeeded( column );
758 }
759 ret += ')'_L1;
760 }
761 return ret;
762}
763
768
770{
771 if ( mOnExpr )
772 return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
773 else
774 return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
775}
776
777//
778
780{
781 QString ret;
782 ret = mColumn->dump();
783 if ( !mAsc )
784 ret += " DESC"_L1;
785 return ret;
786}
787
792
797
798//
799
801{
802 QString ret( u"CAST("_s );
803 ret += mNode->dump();
804 ret += " AS "_L1;
805 ret += mType;
806 ret += ')';
807 return ret;
808}
809
811{
812 return new NodeCast( mNode->clone(), mType );
813}
814
815//
816// QgsSQLStatementFragment
817//
818
820 : QgsSQLStatement( fragment, true )
821{}
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes).
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.
QString text() const
Returns a the name of this operator without the operands.
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.
QString valueAsString() const
Returns a string representation of the node's literal value.
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.
QString text() const
Returns a the name of this operator without the operands.
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.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:6995
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)