QGIS API Documentation  2.14.0-Essen
qgssqlexpressioncompiler.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssqlexpressioncompiler.cpp
3  ----------------------------
4  begin : November 2015
5  copyright : (C) 2015 Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
19  : mResult( None )
20  , mFields( fields )
21  , mFlags( flags )
22 {
23 }
24 
26 {
27 
28 }
29 
31 {
32  if ( exp->rootNode() )
33  return compileNode( exp->rootNode(), mResult );
34  else
35  return Fail;
36 }
37 
39 {
40  QString quoted = identifier;
41  quoted.replace( '"', "\"\"" );
42  quoted = quoted.prepend( '\"' ).append( '\"' );
43  return quoted;
44 }
45 
47 {
48  ok = true;
49 
50  if ( value.isNull() )
51  return "NULL";
52 
53  switch ( value.type() )
54  {
55  case QVariant::Int:
56  case QVariant::LongLong:
57  case QVariant::Double:
58  return value.toString();
59 
60  case QVariant::Bool:
61  return value.toBool() ? "TRUE" : "FALSE";
62 
63  default:
64  case QVariant::String:
65  QString v = value.toString();
66  v.replace( '\'', "''" );
67  if ( v.contains( '\\' ) )
68  return v.replace( '\\', "\\\\" ).prepend( "E'" ).append( '\'' );
69  else
70  return v.prepend( '\'' ).append( '\'' );
71  }
72 }
73 
75 {
76  switch ( node->nodeType() )
77  {
79  {
80  const QgsExpression::NodeUnaryOperator* n = static_cast<const QgsExpression::NodeUnaryOperator*>( node );
81  switch ( n->op() )
82  {
84  break;
85 
87  break;
88  }
89 
90  break;
91  }
92 
94  {
95  const QgsExpression::NodeBinaryOperator* n = static_cast<const QgsExpression::NodeBinaryOperator*>( node );
96 
97  QString op;
98  bool partialCompilation = false;
99  bool failOnPartialNode = false;
100  switch ( n->op() )
101  {
102  case QgsExpression::boEQ:
104  {
105  // equality between column refs results in a partial compilation, since provider is performing
106  // case-insensitive matches between strings
107  partialCompilation = true;
108  }
109 
110  op = "=";
111  break;
112 
113  case QgsExpression::boGE:
114  op = ">=";
115  break;
116 
117  case QgsExpression::boGT:
118  op = ">";
119  break;
120 
121  case QgsExpression::boLE:
122  op = "<=";
123  break;
124 
125  case QgsExpression::boLT:
126  op = "<";
127  break;
128 
129  case QgsExpression::boIs:
130  op = "IS";
131  break;
132 
134  op = "IS NOT";
135  failOnPartialNode = mFlags.testFlag( CaseInsensitiveStringMatch );
136  break;
137 
139  op = "LIKE";
140  partialCompilation = mFlags.testFlag( LikeIsCaseInsensitive );
141  break;
142 
144  if ( mFlags.testFlag( LikeIsCaseInsensitive ) )
145  op = "LIKE";
146  else
147  op = "ILIKE";
148  break;
149 
151  op = "NOT LIKE";
152  partialCompilation = mFlags.testFlag( LikeIsCaseInsensitive );
153  failOnPartialNode = mFlags.testFlag( CaseInsensitiveStringMatch );
154  break;
155 
157  failOnPartialNode = mFlags.testFlag( CaseInsensitiveStringMatch );
158  if ( mFlags.testFlag( LikeIsCaseInsensitive ) )
159  op = "NOT LIKE";
160  else
161  op = "NOT ILIKE";
162  break;
163 
164  case QgsExpression::boOr:
165  op = "OR";
166  break;
167 
169  op = "AND";
170  break;
171 
172  case QgsExpression::boNE:
173  failOnPartialNode = mFlags.testFlag( CaseInsensitiveStringMatch );
174  op = "<>";
175  break;
176 
178  op = "*";
179  break;
180 
182  op = "+";
183  break;
184 
186  op = "-";
187  break;
188 
190  return Fail; // handle cast to real
191 
193  op = "%";
194  break;
195 
197  op = "||";
198  break;
199 
201  return Fail; // handle cast to int
202 
204  op = "^";
205  break;
206 
208  op = "~";
209  break;
210  }
211 
212  if ( op.isNull() )
213  return Fail;
214 
215  QString left;
216  Result lr( compileNode( n->opLeft(), left ) );
217 
218  QString right;
219  Result rr( compileNode( n->opRight(), right ) );
220 
221  if ( failOnPartialNode && ( lr == Partial || rr == Partial ) )
222  return Fail;
223 
224  result = '(' + left + ' ' + op + ' ' + right + ')';
225  if ( lr == Complete && rr == Complete )
226  return ( partialCompilation ? Partial : Complete );
227  else if (( lr == Partial && rr == Complete ) || ( lr == Complete && rr == Partial ) || ( lr == Partial && rr == Partial ) )
228  return Partial;
229  else
230  return Fail;
231  }
232 
234  {
235  const QgsExpression::NodeLiteral* n = static_cast<const QgsExpression::NodeLiteral*>( node );
236  bool ok = false;
237  if ( mFlags.testFlag( CaseInsensitiveStringMatch ) && n->value().type() == QVariant::String )
238  {
239  // provider uses case insensitive matching, so if literal was a string then we only have a Partial compilation and need to
240  // double check results using QGIS' expression engine
241  result = quotedValue( n->value(), ok );
242  return ok ? Partial : Fail;
243  }
244  else
245  {
246  result = quotedValue( n->value(), ok );
247  return ok ? Complete : Fail;
248  }
249  }
250 
252  {
253  const QgsExpression::NodeColumnRef* n = static_cast<const QgsExpression::NodeColumnRef*>( node );
254 
255  if ( mFields.indexFromName( n->name() ) == -1 )
256  // Not a provider field
257  return Fail;
258 
259  result = quotedIdentifier( n->name() );
260 
261  return Complete;
262  }
263 
265  {
266  const QgsExpression::NodeInOperator* n = static_cast<const QgsExpression::NodeInOperator*>( node );
267  QStringList list;
268 
269  Result inResult = Complete;
270  Q_FOREACH ( const QgsExpression::Node* ln, n->list()->list() )
271  {
272  QString s;
273  Result r = compileNode( ln, s );
274  if ( r == Complete || r == Partial )
275  {
276  list << s;
277  if ( r == Partial )
278  inResult = Partial;
279  }
280  else
281  return r;
282  }
283 
284  QString nd;
285  Result rn = compileNode( n->node(), nd );
286  if ( rn != Complete && rn != Partial )
287  return rn;
288 
289  result = QString( "%1 %2IN(%3)" ).arg( nd, n->isNotIn() ? "NOT " : "", list.join( "," ) );
290  return ( inResult == Partial || rn == Partial ) ? Partial : Complete;
291  }
292 
295  break;
296  }
297 
298  return Fail;
299 }
Class for parsing and evaluation of expressions (formerly called "search strings").
virtual NodeType nodeType() const =0
Abstract virtual that returns the type of this node.
QString & append(QChar ch)
Provider treats LIKE as case-insensitive.
QString & prepend(QChar ch)
virtual Result compile(const QgsExpression *exp)
Compiles an expression and returns the result of the compilation.
Container of fields for a vector layer.
Definition: qgsfield.h:187
NodeList * list() const
QString join(const QString &separator) const
QVariant value() const
The value of the literal.
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
bool isNull() const
QgsSqlExpressionCompiler(const QgsFields &fields, const Flags &flags=Flags())
Constructor for expression compiler.
bool isNull() const
virtual QString quotedValue(const QVariant &value, bool &ok)
Returns a quoted attribute value, in the format expected by the provider.
QString name() const
The name of the column.
virtual QString result()
Returns the compiled expression string for use by the provider.
int indexFromName(const QString &name) const
Look up field&#39;s index from name. Returns -1 on error.
Definition: qgsfield.cpp:424
BinaryOperator op() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QString & replace(int position, int n, QChar after)
Result
Possible results from expression compilation.
Provider performs case-insensitive string matching for all strings.
virtual QString quotedIdentifier(const QString &identifier)
Returns a quoted column identifier, in the format expected by the provider.
bool toBool() const
virtual Result compileNode(const QgsExpression::Node *node, QString &str)
Compiles an expression node and returns the result of the compilation.
UnaryOperator op() const
Type type() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QList< Node * > list()