1 /* This file is part of the KDE project
2    Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this library; see the file COPYING.LIB.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #ifndef KDB_QUERYSCHEMA_P_H
21 #define KDB_QUERYSCHEMA_P_H
22 
23 #include "KDbDriver.h"
24 #include "KDbExpression.h"
25 #include "KDbQueryColumnInfo.h"
26 #include "KDbQuerySchema.h"
27 
28 #include <QBitArray>
29 #include <QWeakPointer>
30 
31 class KDbConnection;
32 
33 class Q_DECL_HIDDEN KDbQueryColumnInfo::Private
34 {
35 public:
Private(KDbField * f,const QString & a,bool v,KDbQueryColumnInfo * foreign)36     Private(KDbField *f, const QString& a, bool v, KDbQueryColumnInfo *foreign)
37         : field(f)
38         , alias(a)
39         , visible(v)
40         , indexForVisibleLookupValue(-1)
41         , foreignColumn(foreign)
42     {
43     }
44 
45     KDbConnection *connection = nullptr; //!< Used to relate KDbQueryColumnInfo with query. @since 3.2
46     const KDbQuerySchema *querySchema = nullptr; //!< Used to relate KDbQueryColumnInfo with query. @since 3.2
47     KDbField *field;
48     QString alias;
49 
50     //! @c true if this column is visible to the user (and its data is fetched by the engine)
51     bool visible;
52 
53     /*! Index of column with visible lookup value within the 'fields expanded' vector.
54      @see KDbQueryColumnInfo::indexForVisibleLookupValue() */
55     int indexForVisibleLookupValue;
56 
57     //! Non-nullptr if this column is a visible column for @a foreignColumn
58     KDbQueryColumnInfo *foreignColumn;
59 };
60 
61 class KDbQuerySchemaPrivate
62 {
63     Q_DECLARE_TR_FUNCTIONS(KDbQuerySchema)
64 public:
65     explicit KDbQuerySchemaPrivate(KDbQuerySchema* q, KDbQuerySchemaPrivate* copy = nullptr);
66 
67     ~KDbQuerySchemaPrivate();
68 
69     //! @return a new query that's associated with @a conn. Used internally, e.g. by the parser.
70     //! Uses an internal KDbQuerySchema(KDbConnection*) ctor.
71     static KDbQuerySchema* createQuery(KDbConnection *conn);
72 
73     void clear();
74 
75     void clearCachedData();
76 
77     bool setColumnAlias(int position, const QString& alias);
78 
setTableAlias(int position,const QString & alias)79     inline bool setTableAlias(int position, const QString& alias) {
80         if (tablePositionsForAliases.contains(alias.toLower())) {
81             return false;
82         }
83         tableAliases.insert(position, alias.toLower());
84         tablePositionsForAliases.insert(alias.toLower(), position);
85         return true;
86     }
87 
columnAliasesCount()88     inline int columnAliasesCount() {
89         tryRegenerateExprAliases();
90         return columnAliases.count();
91     }
92 
columnAlias(int position)93     inline QString columnAlias(int position) {
94         tryRegenerateExprAliases();
95         return columnAliases.value(position);
96     }
97 
hasColumnAlias(int position)98     inline bool hasColumnAlias(int position) {
99         tryRegenerateExprAliases();
100         return columnAliases.contains(position);
101     }
102 
removeTablePositionForAlias(const QString & alias)103     inline void removeTablePositionForAlias(const QString& alias) {
104         tablePositionsForAliases.remove(alias.toLower());
105     }
106 
tablePositionForAlias(const QString & alias)107     inline int tablePositionForAlias(const QString& alias) const {
108         return tablePositionsForAliases.value(alias.toLower(), -1);
109     }
110 
columnPositionForAlias(const QString & alias)111     inline int columnPositionForAlias(const QString& alias) const {
112         return columnPositionsForAliases.value(alias.toLower(), -1);
113     }
114 
115     //! Accessor for buildSelectQuery()
setWhereExpressionInternal(KDbQuerySchema * query,const KDbExpression & expr)116     static void setWhereExpressionInternal(KDbQuerySchema *query, const KDbExpression &expr)
117     {
118         query->d->whereExpr = expr;
119     }
120 
121     KDbQuerySchema *query;
122 
123     /*! Master table of the query. Can be @c nullptr.
124       Any data modifications can be performed if we know master table.
125       If null, query's records cannot be modified. */
126     KDbTableSchema *masterTable;
127 
128     /*! List of tables used in this query */
129     QList<KDbTableSchema*> tables;
130 
131     KDbField *fakeRecordIdField; //! used to mark a place for record Id
132     KDbQueryColumnInfo *fakeRecordIdCol; //! used to mark a place for record Id
133 
134 protected:
135     void tryRegenerateExprAliases();
136 
137     bool setColumnAliasInternal(int position, const QString& alias);
138 
139     /*! Used to mapping columns to its aliases for this query */
140     QHash<int, QString> columnAliases;
141 
142     /*! Collects table positions for aliases: used in tablePositionForAlias(). */
143     QHash<QString, int> tablePositionsForAliases;
144 
145     /*! Collects column positions for aliases: used in columnPositionForAlias(). */
146     QHash<QString, int> columnPositionsForAliases;
147 
148 public:
149     /*! Used to mapping tables to its aliases for this query */
150     QHash<int, QString> tableAliases;
151 
152     /*! Helper used with aliases */
153     int maxIndexWithAlias;
154 
155     /*! Used to store visibility flag for every field */
156     QBitArray visibility;
157 
158     /*! List of asterisks defined for this query  */
159     KDbField::List asterisks;
160 
161     /*! A list of fields for ORDER BY section. @see KDbQuerySchema::orderByColumnList(). */
162     KDbOrderByColumnList* orderByColumnList;
163 
164     /*! A cache for autoIncrementFields(). */
165     KDbQueryColumnInfo::List *autoincFields;
166 
167     /*! A cache for autoIncrementSqlFieldsList(). */
168     KDbEscapedString autoIncrementSqlFieldsList;
169     QWeakPointer<const KDbDriver> lastUsedDriverForAutoIncrementSQLFieldsList;
170 
171     /*! order of PKEY fields (e.g. for updateRecord() ) */
172     QVector<int> *pkeyFieldsOrder;
173 
174     /*! number of PKEY fields within the query */
175     int pkeyFieldCount;
176 
177     /*! Forced (predefined) raw SQL statement */
178     KDbEscapedString sql;
179 
180     /*! Relationships defined for this query. */
181     QList<KDbRelationship*> relations;
182 
183     /*! Information about columns bound to tables.
184      Used if table is used in FROM section more than once
185      (using table aliases).
186 
187      This list is updated by insertField(int position, KDbField *field,
188      int bindToTable, bool visible), using bindToTable parameter.
189 
190      Example: for this statement:
191      SELECT t1.a, othertable.x, t2.b FROM table t1, table t2, othertable;
192      tablesBoundToColumns list looks like this:
193      [ 0, -1, 1 ]
194      - first column is bound to table 0 "t1"
195      - second coulmn is not specially bound (othertable.x isn't ambiguous)
196      - third column is bound to table 1 "t2"
197     */
198     QVector<int> tablesBoundToColumns;
199 
200     /*! WHERE expression */
201     KDbExpression whereExpr;
202 
203     /*! Set by insertField(): true, if aliases for expression columns should
204      be generated on next columnAlias() call. */
205     bool regenerateExprAliases;
206 
207     //! Points to connection recently used for caching
208     //! @todo use equivalent of QPointer<KDbConnection>
209     KDbConnection *recentConnection = nullptr;
210 
211     //! Owned fields created by KDbQuerySchema::addExpressionInternal()
212     KDbField::List ownedExpressionFields;
213 };
214 
215 //! Information about expanded fields for a single query schema, used for caching
216 class KDbQuerySchemaFieldsExpanded
217 {
218 public:
KDbQuerySchemaFieldsExpanded()219     inline KDbQuerySchemaFieldsExpanded()
220     {
221     }
222 
~KDbQuerySchemaFieldsExpanded()223     inline ~KDbQuerySchemaFieldsExpanded()
224     {
225         qDeleteAll(fieldsExpanded);
226         qDeleteAll(internalFields);
227     }
228 
229     /*! Temporary field vector for using in fieldsExpanded() */
230     KDbQueryColumnInfo::Vector fieldsExpanded;
231 
232     /*! Like fieldsExpanded but only visible column infos; infos are not owned. */
233     KDbQueryColumnInfo::Vector visibleFieldsExpanded;
234 
235     /*! Temporary field vector containing internal fields used for lookup columns. */
236     KDbQueryColumnInfo::Vector internalFields;
237 
238     /*! Temporary, used to cache sum of expanded fields and internal fields (+record Id) used for lookup columns.
239      Contains not auto-deleted items.*/
240     KDbQueryColumnInfo::Vector fieldsExpandedWithInternalAndRecordId;
241 
242     /*! Like fieldsExpandedWithInternalAndRecordId but only contains visible column infos; infos are not owned.*/
243     KDbQueryColumnInfo::Vector visibleFieldsExpandedWithInternalAndRecordId;
244 
245     /*! Temporary, used to cache sum of expanded fields and internal fields used for lookup columns.
246      Contains not auto-deleted items.*/
247     KDbQueryColumnInfo::Vector fieldsExpandedWithInternal;
248 
249     /*! Like fieldsExpandedWithInternal but only contains visible column infos; infos are not owned.*/
250     KDbQueryColumnInfo::Vector visibleFieldsExpandedWithInternal;
251 
252     /*! A hash for fast lookup of query columns' order (unexpanded version). */
253     QHash<KDbQueryColumnInfo*, int> columnsOrder;
254 
255     /*! A hash for fast lookup of query columns' order (unexpanded version without asterisks). */
256     QHash<KDbQueryColumnInfo*, int> columnsOrderWithoutAsterisks;
257 
258     /*! A hash for fast lookup of query columns' order.
259      This is exactly opposite information compared to vector returned
260      by fieldsExpanded() */
261     QHash<KDbQueryColumnInfo*, int> columnsOrderExpanded;
262 
263     QHash<QString, KDbQueryColumnInfo*> columnInfosByNameExpanded;
264 
265     QHash<QString, KDbQueryColumnInfo*> columnInfosByName; //!< Same as columnInfosByNameExpanded but asterisks are skipped
266 
267     //! Fields created for multiple joined columns like a||' '||b||' '||c
268     KDbField::List ownedVisibleFields;
269 };
270 
271 /**
272  * Return identifier string @a name escaped using @a conn connection and type @a escapingType
273  *
274  * @a conn is only used for KDb::DriverEscaping type. If @a conn is missing for this type,
275  * identifier is escaped using double quotes (").
276  */
277 QString escapeIdentifier(const QString& name, KDbConnection *conn,
278                          KDb::IdentifierEscapingType escapingType);
279 
280 #endif
281