1 #include "selectresolver.h"
2 #include "parser/token.h"
3 #include "parser/lexer.h"
4 #include "parser/keywords.h"
5 #include "schemaresolver.h"
6 #include "parser/ast/sqlitecreateview.h"
7 #include "common/global.h"
8 #include <QDebug>
9 #include <QHash>
10 #include <QHashIterator>
11 #include <QString>
12
SelectResolver(Db * db,const QString & originalQuery)13 SelectResolver::SelectResolver(Db *db, const QString& originalQuery)
14 {
15 this->db = db;
16 this->query = originalQuery;
17 schemaResolver = new SchemaResolver(db);
18 }
19
SelectResolver(Db * db,const QString & originalQuery,const BiStrHash & dbNameToAttach)20 SelectResolver::SelectResolver(Db* db, const QString& originalQuery, const BiStrHash& dbNameToAttach) :
21 SelectResolver(db, originalQuery)
22 {
23 this->dbNameToAttach = dbNameToAttach;
24 }
25
~SelectResolver()26 SelectResolver::~SelectResolver()
27 {
28 safe_delete(schemaResolver);
29 }
30
resolveColumnsFromFirstCore()31 QList<SelectResolver::Column> SelectResolver::resolveColumnsFromFirstCore()
32 {
33 if (!parseOriginalQuery())
34 return QList<SelectResolver::Column>();
35
36 return resolve(originalQueryParsed->coreSelects.first());
37 }
38
resolveColumns()39 QList<QList<SelectResolver::Column>> SelectResolver::resolveColumns()
40 {
41 if (!parseOriginalQuery())
42 return QList<QList<SelectResolver::Column>>();
43
44 return resolve(originalQueryParsed.data());
45 }
46
resolve(SqliteSelect::Core * selectCore)47 QList<SelectResolver::Column> SelectResolver::resolve(SqliteSelect::Core *selectCore)
48 {
49 errors.clear();
50 extractCte(selectCore);
51 return resolveCore(selectCore);
52 }
53
resolve(SqliteSelect * select)54 QList<QList<SelectResolver::Column>> SelectResolver::resolve(SqliteSelect *select)
55 {
56 errors.clear();
57 extractCte(select);
58 QList<QList<SelectResolver::Column> > results;
59 for (SqliteSelect::Core* core : select->coreSelects)
60 {
61 results << resolveCore(core);
62 currentCoreResults.clear();
63 }
64
65 return results;
66 }
67
resolveAvailableColumns(SqliteSelect::Core * selectCore)68 QList<SelectResolver::Column> SelectResolver::resolveAvailableColumns(SqliteSelect::Core *selectCore)
69 {
70 errors.clear();
71 extractCte(selectCore);
72 return resolveAvailableCoreColumns(selectCore);
73 }
74
resolveAvailableColumns(SqliteSelect * select)75 QList<QList<SelectResolver::Column> > SelectResolver::resolveAvailableColumns(SqliteSelect *select)
76 {
77 errors.clear();
78 extractCte(select);
79 QList<QList<SelectResolver::Column> > results;
80 for (SqliteSelect::Core* core : select->coreSelects)
81 results << resolveAvailableCoreColumns(core);
82
83 return results;
84 }
85
resolveTables(SqliteSelect::Core * selectCore)86 QSet<SelectResolver::Table> SelectResolver::resolveTables(SqliteSelect::Core *selectCore)
87 {
88 QSet<Table> tables;
89 extractCte(selectCore);
90 QList<Column> columns = resolveAvailableColumns(selectCore);
91 for (const Column& col : columns)
92 {
93 if (col.type != Column::Type::COLUMN)
94 continue;
95
96 tables << col.getTable();
97 }
98
99 return tables;
100 }
101
resolveTables(SqliteSelect * select)102 QList<QSet<SelectResolver::Table> > SelectResolver::resolveTables(SqliteSelect *select)
103 {
104 QList<QSet<Table> > results;
105 extractCte(select);
106 QList<QList<Column> > columnLists = resolveAvailableColumns(select);
107 for (const QList<Column>& columns : columnLists)
108 {
109 QSet<Table> tables;
110 for (const Column& col : columns)
111 {
112 if (col.type != Column::Type::COLUMN)
113 continue;
114
115 tables << col.getTable();
116 }
117
118 results << tables;
119 }
120
121 return results;
122 }
123
translateToColumns(SqliteSelect * select,const TokenList & columnTokens)124 QList<SelectResolver::Column> SelectResolver::translateToColumns(SqliteSelect* select, const TokenList& columnTokens)
125 {
126 errors.clear();
127 extractCte(select);
128 QList<SelectResolver::Column> results;
129 for (const TokenPtr& token : columnTokens)
130 results << translateTokenToColumn(select, token);
131
132 return results;
133 }
134
translateToColumns(SqliteSelect * select,TokenPtr token)135 SelectResolver::Column SelectResolver::translateToColumns(SqliteSelect* select, TokenPtr token)
136 {
137 errors.clear();
138 return translateTokenToColumn(select, token);
139 }
140
hasErrors() const141 bool SelectResolver::hasErrors() const
142 {
143 return !errors.isEmpty();
144 }
145
getErrors() const146 const QStringList& SelectResolver::getErrors() const
147 {
148 return errors;
149 }
150
resolveCore(SqliteSelect::Core * selectCore)151 QList<SelectResolver::Column> SelectResolver::resolveCore(SqliteSelect::Core* selectCore)
152 {
153 if (selectCore->from)
154 currentCoreSourceColumns = resolveJoinSource(selectCore->from);
155
156 for (SqliteSelect::Core::ResultColumn* resCol : selectCore->resultColumns)
157 resolve(resCol);
158
159 if (selectCore->distinctKw)
160 markDistinctColumns();
161
162 if (selectCore->groupBy.size() > 0)
163 markGroupedColumns();
164
165 fixColumnNames();
166
167 SqliteSelect* select = dynamic_cast<SqliteSelect*>(selectCore->parentStatement());
168 if (select && select->coreSelects.size() > 1)
169 markCompoundColumns();
170
171 return currentCoreResults;
172 }
173
resolveAvailableCoreColumns(SqliteSelect::Core * selectCore)174 QList<SelectResolver::Column> SelectResolver::resolveAvailableCoreColumns(SqliteSelect::Core* selectCore)
175 {
176 QList<Column> columns;
177 if (selectCore->from)
178 columns = resolveJoinSource(selectCore->from);
179
180 return columns;
181 }
182
translateTokenToColumn(SqliteSelect * select,TokenPtr token)183 SelectResolver::Column SelectResolver::translateTokenToColumn(SqliteSelect* select, TokenPtr token)
184 {
185 // Default result
186 Column notTranslatedColumn;
187 notTranslatedColumn.type = Column::OTHER;
188 notTranslatedColumn.column = token->value;
189
190 // Find containing statement
191 SqliteStatement* parentStmt = select->findStatementWithToken(token);
192 if (!parentStmt)
193 {
194 qDebug() << "Could not find containing statement for given token while translating column token:" << token->toString()
195 << "Select tokens:" << select->tokens.toString();
196
197 return notTranslatedColumn;
198 }
199
200 // Go through all select cores, from the most deep, to the most shallow
201 SqliteSelect::Core* core = nullptr;
202 while (parentStmt)
203 {
204 // Find nearest SELECT core.
205 while (parentStmt && !(core = dynamic_cast<SqliteSelect::Core*>(parentStmt)))
206 parentStmt = parentStmt->parentStatement();
207
208 if (!core)
209 {
210 qDebug() << "Could not find SqliteSelect::Core object for given token while translating column token:" << token->toString()
211 << "Select:" << select->detokenize();
212
213 return notTranslatedColumn;
214 }
215
216 // Search through available columns
217 for (const Column& availableColumn : resolveAvailableColumns(core))
218 {
219 if (availableColumn.type == Column::COLUMN && availableColumn.column.compare(token->value, Qt::CaseInsensitive) == 0)
220 return availableColumn;
221 }
222
223 // Not in this core. See if there is any core upper (if this was a subselect).
224 parentStmt = parentStmt->parentStatement();
225 }
226
227 return notTranslatedColumn;
228 }
229
markDistinctColumns()230 void SelectResolver::markDistinctColumns()
231 {
232 markCurrentColumnsWithFlag(FROM_DISTINCT_SELECT);
233 }
234
markCompoundColumns()235 void SelectResolver::markCompoundColumns()
236 {
237 markCurrentColumnsWithFlag(FROM_COMPOUND_SELECT);
238 }
239
markGroupedColumns()240 void SelectResolver::markGroupedColumns()
241 {
242 markCurrentColumnsWithFlag(FROM_GROUPED_SELECT);
243 }
244
fixColumnNames()245 void SelectResolver::fixColumnNames()
246 {
247 QSet<QString> existingDisplayNames;
248 QSet<QString> existingAliasNames;
249 QString originalName;
250 QString originalAlias;
251 QString alias;
252 int i;
253
254 QMutableListIterator<Column> it(currentCoreResults);
255 while (it.hasNext())
256 {
257 // Display name
258 originalName = it.next().displayName;
259 for (i = 1; existingDisplayNames.contains(it.value().displayName); i++)
260 it.value().displayName = originalName + ":" + QString::number(i);
261
262 existingDisplayNames << it.value().displayName;
263
264 // Alias
265 // Handled both alias duplicates and name duplicates.
266 // If name is duplicated, also create alias for it.
267 // This is important, because in case of duplicated name/alias, the result column is actually
268 // made unique with sequenced number - not only for display, but also for data origin.
269 alias = it.value().alias.isNull() ? it.value().column : it.value().alias;
270 originalAlias = alias;
271 for (i = 1; existingAliasNames.contains(alias); i++)
272 alias = originalAlias + ":" + QString::number(i);
273
274 if (alias != originalAlias)
275 it.value().alias = alias;
276
277 existingAliasNames << alias;
278 }
279 }
280
markCurrentColumnsWithFlag(SelectResolver::Flag flag,QList<Column> * columnList)281 void SelectResolver::markCurrentColumnsWithFlag(SelectResolver::Flag flag, QList<Column>* columnList)
282 {
283 QMutableListIterator<Column> it(columnList ? *columnList : currentCoreResults);
284 while (it.hasNext())
285 it.next().flags |= flag;
286 }
287
resolve(SqliteSelect::Core::ResultColumn * resCol)288 void SelectResolver::resolve(SqliteSelect::Core::ResultColumn *resCol)
289 {
290 if (resCol->star)
291 resolveStar(resCol);
292 else
293 resolveExpr(resCol);
294 }
295
resolveStar(SqliteSelect::Core::ResultColumn * resCol)296 void SelectResolver::resolveStar(SqliteSelect::Core::ResultColumn *resCol)
297 {
298 bool foundAtLeastOne = false;
299 for (SelectResolver::Column column : currentCoreSourceColumns)
300 {
301 if (!resCol->table.isNull())
302 {
303 /*
304 * Star was prefixed with table or table alias.
305 * The "FROM" clause allows to use alias name the same as
306 * some other table real name in the very same "FROM".
307 * Their columns concatenate, so here we allow any column that
308 * prefix matches either alias or table from data source list.
309 * For example it's correct to query:
310 * SELECT test.* FROM test, otherTable AS test;
311 * This case is simpler then in resolveDbAndTable(),
312 * because here's no database allowed.
313 *
314 * Also, if the table has an alias specified,
315 * then the alias has a precedence before table's name,
316 * therefore we match table name only if the table alias
317 * is null.
318 */
319 if (
320 (
321 !column.tableAlias.isNull() &&
322 resCol->table.compare(column.tableAlias, Qt::CaseInsensitive) != 0
323 ) ||
324 (
325 column.tableAlias.isNull() &&
326 resCol->table.compare(column.table, Qt::CaseInsensitive) != 0
327 )
328
329 )
330 {
331 continue;
332 }
333 }
334
335 // If source column name is aliased, use it
336 if (!column.alias.isNull())
337 column.displayName = column.alias;
338 else
339 column.displayName = column.column;
340
341 column.originalColumn = resCol;
342 currentCoreResults << column;
343 foundAtLeastOne = true;
344 }
345
346 if (!foundAtLeastOne)
347 errors << QObject::tr("Could not resolve data source for column: %1").arg(resCol->detokenize());
348 }
349
resolveExpr(SqliteSelect::Core::ResultColumn * resCol)350 void SelectResolver::resolveExpr(SqliteSelect::Core::ResultColumn *resCol)
351 {
352 SqliteExpr* expr = resCol->expr;
353 if (expr->mode != SqliteExpr::Mode::ID)
354 {
355 // Not a simple column, but some expression
356 SelectResolver::Column column;
357 column.alias = resCol->alias;
358 column.originalColumn = resCol;
359 column.column = getResColTokensWithoutAlias(resCol).detokenize().trimmed();
360 column.displayName = !resCol->alias.isNull() ? column.alias : column.column;
361
362 column.type = Column::OTHER;
363 currentCoreResults << column;
364
365 // In this case we end it here.
366 return;
367 }
368
369 // Now we know we're dealing with db.table.column (with db and table optional)
370 resolveDbAndTable(resCol);
371 }
372
resolveDbAndTable(SqliteSelect::Core::ResultColumn * resCol)373 void SelectResolver::resolveDbAndTable(SqliteSelect::Core::ResultColumn *resCol)
374 {
375 SqliteExpr* expr = resCol->expr;
376
377 // Basic info
378 Column col;
379 col.alias = resCol->alias;
380 col.column = expr->column;
381 col.originalColumn = resCol;
382 col.type = Column::COLUMN;
383
384 // Display name
385 if (col.alias.isNull())
386 col.displayName = expr->column;
387 else
388 col.displayName = col.alias;
389
390 // Looking for table relation
391 Column matched;
392 if (isRowIdKeyword(expr->column))
393 matched = resolveRowIdColumn(expr);
394 else if (!expr->database.isNull())
395 matched = resolveExplicitColumn(expr->database, expr->table, expr->column);
396 else if (!expr->table.isNull())
397 matched = resolveExplicitColumn(expr->table, expr->column);
398 else
399 matched = resolveExplicitColumn(expr->column);
400
401
402 if (!matched.table.isNull())
403 {
404 col.database = matched.database;
405 col.originalDatabase = resolveDatabase(matched.database);
406 col.table = matched.table;
407 col.tableAlias = matched.tableAlias;
408 col.flags = matched.flags;
409 }
410 else if (matched.type == Column::OTHER)
411 {
412 col.type = Column::OTHER;
413 }
414 else if (!ignoreInvalidNames)
415 {
416 QString colStr = expr->detokenize();
417 qDebug() << "Source table for column '" << colStr
418 << "' not matched while resolving select: " << query;
419 errors << QObject::tr("Could not resolve table for column '%1'.").arg(colStr);
420 }
421
422 currentCoreResults << col;
423 }
424
resolveRowIdColumn(SqliteExpr * expr)425 SelectResolver::Column SelectResolver::resolveRowIdColumn(SqliteExpr *expr)
426 {
427 // Looking for first source that can provide ROWID.
428 for (const Column& column : currentCoreSourceColumns)
429 {
430 if (column.table.isNull())
431 continue; // ROWID cannot be related to source with no table
432
433 if (!expr->table.isNull() && matchTable(column, expr->table))
434 return column;
435 }
436 return Column();
437 }
438
resolveExplicitColumn(const QString & columnName)439 SelectResolver::Column SelectResolver::resolveExplicitColumn(const QString &columnName)
440 {
441 for (const Column& column : currentCoreSourceColumns)
442 {
443 if (columnName.compare(column.column, Qt::CaseInsensitive) != 0 && columnName.compare(column.alias, Qt::CaseInsensitive) != 0)
444 continue;
445
446 return column;
447 }
448 return Column();
449 }
450
resolveExplicitColumn(const QString & table,const QString & columnName)451 SelectResolver::Column SelectResolver::resolveExplicitColumn(const QString &table, const QString &columnName)
452 {
453 for (const Column& column : currentCoreSourceColumns)
454 {
455 if (columnName.compare(column.column, Qt::CaseInsensitive) != 0 && columnName.compare(column.alias, Qt::CaseInsensitive) != 0)
456 continue;
457
458 if (!matchTable(column, table))
459 continue;
460
461 return column;
462 }
463 return Column();
464 }
465
resolveExplicitColumn(const QString & database,const QString & table,const QString & columnName)466 SelectResolver::Column SelectResolver::resolveExplicitColumn(const QString &database, const QString &table, const QString &columnName)
467 {
468 for (const Column& column : currentCoreSourceColumns)
469 {
470 if (columnName.compare(column.column, Qt::CaseInsensitive) != 0 && columnName.compare(column.alias, Qt::CaseInsensitive) != 0)
471 continue;
472
473 if (!matchTable(column, table))
474 continue;
475
476 if (database.compare(column.database, Qt::CaseInsensitive) != 0)
477 continue;
478
479 return column;
480 }
481 return Column();
482 }
483
matchTable(const SelectResolver::Column & sourceColumn,const QString & table)484 bool SelectResolver::matchTable(const SelectResolver::Column &sourceColumn, const QString &table)
485 {
486 // First check by tableAlias if it's present
487 if (!sourceColumn.tableAlias.isNull())
488 return (sourceColumn.tableAlias.compare(table, Qt::CaseInsensitive) == 0);
489
490 return (sourceColumn.table.compare(table, Qt::CaseInsensitive) == 0);
491 }
492
getResColTokensWithoutAlias(SqliteSelect::Core::ResultColumn * resCol)493 TokenList SelectResolver::getResColTokensWithoutAlias(SqliteSelect::Core::ResultColumn *resCol)
494 {
495 TokenList allTokens = resCol->tokens;
496 if (!resCol->alias.isNull())
497 {
498 int depth = 0;
499 int idx = -1;
500 int idxCandidate = -1;
501 for (const TokenPtr& token : allTokens)
502 {
503 idxCandidate++;
504 if (token->type == Token::PAR_LEFT)
505 {
506 depth++;
507 }
508 else if (token->type == Token::PAR_RIGHT)
509 {
510 depth--;
511 }
512 else if (token->type == Token::KEYWORD && token->value.compare("AS", Qt::CaseInsensitive) == 0 && depth <= 0)
513 {
514 idx = idxCandidate;
515 break;
516 }
517 }
518
519 if (idx > -1)
520 allTokens = allTokens.mid(0, idx - 1);
521 }
522
523 return allTokens;
524 }
525
extractCte(SqliteSelect * select)526 void SelectResolver::extractCte(SqliteSelect *select)
527 {
528 cteList.clear();
529 if (!select->with)
530 return;
531
532 for (SqliteWith::CommonTableExpression* cte : select->with->cteList)
533 cteList[cte->table] = cte;
534 }
535
extractCte(SqliteSelect::Core * core)536 void SelectResolver::extractCte(SqliteSelect::Core *core)
537 {
538 if (!core->parentStatement())
539 return;
540
541 extractCte(dynamic_cast<SqliteSelect*>(core->parentStatement()));
542 }
543
resolveJoinSource(SqliteSelect::Core::JoinSource * joinSrc)544 QList<SelectResolver::Column> SelectResolver::resolveJoinSource(SqliteSelect::Core::JoinSource *joinSrc)
545 {
546 QList<SelectResolver::Column> columnSources;
547 columnSources += resolveSingleSource(joinSrc->singleSource);
548 for (SqliteSelect::Core::JoinSourceOther* otherSrc : joinSrc->otherSources)
549 columnSources += resolveOtherSource(otherSrc);
550
551 return columnSources;
552 }
553
resolveSingleSource(SqliteSelect::Core::SingleSource * joinSrc)554 QList<SelectResolver::Column> SelectResolver::resolveSingleSource(SqliteSelect::Core::SingleSource *joinSrc)
555 {
556 if (!joinSrc)
557 return QList<Column>();
558
559 if (joinSrc->select)
560 return resolveSingleSourceSubSelect(joinSrc);
561
562 if (joinSrc->joinSource)
563 return resolveJoinSource(joinSrc->joinSource);
564
565 if (!joinSrc->funcName.isNull())
566 return resolveTableFunctionColumns(joinSrc);
567
568 if (isView(joinSrc->database, joinSrc->table))
569 return resolveView(joinSrc->database, joinSrc->table, joinSrc->alias);
570
571 if (joinSrc->database.isNull() && cteList.contains(joinSrc->table))
572 return resolveCteColumns(joinSrc);
573
574 QList<Column> columnSources;
575 QStringList columns = getTableColumns(joinSrc->database, joinSrc->table, joinSrc->alias);
576 Column column;
577 column.type = Column::COLUMN;
578 column.table = joinSrc->table;;
579 column.database = joinSrc->database;
580 column.originalDatabase = resolveDatabase(joinSrc->database);
581 if (!joinSrc->alias.isNull())
582 column.tableAlias = joinSrc->alias;
583
584 for (const QString& columnName : columns)
585 {
586 column.column = columnName;
587 columnSources << column;
588 }
589
590 return columnSources;
591 }
592
resolveCteColumns(SqliteSelect::Core::SingleSource * joinSrc)593 QList<SelectResolver::Column> SelectResolver::resolveCteColumns(SqliteSelect::Core::SingleSource* joinSrc)
594 {
595 SqliteWith::CommonTableExpression* cte = cteList[joinSrc->table];
596
597 Column column;
598 column.type = Column::COLUMN;
599 column.flags |= FROM_CTE_SELECT;
600 column.tableAlias = cte->table;
601
602 QList<Column> columnSources;
603
604 static_qstring(cteSelectTpl, "WITH %1 SELECT * FROM %2");
605 QString selectQuery = cte->detokenize();
606 QString query = cteSelectTpl.arg(selectQuery, cte->table);
607 QList<AliasedColumn> queryColumns = db->columnsForQuery(query);
608 if (queryColumns.isEmpty())
609 {
610 qWarning() << "Could not detect query columns. Probably due to db error:" << db->getErrorText();
611 return columnSources;
612 }
613
614 for (const AliasedColumn& queryColumn : queryColumns)
615 {
616 if (!queryColumn.getDatabase().isNull())
617 column.database = resolveDatabase(queryColumn.getDatabase());
618 else
619 column.database = queryColumn.getDatabase();
620
621 column.table = queryColumn.getTable();
622
623 // From CTE perspective, however the column is received as "result column name" from SQLite API
624 // is what we report back to user of the CTE as available column. No matter if it's actual alias,
625 // or simply name of a column.
626 column.column = queryColumn.getAlias();
627 column.displayName = queryColumn.getAlias();
628 columnSources << column;
629 }
630
631 return columnSources;
632 }
633
resolveTableFunctionColumns(SqliteSelect::Core::SingleSource * joinSrc)634 QList<SelectResolver::Column> SelectResolver::resolveTableFunctionColumns(SqliteSelect::Core::SingleSource *joinSrc)
635 {
636 static_qstring(columnSqlTpl, "SELECT * FROM %1 LIMIT 0");
637 SqlQueryPtr result = db->exec(columnSqlTpl.arg(joinSrc->detokenize()));
638 if (result->isError())
639 errors << result->getErrorText();
640
641 QStringList columnNames = result->getColumnNames();
642
643 QList<Column> columnSources;
644 Column column;
645 column.type = Column::OTHER;
646 column.database = joinSrc->database;
647 column.originalDatabase = resolveDatabase(joinSrc->database);
648 if (!joinSrc->alias.isNull())
649 column.tableAlias = joinSrc->alias;
650
651 for (const QString& columnName : columnNames)
652 {
653 column.column = columnName;
654 columnSources << column;
655 }
656 return columnSources;
657 }
658
resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource * joinSrc)659 QList<SelectResolver::Column> SelectResolver::resolveSingleSourceSubSelect(SqliteSelect::Core::SingleSource *joinSrc)
660 {
661 QList<Column> columnSources = resolveSubSelect(joinSrc->select);
662 applySubSelectAlias(columnSources, joinSrc->alias);
663
664 QMutableListIterator<Column> it(columnSources);
665 while (it.hasNext())
666 {
667 if (it.next().alias.isEmpty())
668 continue;
669
670 it.value().aliasDefinedInSubQuery = true;
671 }
672
673 return columnSources;
674 }
675
resolveOtherSource(SqliteSelect::Core::JoinSourceOther * otherSrc)676 QList<SelectResolver::Column> SelectResolver::resolveOtherSource(SqliteSelect::Core::JoinSourceOther *otherSrc)
677 {
678 return resolveSingleSource(otherSrc->singleSource);
679 }
680
resolveSubSelect(SqliteSelect * select)681 QList<SelectResolver::Column> SelectResolver::resolveSubSelect(SqliteSelect *select)
682 {
683 QList<Column> columnSources;
684 Q_ASSERT(select->coreSelects.size() > 0);
685
686 bool compound = (select->coreSelects.size() > 1);
687
688 if (compound && !resolveMultiCore)
689 return columnSources;
690
691 SelectResolver internalResolver(db, query);
692 columnSources += internalResolver.resolve(select->coreSelects[0]);
693
694 if (compound)
695 {
696 QMutableListIterator<Column> it(columnSources);
697 while (it.hasNext())
698 it.next().flags |= FROM_COMPOUND_SELECT;
699 }
700
701 return columnSources;
702 }
703
resolveView(const QString & database,const QString & name,const QString & alias)704 QList<SelectResolver::Column> SelectResolver::resolveView(const QString& database, const QString& name, const QString& alias)
705 {
706 QList<Column> results;
707 SqliteQueryPtr query = schemaResolver->getParsedObject(database, name, SchemaResolver::VIEW);
708 if (!query)
709 {
710 qDebug() << "Could not get parsed CREATE VIEW in SelectResolver::resolveView().";
711 return results;
712 }
713
714 SqliteCreateViewPtr createView = query.dynamicCast<SqliteCreateView>();
715 if (!createView)
716 {
717 qDebug() << "Parsed object not a CREATE VIEW as expected, but instead it's:" << sqliteQueryTypeToString(query->queryType);
718 return results;
719 }
720
721 results = resolveSubSelect(createView->select);
722 applySubSelectAlias(results, (!alias.isNull() ? alias : name));
723
724 return results;
725 }
726
isView(const QString & database,const QString & name)727 bool SelectResolver::isView(const QString& database, const QString& name)
728 {
729 return schemaResolver->getViews(database).contains(name, Qt::CaseInsensitive);
730 }
731
getTableColumns(const QString & database,const QString & table,const QString & alias)732 QStringList SelectResolver::getTableColumns(const QString &database, const QString &table, const QString& alias)
733 {
734 Table dbTable;
735 dbTable.database = database;
736 dbTable.table = table;
737 dbTable.tableAlias = alias;
738
739 if (tableColumnsCache.contains(dbTable))
740 {
741 return tableColumnsCache.value(dbTable);
742 }
743 else
744 {
745 QStringList columns = schemaResolver->getTableColumns(database, table);
746 tableColumnsCache[dbTable] = columns;
747 return columns;
748 }
749 }
750
applySubSelectAlias(QList<SelectResolver::Column> & columns,const QString & alias)751 void SelectResolver::applySubSelectAlias(QList<SelectResolver::Column>& columns, const QString& alias)
752 {
753 // If this subselect is aliased, then all source columns should be considered as from aliased table
754 QMutableListIterator<Column> it(columns);
755 if (!alias.isNull())
756 {
757 while (it.hasNext())
758 {
759 it.next().pushTableAlias();
760 it.value().tableAlias = alias;
761 it.value().flags &= ~FROM_ANONYMOUS_SELECT; // remove anonymous flag
762 }
763 }
764 else
765 {
766 // Otherwise, mark column as being from anonymous subselect.
767 // This is used by QueryExecutorColumns step to avoid prefixing result column with table
768 // when it comes from anonymous subselect (which SQLite needs this to be not prefixed column).
769 while (it.hasNext())
770 it.next().flags |= FROM_ANONYMOUS_SELECT;
771 }
772 }
773
resolveDatabase(const QString & database)774 QString SelectResolver::resolveDatabase(const QString& database)
775 {
776 if (dbNameToAttach.containsRight(database, Qt::CaseInsensitive))
777 return dbNameToAttach.valueByRight(database, Qt::CaseInsensitive);
778
779 return database;
780 }
781
parseOriginalQuery()782 bool SelectResolver::parseOriginalQuery()
783 {
784 if (originalQueryParsed)
785 return true;
786
787 Parser parser;
788 if (!parser.parse(query) || parser.getQueries().isEmpty())
789 {
790 qWarning() << "Could not parse query in SelectResolver:" << query;
791 return false;
792 }
793
794 SqliteQueryPtr theQuery = parser.getQueries().first();
795 if (theQuery.dynamicCast<SqliteSelect>().isNull())
796 {
797 qWarning() << "Parsed query is not SELECT as expected in SelectResolver::parseOriginalQuery():" << query;
798 return false;
799 }
800
801 originalQueryParsed = theQuery.dynamicCast<SqliteSelect>();
802 return true;
803 }
804
Table()805 SelectResolver::Table::Table()
806 {
807 }
808
Table(const SelectResolver::Table & other)809 SelectResolver::Table::Table(const SelectResolver::Table &other) :
810 database(other.database), originalDatabase(other.originalDatabase), table(other.table),
811 tableAlias(other.tableAlias), oldTableAliases(other.oldTableAliases), flags(other.flags)
812 {
813 }
814
operator ==(const SelectResolver::Table & other)815 int SelectResolver::Table::operator ==(const SelectResolver::Table &other)
816 {
817 return ::operator==(*this, other);
818 }
819
pushTableAlias()820 void SelectResolver::Table::pushTableAlias()
821 {
822 if (!tableAlias.isNull())
823 oldTableAliases += tableAlias;
824 }
825
operator ==(const SelectResolver::Table & t1,const SelectResolver::Table & t2)826 int operator==(const SelectResolver::Table& t1, const SelectResolver::Table& t2)
827 {
828 return t1.table.compare(t2.table, Qt::CaseInsensitive) == 0 &&
829 t1.database.compare(t2.database, Qt::CaseInsensitive) == 0 &&
830 t1.tableAlias.compare(t2.tableAlias, Qt::CaseInsensitive) == 0 &&
831 t1.oldTableAliases.size() == t2.oldTableAliases.size() &&
832 t1.oldTableAliases.join(",").compare(t2.oldTableAliases.join(","), Qt::CaseInsensitive) == 0;
833 }
834
qHash(const SelectResolver::Table & table)835 uint qHash(const SelectResolver::Table& table)
836 {
837 return qHash(table.database.toLower() + "." + table.table.toLower() + "/" + table.tableAlias.toLower() + "/" +
838 table.oldTableAliases.join(","));
839 }
840
operator ==(const SelectResolver::Column & other)841 int SelectResolver::Column::operator ==(const SelectResolver::Column &other)
842 {
843 return ::operator==(*this, other);
844 }
845
getTable() const846 SelectResolver::Table SelectResolver::Column::getTable() const
847 {
848 return Table(*this);
849 }
850
operator ==(const SelectResolver::Column & c1,const SelectResolver::Column & c2)851 int operator ==(const SelectResolver::Column &c1, const SelectResolver::Column &c2)
852 {
853 return c1.column.compare(c2.column, Qt::CaseInsensitive) == 0 &&
854 c1.table.compare(c2.table, Qt::CaseInsensitive) == 0 &&
855 c1.database.compare(c2.database, Qt::CaseInsensitive) == 0 &&
856 c1.tableAlias.compare(c2.tableAlias, Qt::CaseInsensitive) == 0 &&
857 c1.oldTableAliases.size() == c2.oldTableAliases.size() &&
858 c1.oldTableAliases.join(",").compare(c2.oldTableAliases.join(","), Qt::CaseInsensitive) == 0;
859 }
860
qHash(const SelectResolver::Column & column)861 uint qHash(const SelectResolver::Column &column)
862 {
863 return qHash(column.database.toLower() + "." + column.table.toLower() + "." + column.column.toLower() + "/" +
864 column.tableAlias.toLower() + "/" + column.oldTableAliases.join(","));
865 }
866