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 )
 
 
  184  const auto constTables = n.
tables();
 
  187    table->accept( *
this );
 
  189  const auto constColumns = n.
columns();
 
  192    column->accept( *
this );
 
  194  const auto constJoins = n.
joins();
 
  197    join->accept( *
this );
 
  202  const auto constOrderBy = n.
orderBy();
 
  205    column->accept( *
this );
 
 
  257    errorMsgOut = tr( 
"No root node" );
 
  267      if ( !errorMsgOut.isEmpty() )
 
  268        errorMsgOut += QLatin1Char( 
' ' );
 
  269      errorMsgOut += tr( 
"Table %1 is referenced by column %2, but not selected in FROM / JOIN." ).arg( pair.first, pair.second );
 
  273  return errorMsgOut.isEmpty();
 
 
  290  const auto constMList = mList;
 
  291  for ( 
Node *node : constMList )
 
  293    nl->
mList.append( node->clone() );
 
 
  303  const auto constMList = mList;
 
  304  for ( 
Node *n : constMList )
 
  306    if ( !first ) msg += QLatin1String( 
", " );
 
 
  369  Q_ASSERT( 
false && 
"unexpected binary operator" );
 
 
  404  Q_ASSERT( 
false && 
"unexpected binary operator" );
 
 
  414  QString rdump( mOpRight->dump() );
 
  419    rdump.prepend( 
'(' ).append( 
')' );
 
  423  if ( leftAssociative() )
 
  425    fmt += lOp && ( lOp->
precedence() < precedence() ) ? 
"(%1)" : 
"%1";
 
  426    fmt += QLatin1String( 
" %2 " );
 
  427    fmt += rOp && ( rOp->
precedence() <= precedence() ) ? 
"(%3)" : 
"%3";
 
  431    fmt += lOp && ( lOp->
precedence() <= precedence() ) ? 
"(%1)" : 
"%1";
 
  432    fmt += QLatin1String( 
" %2 " );
 
  433    fmt += rOp && ( rOp->
precedence() < precedence() ) ? 
"(%3)" : 
"%3";
 
 
  448  return QStringLiteral( 
"%1 %2IN (%3)" ).arg( mNode->dump(), mNotIn ? 
"NOT " : 
"", mList->dump() );
 
 
  453  return new NodeInOperator( mNode->clone(), mList->clone(), mNotIn );
 
 
  460  return QStringLiteral( 
"%1 %2BETWEEN %3 AND %4" ).arg( mNode->dump(), mNotBetween ? 
"NOT " : 
"", mMinVal->dump(), mMaxVal->dump() );
 
 
  465  return new NodeBetweenOperator( mNode->clone(), mMinVal->clone(), mMaxVal->clone(), mNotBetween );
 
 
  472  return QStringLiteral( 
"%1(%2)" ).arg( mName, mArgs ? mArgs->dump() : QString() ); 
 
 
  477  return new NodeFunction( mName, mArgs ? mArgs->clone() : nullptr );
 
 
  485    return QStringLiteral( 
"NULL" );
 
  487  switch ( mValue.userType() )
 
  489    case QMetaType::Type::Int:
 
  490      return QString::number( mValue.toInt() );
 
  491    case QMetaType::Type::LongLong:
 
  492      return QString::number( mValue.toLongLong() );
 
  493    case QMetaType::Type::Double:
 
  494      return QString::number( mValue.toDouble() );
 
  495    case QMetaType::Type::QString:
 
  497    case QMetaType::Type::Bool:
 
  498      return mValue.toBool() ? 
"TRUE" : 
"FALSE";
 
  500      return tr( 
"[unsupported type: %1; value: %2]" ).arg( mValue.typeName(), mValue.toString() );
 
 
  515    ret += QLatin1String( 
"DISTINCT " );
 
  516  if ( !mTableName.isEmpty() )
 
 
  542  ret += mColumnNode->
dump();
 
  543  if ( !mAlias.isEmpty() )
 
  545    ret += QLatin1String( 
" AS " );
 
 
  567  if ( !mSchema.isEmpty() )
 
  568    ret += mSchema + 
'.';
 
  571  if ( !mAlias.isEmpty() )
 
  573    ret += QLatin1String( 
" AS " );
 
 
  593  qDeleteAll( mTableList );
 
  594  qDeleteAll( mColumns );
 
  595  qDeleteAll( mJoins );
 
  596  qDeleteAll( mOrderBy );
 
 
  601  QString ret = QStringLiteral( 
"SELECT " );
 
  603    ret += QLatin1String( 
"DISTINCT " );
 
  604  bool bFirstColumn = 
true;
 
  605  const auto constMColumns = mColumns;
 
  609      ret += QLatin1String( 
", " );
 
  610    bFirstColumn = 
false;
 
  611    ret += column->dump();
 
  613  ret += QLatin1String( 
" FROM " );
 
  614  bool bFirstTable = 
true;
 
  615  const auto constMTableList = mTableList;
 
  619      ret += QLatin1String( 
", " );
 
  621    ret += table->dump();
 
  623  const auto constMJoins = mJoins;
 
  631    ret += QLatin1String( 
" WHERE " );
 
  632    ret += mWhere->dump();
 
  634  if ( !mOrderBy.isEmpty() )
 
  636    ret += QLatin1String( 
" ORDER BY " );
 
  638    const auto constMOrderBy = mOrderBy;
 
  642        ret += QLatin1String( 
", " );
 
  644      ret += orderBy->dump();
 
 
  652  QList<QgsSQLStatement::NodeSelectedColumn *> newColumnList;
 
  653  const auto constMColumns = mColumns;
 
  656    newColumnList.push_back( column->cloneThis() );
 
  658  QList<QgsSQLStatement::NodeTableDef *> newTableList;
 
  659  const auto constMTableList = mTableList;
 
  662    newTableList.push_back( table->cloneThis() );
 
  665  const auto constMJoins = mJoins;
 
  672    newSelect->
setWhere( mWhere->clone() );
 
  674  QList<QgsSQLStatement::NodeColumnSorted *> newOrderByList;
 
  675  const auto constMOrderBy = mOrderBy;
 
  678    newOrderByList.push_back( columnSorted->cloneThis() );
 
 
  692    ret += QLatin1Char( 
' ' );
 
  694  ret += QLatin1String( 
"JOIN " );
 
  695  ret += mTableDef->dump();
 
  698    ret += QLatin1String( 
" ON " );
 
  699    ret += mOnExpr->dump();
 
  703    ret += QLatin1String( 
" USING (" );
 
  705    const auto constMUsingColumns = mUsingColumns;
 
  706    for ( QString column : constMUsingColumns )
 
  709        ret += QLatin1String( 
", " );
 
  713    ret += QLatin1Char( 
')' );
 
 
  726    return new NodeJoin( mTableDef->cloneThis(), mOnExpr->clone(), mType );
 
  728    return new NodeJoin( mTableDef->cloneThis(), mUsingColumns, mType );
 
 
  736  ret = mColumn->dump();
 
  738    ret += QLatin1String( 
" DESC" );
 
 
  756  QString ret( QStringLiteral( 
"CAST(" ) );
 
  757  ret += mNode->dump();
 
  758  ret += QLatin1String( 
" AS " );
 
 
  766  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.
 
An '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.
 
An 'x IN (y, z)' operator.
 
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 logical/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 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.
 
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)
 
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.
 
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)