21#include <QRegularExpression>
37 "=",
"<>",
"<=",
">=",
"<",
">",
"LIKE",
"NOT LIKE",
"ILIKE",
"NOT ILIKE",
"IS",
"IS NOT",
38 "+",
"-",
"*",
"/",
"//",
"%",
"^",
51 "",
"LEFT",
"LEFT OUTER",
"RIGHT",
"RIGHT OUTER",
"CROSS",
"INNER",
"FULL"
67 return tr(
"(no root)" );
74 return QStringLiteral(
"\"%1\"" ).arg( name.replace(
'\"', QLatin1String(
"\"\"" ) ) );
80 static const char *
const RESERVED_KEYWORDS[] =
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"
88 for (
size_t i = 0; i <
sizeof( RESERVED_KEYWORDS ) /
sizeof( RESERVED_KEYWORDS[0] ); ++i )
90 if ( name.compare( QString( RESERVED_KEYWORDS[i] ), Qt::CaseInsensitive ) == 0 )
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 );
101 if ( text.length() >= 2 && text[0] ==
'"' && text[text.length() - 1] ==
'"' )
104 text = text.mid( 1, text.length() - 2 );
107 text.replace( QLatin1String(
"\"\"" ), QLatin1String(
"\"" ) );
114 if ( text.length() >= 2 && text[0] ==
'[' && text[text.length() - 1] ==
']' )
117 text = text.mid( 1, text.length() - 2 );
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 );
137 : mAllowFragments( allowFragments )
144 : mAllowFragments( other.mAllowFragments )
145 , mStatement( other.mStatement )
152 if ( &other !=
this )
185 const auto constTables = n.
tables();
188 table->accept( *
this );
190 const auto constColumns = n.
columns();
193 column->accept( *
this );
195 const auto constJoins = n.
joins();
198 join->accept( *
this );
203 const auto constOrderBy = n.
orderBy();
206 column->accept( *
this );
258 errorMsgOut = tr(
"No root node" );
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 );
274 return errorMsgOut.isEmpty();
291 const auto constMList = mList;
292 for (
Node *node : constMList )
294 nl->
mList.append( node->clone() );
304 const auto constMList = mList;
305 for (
Node *n : constMList )
307 if ( !first ) msg += QLatin1String(
", " );
370 Q_ASSERT(
false &&
"unexpected binary operator" );
405 Q_ASSERT(
false &&
"unexpected binary operator" );
415 QString rdump( mOpRight->dump() );
420 rdump.prepend(
'(' ).append(
')' );
424 if ( leftAssociative() )
426 fmt += lOp && ( lOp->
precedence() < precedence() ) ?
"(%1)" :
"%1";
427 fmt += QLatin1String(
" %2 " );
428 fmt += rOp && ( rOp->
precedence() <= precedence() ) ?
"(%3)" :
"%3";
432 fmt += lOp && ( lOp->
precedence() <= precedence() ) ?
"(%1)" :
"%1";
433 fmt += QLatin1String(
" %2 " );
434 fmt += rOp && ( rOp->
precedence() < precedence() ) ?
"(%3)" :
"%3";
449 return QStringLiteral(
"%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ?
"NOT " :
"", mList->dump() );
454 return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
461 return QStringLiteral(
"%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ?
"NOT " :
"", mMinVal->dump(), mMaxVal->dump() );
466 return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
473 return QStringLiteral(
"%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() );
478 return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
486 return QStringLiteral(
"NULL" );
488 switch ( mValue.type() )
491 return QString::number( mValue.toInt() );
492 case QVariant::LongLong:
493 return QString::number( mValue.toLongLong() );
494 case QVariant::Double:
495 return QString::number( mValue.toDouble() );
496 case QVariant::String:
499 return mValue.toBool() ?
"TRUE" :
"FALSE";
501 return tr(
"[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
516 ret += QLatin1String(
"DISTINCT " );
517 if ( !mTableName.isEmpty() )
543 ret += mColumnNode->
dump();
544 if ( !mAlias.isEmpty() )
546 ret += QLatin1String(
" AS " );
568 if ( !mSchema.isEmpty() )
569 ret += mSchema +
'.';
572 if ( !mAlias.isEmpty() )
574 ret += QLatin1String(
" AS " );
594 qDeleteAll( mTableList );
595 qDeleteAll( mColumns );
596 qDeleteAll( mJoins );
598 qDeleteAll( mOrderBy );
603 QString ret = QStringLiteral(
"SELECT " );
605 ret += QLatin1String(
"DISTINCT " );
606 bool bFirstColumn =
true;
607 const auto constMColumns = mColumns;
611 ret += QLatin1String(
", " );
612 bFirstColumn =
false;
613 ret += column->dump();
615 ret += QLatin1String(
" FROM " );
616 bool bFirstTable =
true;
617 const auto constMTableList = mTableList;
621 ret += QLatin1String(
", " );
623 ret += table->dump();
625 const auto constMJoins = mJoins;
633 ret += QLatin1String(
" WHERE " );
634 ret += mWhere->dump();
636 if ( !mOrderBy.isEmpty() )
638 ret += QLatin1String(
" ORDER BY " );
640 const auto constMOrderBy = mOrderBy;
644 ret += QLatin1String(
", " );
646 ret += orderBy->dump();
654 QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
655 const auto constMColumns = mColumns;
658 newColumnList.push_back( column->cloneThis() );
660 QList<QgsSQLStatement::NodeTableDef *> newTableList;
661 const auto constMTableList = mTableList;
664 newTableList.push_back( table->cloneThis() );
667 const auto constMJoins = mJoins;
674 newSelect->
setWhere( mWhere->clone() );
676 QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
677 const auto constMOrderBy = mOrderBy;
680 newOrderByList.push_back( columnSorted->cloneThis() );
694 ret += QLatin1Char(
' ' );
696 ret += QLatin1String(
"JOIN " );
697 ret += mTableDef->dump();
700 ret += QLatin1String(
" ON " );
701 ret += mOnExpr->dump();
705 ret += QLatin1String(
" USING (" );
707 const auto constMUsingColumns = mUsingColumns;
708 for ( QString column : constMUsingColumns )
711 ret += QLatin1String(
", " );
715 ret += QLatin1Char(
')' );
728 return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
730 return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
738 ret = mColumn->dump();
740 ret += QLatin1String(
" DESC" );
758 QString ret( QStringLiteral(
"CAST(" ) );
759 ret += mNode->dump();
760 ret += QLatin1String(
" AS " );
768 return new NodeCast( mNode->clone(), mType );
QgsSQLStatementCollectTableNames()=default
Constructor for QgsSQLStatementCollectTableNames.
QSet< TableColumnPair > tableNamesReferenced
QPair< QString, QString > TableColumnPair
QSet< QString > tableNamesDeclared
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.
int precedence() const
Precedence.
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.
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.
QgsSQLStatement::Node * parse(const QString &str, QString &parserErrorMsg, bool allowFragments)