KDb

KDbVariableExpression.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003-2012 Jarosław Staniek <[email protected]>
3 
4  Based on nexp.cpp : Parser module of Python-like language
5  (C) 2001 Jarosław Staniek, MIMUW (www.mimuw.edu.pl)
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Library General Public License for more details.
16 
17  You should have received a copy of the GNU Library General Public License
18  along with this library; see the file COPYING.LIB. If not, write to
19  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include "KDbExpression.h"
24 #include "KDb.h"
25 #include "KDbDriver.h"
26 #include "KDbQuerySchema.h"
27 #include "KDbParser_p.h"
28 #include "kdb_debug.h"
29 
30 KDbVariableExpressionData::KDbVariableExpressionData()
32  , field(nullptr)
33  , tablePositionForField(-1)
34  , tableForQueryAsterisk(nullptr)
35 {
36  ExpressionDebug << "VariableExpressionData" << ref;
37 }
38 
39 KDbVariableExpressionData::KDbVariableExpressionData(const QString& aName)
41  , name(aName)
42  , field(nullptr)
43  , tablePositionForField(-1)
44  , tableForQueryAsterisk(nullptr)
45 {
46  ExpressionDebug << "VariableExpressionData" << ref;
47 }
48 
49 KDbVariableExpressionData::~KDbVariableExpressionData()
50 {
51  ExpressionDebug << "~VariableExpressionData" << ref;
52 }
53 
54 KDbVariableExpressionData* KDbVariableExpressionData::clone()
55 {
56  ExpressionDebug << "VariableExpressionData::clone" << *this;
57  return new KDbVariableExpressionData(*this);
58 }
59 
61 {
62  Q_UNUSED(callStack);
63  dbg.nospace() << qPrintable(QString::fromLatin1("VariableExp(\"%1\",type=%2)")
65  : QLatin1String("FIELD_NOT_DEFINED_YET")));
66 }
67 
68 KDbEscapedString KDbVariableExpressionData::toStringInternal(
69  const KDbDriver *driver,
71  KDb::ExpressionCallStack* callStack) const
72 {
73  Q_UNUSED(driver);
74  Q_UNUSED(params);
75  Q_UNUSED(callStack);
76  return KDbEscapedString(name);
77 }
78 
79 void KDbVariableExpressionData::getQueryParameters(QList<KDbQuerySchemaParameter>* params)
80 {
81  Q_UNUSED(params);
82 }
83 
84 //! We're assuming it's called after VariableExpr::validate()
86 {
87  Q_UNUSED(callStack);
88  if (field)
89  return field->type();
90 
91  //BTW, asterisks are not stored in VariableExpr outside of parser, so ok.
92  return KDbField::InvalidType;
93 }
94 
95 static void validateImplError(KDbParseInfo *parseInfo_, const QString &errmsg)
96 {
97  KDbParseInfoInternal *parseInfo = static_cast<KDbParseInfoInternal*>(parseInfo_);
98  parseInfo->setErrorMessage(QLatin1String("Implementation error"));
99  parseInfo->setErrorDescription(errmsg);
100 }
101 
103 {
104  Q_UNUSED(callStack);
105  KDbParseInfoInternal *parseInfo = static_cast<KDbParseInfoInternal*>(parseInfo_);
106  field = nullptr;
108  tableForQueryAsterisk = nullptr;
109 
110  /* taken from parser's addColumn(): */
111  kdbDebug() << "checking variable name: " << name;
112  QString tableName, fieldName;
113  if (!KDb::splitToTableAndFieldParts(name, &tableName, &fieldName,
115  {
116  return false;
117  }
118  //! @todo shall we also support db name?
119  if (tableName.isEmpty()) {//fieldname only
120  if (fieldName == QLatin1String("*")) {
121  return true;
122  }
123 
124  //find first table that has this field
125  KDbField *firstField = nullptr;
126  foreach(KDbTableSchema *table, *parseInfo->querySchema()->tables()) {
127  KDbField *f = table->field(fieldName);
128  if (f) {
129  if (!firstField) {
130  firstField = f;
131  } else if (f->table() != firstField->table()) {
132  //ambiguous field name
133  parseInfo->setErrorMessage(tr("Ambiguous field name"));
134  parseInfo->setErrorDescription(
135  tr("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
136  "Use \"<tableName>.%4\" notation to specify table name.",
137  "Note: translate also <tableName>")
138  .arg(firstField->table()->name(), f->table()->name(),
139  fieldName, fieldName));
140  return false;
141  }
142  }
143  }
144  if (!firstField) {
145  parseInfo->setErrorMessage(tr("Field not found"));
146  parseInfo->setErrorDescription(
147  tr("Could not find table containing field \"%1\".").arg(fieldName));
148  return false;
149  }
150  //ok
151  field = firstField; //store
152  return true;
153  }
154 
155  //table.fieldname or tableAlias.fieldname
156  KDbTableSchema *ts = parseInfo->querySchema()->table(tableName);
157  int tablePosition = -1;
158  if (ts) {//table.fieldname
159  //check if "table" is covered by an alias
160  const QList<int> tPositions = parseInfo->querySchema()->tablePositions(tableName);
161  QString tableAlias;
162  bool covered = true;
163  foreach(int position, tPositions) {
164  tableAlias = parseInfo->querySchema()->tableAlias(position);
165  if (tableAlias.isEmpty() || tableAlias.toLower() == tableName) {
166  covered = false; //uncovered
167  break;
168  }
169  kdbDebug() << " --" << "covered by " << tableAlias << " alias";
170  }
171  if (covered) {
172  parseInfo->setErrorMessage(tr("Could not access the table directly using its name"));
173  parseInfo->setErrorDescription(
174  tr("Table name \"%1\" is covered by aliases. "
175  "Instead of \"%2\", \"%3\" can be used.")
176  .arg(tableName,
177  tableName + QLatin1Char('.') + fieldName,
178  tableAlias + QLatin1Char('.') + fieldName));
179  return false;
180  }
181  if (!tPositions.isEmpty()) {
182  tablePosition = tPositions.first();
183  }
184  }
185  else {//try to find tableAlias
186  tablePosition = parseInfo->querySchema()->tablePositionForAlias(tableName);
187  if (tablePosition >= 0) {
188  ts = parseInfo->querySchema()->tables()->at(tablePosition);
189  if (ts) {
190 // kdbDebug() << " --it's a tableAlias.name";
191  }
192  }
193  }
194 
195  if (!ts) {
196  parseInfo->setErrorMessage(tr("Table not found"));
197  parseInfo->setErrorDescription(tr("Unknown table \"%1\".").arg(tableName));
198  return false;
199  }
200 
201  const QList<int> positionsList(parseInfo->tablesAndAliasesForName(tableName));
202  if (positionsList.isEmpty()) { //for sanity
203  validateImplError(parseInfo,
204  QString::fromLatin1("%1.%2, !positionsList ").arg(tableName, fieldName));
205  return false;
206  }
207 
208  //it's a table.*
209  if (fieldName == QLatin1String("*")) {
210  if (positionsList.count() > 1) {
211  parseInfo->setErrorMessage(tr("Ambiguous \"%1.*\" expression").arg(tableName));
212  parseInfo->setErrorDescription(tr("More than one \"%1\" table or alias defined.").arg(tableName));
213  return false;
214  }
216  return true;
217  }
218 
219 // kdbDebug() << " --it's a table.name";
220  KDbField *realField = ts->field(fieldName);
221  if (!realField) {
222  parseInfo->setErrorMessage(tr("Field not found"));
223  parseInfo->setErrorDescription(
224  tr("Table \"%1\" has no \"%2\" field.").arg(tableName, fieldName));
225  return false;
226  }
227 
228  // check if table or alias is used twice and both have the same column
229  // (so the column is ambiguous)
230  if (positionsList.count() > 1) {
231  parseInfo->setErrorMessage(tr("Ambiguous \"%1.%2\" expression").arg(tableName, fieldName));
232  parseInfo->setErrorDescription(
233  tr("More than one \"%1\" table or alias defined containing \"%2\" field.")
234  .arg(tableName, fieldName));
235  return false;
236  }
237  field = realField; //store
238  tablePositionForField = tablePosition;
239  return true;
240 }
241 
242 //=========================================
243 
246 {
247  ExpressionDebug << "KDbVariableExpression() ctor" << *this;
248 }
249 
252  KDb::VariableExpression, KDbToken()/*undefined*/)
253 {
254 }
255 
257  : KDbExpression(expr)
258 {
259 }
260 
262  : KDbExpression(data)
263 {
264  ExpressionDebug << "KDbVariableExpression ctor (KDbExpressionData*)" << *this;
265 }
266 
268  : KDbExpression(ptr)
269 {
270 }
271 
272 KDbVariableExpression::~KDbVariableExpression()
273 {
274 }
275 
277 {
278  return d->convert<KDbVariableExpressionData>()->name;
279 }
280 
282 {
283  return d->convert<KDbVariableExpressionData>()->field;
284 }
285 
287 {
289 }
290 
292 {
294 }
T & first()
Internal data class used to implement implicitly shared class KDbExpression.
KDB_EXPORT bool splitToTableAndFieldParts(const QString &string, QString *tableName, QString *fieldName, SplitToTableAndFieldPartsOptions option=FailIfNoTableOrFieldName)
Definition: KDb.cpp:603
An iterator for a list of values of query schema parameters Allows to iterate over parameters and ret...
A type-safe KDbSQL token It can be used in KDb expressions.
Definition: KDbToken.h:36
@ InvalidType
Definition: KDbField.h:86
KDbTableSchema * table()
Definition: KDbField.cpp:585
int count(const T &value) const const
The KDbVariableExpression class represents variables such as fieldname or tablename....
virtual KDbField * field(int id)
void ref()
QDebug & nospace()
A database connectivity and creation framework.
KDbField::Type type() const
Specialized string for escaping.
QString name
KDbTableSchema * tableForQueryAsterisk() const
Database driver's abstraction.
Definition: KDbDriver.h:49
KDbField::Type typeInternal(KDb::ExpressionCallStack *callStack) const override
We're assuming it's called after VariableExpr::validate()
static QString defaultSqlTypeName(KDbField::Type type)
Definition: KDbDriver.cpp:164
bool isEmpty() const const
Internal data class used to implement implicitly shared class KDbVariableExpression.
void debugInternal(QDebug dbg, KDb::ExpressionCallStack *callStack) const override
Sends information about this expression to debug output dbg (internal).
ExplicitlySharedExpressionDataPointer d
bool isEmpty() const const
@ SetFieldNameIfNoTableName
see splitToTableAndFieldParts()
Definition: KDb.h:248
Type type() const
Definition: KDbField.cpp:379
QString toLower() const const
bool validateInternal(KDbParseInfo *parseInfo, KDb::ExpressionCallStack *callStack) override
KDbTableSchema * tableForQueryAsterisk
QString fromLatin1(const char *str, int size)
QString name(StandardShortcut id)
Meta-data for a field.
Definition: KDbField.h:71
The KDbExpression class represents a base class for all expressions.
Definition: KDbExpression.h:51
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:21:34 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.