#ifndef SCHEMARESOLVER_H #define SCHEMARESOLVER_H #include "parser/parser.h" #include "parser/ast/sqlitequerytype.h" #include "parser/ast/sqlitecreatetable.h" #include "parser/ast/sqlitecreateindex.h" #include "parser/ast/sqlitecreateview.h" #include "parser/ast/sqlitecreatetrigger.h" #include "coreSQLiteStudio_global.h" #include "common/utils_sql.h" #include "selectresolver.h" #include "db/sqlresultsrow.h" #include "db/sqlquery.h" #include "db/db.h" #include "common/strhash.h" #include class SqliteCreateTable; // TODO add cache class API_EXPORT SchemaResolver { public: enum ObjectType { TABLE, INDEX, TRIGGER, VIEW, ANY }; struct ObjectDetails { ObjectType type; QString ddl; }; explicit SchemaResolver(Db* db); virtual ~SchemaResolver(); QStringList getTables(const QString& database = QString::null); QStringList getIndexes(const QString& database = QString::null); QStringList getTriggers(const QString& database = QString::null); QStringList getViews(const QString& database = QString::null); StrHash getGroupedIndexes(const QString& database = QString::null); StrHash getGroupedTriggers(const QString& database = QString::null); QSet getDatabases(); QStringList getObjects(const QString& type); QStringList getObjects(const QString& database, const QString& type); QStringList getAllObjects(); QStringList getAllObjects(const QString& database); QString getUniqueName(const QString& database, const QString& namePrefix); QString getUniqueName(const QString& namePrefix = QString::null); QStringList getFkReferencingTables(const QString& table); QStringList getFkReferencingTables(const QString& database, const QString& table); QStringList getIndexesForTable(const QString& database, const QString& table); QStringList getIndexesForTable(const QString& table); QStringList getTriggersForTable(const QString& database, const QString& table); QStringList getTriggersForTable(const QString& table); QStringList getTriggersForView(const QString& database, const QString& view); QStringList getTriggersForView(const QString& view); QStringList getViewsForTable(const QString& database, const QString& table); QStringList getViewsForTable(const QString& table); StrHash getAllObjectDetails(); StrHash getAllObjectDetails(const QString& database); QList getParsedIndexesForTable(const QString& database, const QString& table); QList getParsedIndexesForTable(const QString& table); QList getParsedTriggersForTable(const QString& database, const QString& table, bool includeContentReferences = false); QList getParsedTriggersForTable(const QString& table, bool includeContentReferences = false); QList getParsedTriggersForView(const QString& database, const QString& view, bool includeContentReferences = false); QList getParsedTriggersForView(const QString& view, bool includeContentReferences = false); QList getParsedViewsForTable(const QString& database, const QString& table); QList getParsedViewsForTable(const QString& table); bool isWithoutRowIdTable(const QString& table); bool isWithoutRowIdTable(const QString& database, const QString& table); bool isVirtualTable(const QString& database, const QString& table); bool isVirtualTable(const QString& table); SqliteCreateTablePtr resolveVirtualTableAsRegularTable(const QString& table); SqliteCreateTablePtr resolveVirtualTableAsRegularTable(const QString& database, const QString& table); QStringList getWithoutRowIdTableColumns(const QString& table); QStringList getWithoutRowIdTableColumns(const QString& database, const QString& table); /** * @brief getTableColumns Get column names for a table. * @param table Table to query. * @return List of column names of the table. * This does something similar to getting list of columns with * PRAGMA table_info(), but the pragma in Sqlite2 doesn't support * queries for attached databases, therefore this method is provided * to make this possible. It finds table's DDL and parses it, * then extracts list of columns from parsing results. */ QStringList getTableColumns(const QString& table); /** * @brief getTableColumns Get column names for a table. * @param database Attached database name. * @param table Table to query. * @return List of column names of the table. * @overload */ QStringList getTableColumns(const QString& database, const QString& table); QList getTableColumnDataTypes(const QString& table, int expectedNumberOfTypes = -1); QList getTableColumnDataTypes(const QString& database, const QString& table, int expectedNumberOfTypes = -1); StrHash getAllTableColumns(const QString& database = QString::null); QStringList getViewColumns(const QString& view); QStringList getViewColumns(const QString& database, const QString& view); QList getViewColumnObjects(const QString& view); QList getViewColumnObjects(const QString& database, const QString& view); QString getObjectDdl(const QString& name, ObjectType type); QString getObjectDdl(const QString& database, const QString& name, ObjectType type); /** * @brief Parses given object's DDL. * @param name Name of the object in the database. * @return Parsed object, or null pointer if named object was not in the database, or parsing error occured. * * Returned query has to be deleted outside! */ SqliteQueryPtr getParsedObject(const QString& name, ObjectType type); /** * @brief Parses given object's DDL. * @param database Database that the object is in (the attach name of the database). * @param name Name of the object in the database. * @return Parsed object, or null pointer if named object was not in the database, or parsing error occured. * @overload */ SqliteQueryPtr getParsedObject(const QString& database, const QString& name, ObjectType type); StrHash getAllParsedObjects(); StrHash getAllParsedObjects(const QString& database); StrHash getAllParsedTables(); StrHash getAllParsedTables(const QString& database); StrHash getAllParsedIndexes(); StrHash getAllParsedIndexes(const QString& database); StrHash getAllParsedTriggers(); StrHash getAllParsedTriggers(const QString& database); StrHash getAllParsedViews(); StrHash getAllParsedViews(const QString& database); static QString getSqliteMasterDdl(bool temp = false); static QStringList getFkReferencingTables(const QString& table, const QList& allParsedTables); QStringList getCollations(); bool getIgnoreSystemObjects() const; void setIgnoreSystemObjects(bool value); bool getNoDbLocking() const; void setNoDbLocking(bool value); static QString objectTypeToString(ObjectType type); static ObjectType stringToObjectType(const QString& type); private: SqliteQueryPtr getParsedDdl(const QString& ddl); SqliteCreateTablePtr virtualTableAsRegularTable(const QString& database, const QString& table); StrHash< QStringList> getGroupedObjects(const QString &database, const QStringList& inputList, SqliteQueryType type); bool isFilteredOut(const QString& value, const QString& type); void filterSystemIndexes(QStringList& indexes); QList getParsedTriggersForTableOrView(const QString& database, const QString& tableOrView, bool includeContentReferences, bool table); template StrHash> getAllParsedObjectsForType(const QString& database, const QString& type); Db* db = nullptr; Parser* parser = nullptr; bool ignoreSystemObjects = false; Db::Flags dbFlags; }; template StrHash> SchemaResolver::getAllParsedObjectsForType(const QString& database, const QString& type) { StrHash< QSharedPointer> parsedObjects; QString dbName = getPrefixDb(database, db->getDialect()); SqlQueryPtr results; if (type.isNull()) results = db->exec(QString("SELECT name, type, sql FROM %1.sqlite_master;").arg(dbName)); else results = db->exec(QString("SELECT name, type, sql FROM %1.sqlite_master WHERE type = '%2';").arg(dbName, type)); QString name; SqliteQueryPtr parsedObject; QSharedPointer castedObject; foreach (SqlResultsRowPtr row, results->getAll()) { name = row->value("name").toString(); parsedObject = getParsedDdl(row->value("sql").toString()); if (!parsedObject) continue; if (isFilteredOut(name, row->value("type").toString())) continue; castedObject = parsedObject.dynamicCast(); if (castedObject) parsedObjects[name] = castedObject; } return parsedObjects; } #endif // SCHEMARESOLVER_H