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