You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
833 lines
36 KiB
833 lines
36 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef KEXIDB_QUERY_H
|
|
#define KEXIDB_QUERY_H
|
|
|
|
#include <qvaluevector.h>
|
|
#include <qstring.h>
|
|
#include <qmap.h>
|
|
#include <qptrlist.h>
|
|
|
|
#include "fieldlist.h"
|
|
#include "schemadata.h"
|
|
#include "tableschema.h"
|
|
#include "relationship.h"
|
|
|
|
namespace KexiDB {
|
|
|
|
class Connection;
|
|
class QueryAsterisk;
|
|
class QuerySchemaPrivate;
|
|
class QuerySchemaParameter;
|
|
typedef QValueList<QuerySchemaParameter> QuerySchemaParameterList;
|
|
|
|
//! @short Helper class that assigns additional information for the column in a query
|
|
/*! The following information is assigned:
|
|
- alias
|
|
- visibility
|
|
QueryColumnInfo::Vector is created and returned by QuerySchema::fieldsExpanded().
|
|
It is efficiently cached within the QuerySchema object.
|
|
*/
|
|
class KEXI_DB_EXPORT QueryColumnInfo
|
|
{
|
|
public:
|
|
typedef QPtrVector<QueryColumnInfo> Vector;
|
|
typedef QPtrList<QueryColumnInfo> List;
|
|
typedef QPtrListIterator<QueryColumnInfo> ListIterator;
|
|
|
|
QueryColumnInfo(Field *f, const QCString& _alias, bool _visible, QueryColumnInfo *foreignColumn = 0);
|
|
~QueryColumnInfo();
|
|
|
|
//! \return alias if it is not empty, field's name otherwise.
|
|
inline QCString aliasOrName() const {
|
|
return alias.isEmpty() ? field->name().latin1() : (const char*)alias;
|
|
}
|
|
|
|
//! \return field's caption if it is not empty, field's alias otherwise.
|
|
//! If alias is also empty - returns field's name.
|
|
inline QString captionOrAliasOrName() const {
|
|
return field->caption().isEmpty() ? QString(aliasOrName()) : field->caption(); }
|
|
|
|
Field *field;
|
|
QCString alias;
|
|
|
|
/*! \return index of column with visible lookup value within the 'fields expanded' vector.
|
|
-1 means no visible lookup value is available because there is no lookup for the column defined.
|
|
Cached for efficiency as we use this information frequently.
|
|
@see LookupFieldSchema::visibleVolumn() */
|
|
inline int indexForVisibleLookupValue() const { return m_indexForVisibleLookupValue; }
|
|
|
|
/*! Sets index of column with visible lookup value within the 'fields expanded' vector. */
|
|
inline void setIndexForVisibleLookupValue(int index) { m_indexForVisibleLookupValue = index; }
|
|
|
|
//! \return non-0 if this column is a visible column for other column
|
|
QueryColumnInfo *foreignColumn() const { return m_foreignColumn; }
|
|
|
|
/*! \return string for debugging purposes. */
|
|
QString debugString() const;
|
|
|
|
//! true if this column is visible to the user (and its data is fetched by the engine)
|
|
bool visible : 1;
|
|
|
|
private:
|
|
/*! Index of column with visible lookup value within the 'fields expanded' vector.
|
|
@see indexForVisibleLookupValue() */
|
|
int m_indexForVisibleLookupValue;
|
|
|
|
//! Non-0 if this column is a visible column for \a m_foreignColumn
|
|
QueryColumnInfo *m_foreignColumn;
|
|
};
|
|
|
|
//! @short KexiDB::OrderByColumn provides information about a single query column used for sorting
|
|
/*! The column can be expression or table field. */
|
|
class KEXI_DB_EXPORT OrderByColumn
|
|
{
|
|
public:
|
|
typedef QValueListConstIterator<OrderByColumn> ListConstIterator;
|
|
OrderByColumn();
|
|
OrderByColumn(QueryColumnInfo& column, bool ascending = true, int pos = -1);
|
|
|
|
//! Like above but used when the field \a field is not present on the list of columns.
|
|
//! (e.g. SELECT a FROM t ORDER BY b; where T is a table with fields (a,b)).
|
|
OrderByColumn(Field& field, bool ascending = true);
|
|
|
|
~OrderByColumn();
|
|
|
|
//! A column to sort.
|
|
inline QueryColumnInfo* column() const { return m_column; }
|
|
|
|
/*! A helper for column() that allows you to know that sorting column
|
|
was defined by providing its position. -1 by default.
|
|
Example query: SELECT a, b FROM T ORDER BY 2 */
|
|
inline int position() const { return m_pos; }
|
|
|
|
//! A field to sort, used only in case when the second constructor was used.
|
|
inline Field *field() const { return m_field; }
|
|
|
|
//! \return true if ascending sorting should be performed (the default).
|
|
inline bool ascending() const { return m_ascending; }
|
|
|
|
//! \return true if this column is thesame as \a col
|
|
bool operator== ( const OrderByColumn& col ) const
|
|
{ return m_column==col.m_column && m_field==col.m_field
|
|
&& m_ascending==col.m_ascending; }
|
|
|
|
/*! \return string for debugging purposes. */
|
|
QString debugString() const;
|
|
|
|
/*! \return a string like "name ASC" usable for building a SQL statement.
|
|
If \a includeTableNames is true (the default) field is output in a form
|
|
of "tablename.fieldname" (but only if fieldname is not a name of alias).
|
|
\a drv and \a identifierEscaping are used for escaping the table and field identifiers. */
|
|
QString toSQLString(bool includeTableName = true,
|
|
Driver *drv = 0, int identifierEscaping = Driver::EscapeDriver|Driver::EscapeAsNecessary) const;
|
|
|
|
protected:
|
|
//! Column to sort
|
|
QueryColumnInfo* m_column; //!< 0 if m_field is non-0.
|
|
int m_pos; //!< A helper for m_column that allows to know that sorting column
|
|
//!< was defined by providing its position. -1 by default.
|
|
//!< e.g. SELECT a, b FROM T ORDER BY 2
|
|
Field* m_field; //!< Used only in case when the second contructor is used.
|
|
|
|
//! true if ascending sorting should be performed (the default).
|
|
bool m_ascending : 1;
|
|
};
|
|
|
|
//! A base for KexiDB::OrderByColumnList
|
|
typedef QValueList<OrderByColumn> OrderByColumnListBase;
|
|
|
|
//! @short KexiDB::OrderByColumnList provides list of sorted columns for a query schema
|
|
class KEXI_DB_EXPORT OrderByColumnList : protected OrderByColumnListBase
|
|
{
|
|
public:
|
|
/*! Constructs empty list of ordered columns. */
|
|
OrderByColumnList();
|
|
|
|
~OrderByColumnList();
|
|
|
|
/*! Appends multiple fields for sorting. \a querySchema
|
|
is used to find appropriate field or alias name.
|
|
\return false if there is at least one name for which a field or alias name does not exist
|
|
(all the newly appended fields are removed in this case) */
|
|
bool appendFields(QuerySchema& querySchema,
|
|
const QString& field1, bool ascending1 = true,
|
|
const QString& field2 = QString::null, bool ascending2 = true,
|
|
const QString& field3 = QString::null, bool ascending3 = true,
|
|
const QString& field4 = QString::null, bool ascending4 = true,
|
|
const QString& field5 = QString::null, bool ascending5 = true);
|
|
|
|
/*! Appends column \a columnInfo. Ascending sorting is set is \a ascending is true. */
|
|
void appendColumn(QueryColumnInfo& columnInfo, bool ascending = true);
|
|
|
|
/*! Appends a field \a field. Ascending sorting is set is \a ascending is true.
|
|
Read documentation of \ref OrderByColumn(const Field& field, bool ascending = true)
|
|
for more info. */
|
|
void appendField(Field& field, bool ascending = true);
|
|
|
|
/*! Appends field with a name \a field. Ascending sorting is set is \a ascending is true.
|
|
\return true on successful appending, and false if there is no such field or alias
|
|
name in the \a querySchema. */
|
|
bool appendField(QuerySchema& querySchema, const QString& fieldName,
|
|
bool ascending = true);
|
|
|
|
/*! Appends a column that is at position \a pos (counted from 0).
|
|
\return true on successful adding and false if there is no such position \a pos. */
|
|
bool appendColumn(QuerySchema& querySchema, bool ascending = true, int pos = -1);
|
|
|
|
/*! Appends \a column to the list. */
|
|
void appendColumn(const OrderByColumn& column);
|
|
|
|
/*! \return true if the list is empty. */
|
|
bool isEmpty() const { return OrderByColumnListBase::isEmpty(); }
|
|
|
|
/*! \return number of elements of the list. */
|
|
uint count() const { return OrderByColumnListBase::count(); }
|
|
|
|
/*! Removes all elements from the list. */
|
|
void clear() { OrderByColumnListBase::clear(); }
|
|
|
|
const_iterator constBegin () const { return OrderByColumnListBase::constBegin(); }
|
|
const_iterator constEnd () const { return OrderByColumnListBase::constEnd(); }
|
|
|
|
/*! \return string for debugging purposes. */
|
|
QString debugString() const;
|
|
|
|
/*! \return a string like "name ASC, 2 DESC" usable for building a SQL statement.
|
|
If \a includeTableNames is true (the default) fields are output in a form
|
|
of "tablename.fieldname".
|
|
\a drv and \a identifierEscaping are used for escaping the table and field identifiers. */
|
|
QString toSQLString(bool includeTableNames = true,
|
|
Driver *drv = 0, int identifierEscaping = Driver::EscapeDriver|Driver::EscapeAsNecessary) const;
|
|
};
|
|
|
|
//! @short KexiDB::QuerySchema provides information about database query
|
|
/*! The query that can be executed using KexiDB-compatible SQL database engine
|
|
or used as an introspection tool. KexiDB parser builds QuerySchema objects
|
|
by parsing SQL statements. */
|
|
class KEXI_DB_EXPORT QuerySchema : public FieldList, public SchemaData
|
|
{
|
|
public:
|
|
/*! Creates empty query object (without columns). */
|
|
QuerySchema();
|
|
|
|
/*! Creates query schema object that is equivalent to "SELECT * FROM table"
|
|
sql command. Schema of \a table is used to contruct this query --
|
|
it is defined by just adding all the fields to the query in natural order.
|
|
To avoid problems (e.g. with fields added outside of Kexi using ALTER TABLE)
|
|
we do not use "all-tables query asterisk" (see QueryAsterisk) item to achieve
|
|
this effect.
|
|
|
|
Properties such as the name and caption of the query are inherited
|
|
from table schema.
|
|
|
|
We consider that query schema based on \a table is not (a least yet) stored
|
|
in a system table, so query connection is set to NULL
|
|
(even if \a tableSchema's connection is not NULL).
|
|
Id of the created query is set to 0. */
|
|
QuerySchema(TableSchema& tableSchema);
|
|
|
|
/*! Copy constructor. Creates deep copy of \a querySchema.
|
|
QueryAsterisk objects are deeply copied while only pointers to Field objects are copied. */
|
|
QuerySchema(const QuerySchema& querySchema);
|
|
|
|
virtual ~QuerySchema();
|
|
|
|
/*! Inserts \a field to the columns list at \a position.
|
|
Inserted field will not be owned by this QuerySchema object,
|
|
but still by corresponding TableSchema.
|
|
|
|
As \a field object you can also pass KexiDB::QueryAsterisk,
|
|
(see QueryAsterisk class description).
|
|
|
|
Note: After inserting a field, corresponding table will be automatically
|
|
added to query's tables list if it is not present there (see tables()).
|
|
Field must have its table assigned.
|
|
|
|
Added field will be visible. Use insertField(position, field, false)
|
|
to add invisible field.
|
|
*/
|
|
virtual FieldList& insertField(uint position, Field *field);
|
|
|
|
/* Like above method, but you can also set column's visibility.
|
|
New column is not bound explicitly to any table.
|
|
*/
|
|
FieldList& insertField(uint position, Field *field, bool visible);
|
|
|
|
/* Like above method, but you can also explicitly bound the new column
|
|
to specific position on tables list.
|
|
If \a visible is true (the default), the field will be visible.
|
|
If bindToTable==-1, no particular table should be bound.
|
|
@see tableBoundToColumn(uint columnPosition) */
|
|
FieldList& insertField(uint position, Field *field,
|
|
int bindToTable, bool visible = true);
|
|
|
|
/*! Adds \a field to the columns list.
|
|
If \a visible is true (the default), the field will be visible.
|
|
\sa insertField() */
|
|
FieldList& addField(Field* field, bool visible = true);
|
|
|
|
/*! Adds \a field to the columns list. Also binds to a table
|
|
at \a bindToTable position. Use bindToTable==-1 if no table should be bound.
|
|
If \a visible is true (the default), the field will be visible.
|
|
\sa insertField()
|
|
\sa tableBoundToColumn(uint columnPosition)
|
|
*/
|
|
FieldList& addField(Field* field, int bindToTable,
|
|
bool visible = true);
|
|
|
|
/*! Removes field from the columns list. Use with care. */
|
|
virtual void removeField(Field *field);
|
|
|
|
/*! Adds a field built on top of \a expr expression.
|
|
This creates a new Field object and adds it to the query schema using addField(). */
|
|
FieldList& addExpression(BaseExpr* expr, bool visible = true);
|
|
|
|
/*! \return visibility flag for column at \a position.
|
|
By default column is visible. */
|
|
bool isColumnVisible(uint position) const;
|
|
|
|
//! Sets visibility flag for column at \a position to \a v.
|
|
void setColumnVisible(uint position, bool v);
|
|
|
|
/*! Adds \a asterisk at the and of columns list. */
|
|
FieldList& addAsterisk(QueryAsterisk *asterisk, bool visible = true);
|
|
|
|
/*! Removes all columns and their aliases from the columns list,
|
|
removes all tables and their aliases from the tables list within this query.
|
|
Sets master table information to NULL.
|
|
Does not destroy any objects though. Clears name and all other properties.
|
|
\sa FieldList::clear() */
|
|
virtual void clear();
|
|
|
|
/*! \return string for debugging purposes. */
|
|
virtual QString debugString();
|
|
|
|
/*! If query was created using a connection,
|
|
returns this connection object, otherwise NULL. */
|
|
Connection* connection() const;
|
|
|
|
/*! \return table that is master to this query.
|
|
All potentially-editable columns within this query belong just to this table.
|
|
This method also can return NULL if there are no tables at all,
|
|
or if previously assigned master table schema has been removed
|
|
with removeTable().
|
|
Every query that has at least one table defined, should have
|
|
assigned a master table.
|
|
If no master table is assigned explicitym but this method there is only
|
|
one table used for this query even if there are table aliases,
|
|
a single table is returned here.
|
|
(e.g. "T" table is returned for "SELECT T1.A, T2.B FROM T T1, T T2" statement). */
|
|
TableSchema* masterTable() const;
|
|
|
|
/*! Sets master table of this query to \a table.
|
|
This table should be also added to query's tables list
|
|
using addTable(). If \a table equals NULL, nothing is performed.
|
|
\sa masterTable() */
|
|
void setMasterTable(TableSchema *table);
|
|
|
|
/*! \return list of tables used in a query.
|
|
This also includes master table.
|
|
\sa masterTable() */
|
|
TableSchema::List* tables() const;
|
|
|
|
/*! Adds \a table schema as one of tables used in a query.
|
|
if \a alias is not empty, it will be assigned to this table
|
|
using setTableAlias(position, alias)
|
|
*/
|
|
void addTable(TableSchema *table, const QCString& alias = QCString());
|
|
|
|
/*! Removes \a table schema from this query.
|
|
This does not destroy \a table object but only takes it out of the list.
|
|
If this table was master for the query, master table information is also
|
|
invalidated. */
|
|
void removeTable(TableSchema *table);
|
|
|
|
/*! \return table with name \a tableName or 0 if this query has no such table. */
|
|
TableSchema* table(const QString& tableName) const;
|
|
|
|
/*! \return true if the query uses \a table. */
|
|
bool contains(TableSchema *table) const;
|
|
|
|
/*! Convenience function.
|
|
\return table field by searching through all tables in this query.
|
|
The field does not need to be included on the list of query columns.
|
|
Similarly, query aliases are not taken into account.
|
|
|
|
\a tableOrTableAndFieldName string may contain table name and field name
|
|
with '.' character between them, e.g. "mytable.myfield".
|
|
This is recommended way to avoid ambiguity.
|
|
0 is returned if the query has no such
|
|
table defined of the table has no such field defined.
|
|
If you do not provide a table name, the first field found is returned.
|
|
|
|
QuerySchema::table("mytable")->field("myfield") could be
|
|
alternative for findTableField("mytable.myfield") but it can crash
|
|
if "mytable" is not defined in the query.
|
|
|
|
@see KexiDB::splitToTableAndFieldParts()
|
|
*/
|
|
Field* findTableField(const QString &tableOrTableAndFieldName) const;
|
|
|
|
/*! \return alias of a column at \a position or null string
|
|
If there is no alias for this column
|
|
or if there is no such column within the query defined.
|
|
If the column is an expression and has no alias defined,
|
|
a new unique alias will be generated automatically on this call.
|
|
*/
|
|
QCString columnAlias(uint position) const;
|
|
|
|
/*! Provided for convenience.
|
|
\return true if a column at \a position has non empty alias defined
|
|
within the query.
|
|
If there is no alias for this column,
|
|
or if there is no such column in the query defined, false is returned. */
|
|
bool hasColumnAlias(uint position) const;
|
|
|
|
/*! Sets \a alias for a column at \a position, within the query.
|
|
Passing empty string to \a alias clears alias for a given column. */
|
|
void setColumnAlias(uint position, const QCString& alias);
|
|
|
|
/*! \return a table position (within FROM section),
|
|
that is bound to column at \a columnPosition (within SELECT section).
|
|
This information can be used to find if there is alias defined for
|
|
a table that is referenced by a given column.
|
|
|
|
For example, for "SELECT t2.id FROM table1 t1, table2 t2" query statement,
|
|
columnBoundToTable(0) returns 1, what means that table at position 1
|
|
(within FROM section) is bound to column at position 0, so we can
|
|
now call tableAlias(1) to see if we have used alias for this column (t2.d)
|
|
or just a table name (table2.d).
|
|
|
|
These checkings are performed e.g. by Connection::queryStatement()
|
|
to construct a statement string maximally identical to originally
|
|
defined query statement.
|
|
|
|
-1 is returned if:
|
|
- \a columnPosition is out of range (i.e. < 0 or >= fieldCount())
|
|
- a column at \a columnPosition is not bound to any table (i.e.
|
|
no database field is used for this column,
|
|
e.g. "1" constant for "SELECT 1 from table" query statement)
|
|
*/
|
|
int tableBoundToColumn(uint columnPosition) const;
|
|
|
|
/*! \return alias of a table at \a position (within FROM section)
|
|
or null string if there is no alias for this table
|
|
or if there is no such table within the query defined. */
|
|
QCString tableAlias(uint position) const;
|
|
|
|
/*! \return table position (within FROM section) that has attached
|
|
alias \a name.
|
|
If there is no such alias, -1 is returned.
|
|
Only first table's position attached for this alias is returned.
|
|
It is not especially bad, since aliases rarely can be duplicated,
|
|
what leads to ambiguity.
|
|
Duplicated aliases are only allowed for trivial queries that have
|
|
no database fields used within their columns,
|
|
e.g. "SELECT 1 from table1 t, table2 t" is ok
|
|
but "SELECT t.id from table1 t, table2 t" is not.
|
|
*/
|
|
int tablePositionForAlias(const QCString& name) const;
|
|
|
|
/*! \return table position (within FROM section) for \a tableName.
|
|
-1 is returend if there's no such table declared in the FROM section.
|
|
\sa tablePositions()
|
|
*/
|
|
int tablePosition(const QString& tableName) const;
|
|
|
|
/*! \return a list of all \a tableName table occurrences (within FROM section).
|
|
E.g. for "SELECT * FROM table t, table t2" [0, 1] list is returned.
|
|
Empty list is returned there's no such table declared
|
|
in the FROM section at all.
|
|
\sa tablePosition()
|
|
*/
|
|
QValueList<int> tablePositions(const QString& tableName) const;
|
|
|
|
/*! Provided for convenience.
|
|
\return true if a table at \a position (within FROM section of the the query)
|
|
has non empty alias defined.
|
|
If there is no alias for this table,
|
|
or if there is no such table in the query defined, false is returned. */
|
|
bool hasTableAlias(uint position) const;
|
|
|
|
/*! \return column position that has defined alias \a name.
|
|
If there is no such alias, -1 is returned. */
|
|
int columnPositionForAlias(const QCString& name) const;
|
|
|
|
/*! Sets \a alias for a table at \a position (within FROM section
|
|
of the the query).
|
|
Passing empty sting to \a alias clears alias for a given table
|
|
(only for specified \a position). */
|
|
void setTableAlias(uint position, const QCString& alias);
|
|
|
|
/*! \return a list of relationships defined for this query */
|
|
Relationship::List* relationships() const;
|
|
|
|
/*! Adds a new relationship defined by \a field1 and \a field2.
|
|
Both fields should belong to two different tables of this query.
|
|
This is convenience function useful for a typical cases.
|
|
It automatically creates Relationship object for this query.
|
|
If one of the fields are primary keys, it will be detected
|
|
and appropriate master-detail relation will be established.
|
|
This functiuon does nothing if the arguments are invalid. */
|
|
Relationship* addRelationship( Field *field1, Field *field2 );
|
|
|
|
/*! \return list of QueryAsterisk objects defined for this query */
|
|
Field::List* asterisks() const;
|
|
|
|
/*! \return field for \a identifier or 0 if no field for this name
|
|
was found within the query. fieldsExpanded() method is used
|
|
to lookup expanded list of the query fields, so queries with asterisks
|
|
are processed well.
|
|
If a field has alias defined, name is not taken into account,
|
|
but only its alias. If a field has no alias:
|
|
- field's name is checked
|
|
- field's table and field's name are checked in a form of "tablename.fieldname",
|
|
so you can provide \a identifier in this form to avoid ambiguity.
|
|
|
|
If there are more than one fields with the same name equal to \a identifier,
|
|
first-found is returned (checking is performed from first to last query field).
|
|
Structures needed to compute result of this method are cached,
|
|
so only first usage costs o(n) - another usages cost o(1).
|
|
|
|
Example:
|
|
Let query be defined by "SELECT T.B AS X, T.* FROM T" statement and let T
|
|
be table containing fields A, B, C.
|
|
Expanded list of columns for the query is: T.B AS X, T.A, T.B, T.C.
|
|
- Calling field("B") will return a pointer to third query column (not the first,
|
|
because it is covered by "X" alias). Additionally, calling field("X")
|
|
will return the same pointer.
|
|
- Calling field("T.A") will return the same pointer as field("A").
|
|
*/
|
|
virtual Field* field(const QString& name, bool expanded = true);
|
|
|
|
/*! \return field id or NULL if there is no such a field. */
|
|
inline Field* field(uint id) { return FieldList::field(id); }
|
|
|
|
/*! Like QuerySchema::field(const QString& name) but returns not only Field
|
|
object for \a identifier but entire QueryColumnInfo object.
|
|
\a identifier can be:
|
|
- a fieldname
|
|
- an aliasname
|
|
- a tablename.fieldname
|
|
- a tablename.aliasname
|
|
Note that if there are two occurrrences of the same name,
|
|
only the first is accessible using this method. For instance,
|
|
calling columnInfo("name") for "SELECT t1.name, t2.name FROM t1, t2" statement
|
|
will only return the column related to t1.name and not t2.name, so you'll need to
|
|
explicitly specify "t2.name" as the identifier to get the second column. */
|
|
QueryColumnInfo* columnInfo(const QString& identifier, bool expanded = true);
|
|
|
|
/*! Options used in fieldsExpanded(). */
|
|
enum FieldsExpandedOptions {
|
|
Default, //!< All fields are returned even if duplicated
|
|
Unique, //!< Unique list of fields is returned
|
|
WithInternalFields, //!< Like Default but internal fields (for lookup) are appended
|
|
WithInternalFieldsAndRowID //!< Like WithInternalFields but RowID (big int type) field
|
|
//!< is appended after internal fields
|
|
};
|
|
|
|
/*! \return fully expanded list of fields.
|
|
QuerySchema::fields() returns vector of fields used for the query columns,
|
|
but in a case when there are asterisks defined for the query,
|
|
it does not expand QueryAsterisk objects to field lists but return every
|
|
asterisk as-is.
|
|
This could be inconvenient when you need just a fully expanded list of fields,
|
|
so this method does the work for you.
|
|
|
|
If \a options is Unique, each field is returned in the vector only once
|
|
(first found field is selected).
|
|
Note however, that the same field can be returned more than once if it has attached
|
|
a different alias.
|
|
For example, let t be TABLE( a, b ) and let query be defined
|
|
by "SELECT *, a AS alfa FROM t" statement. Both fieldsExpanded(Default)
|
|
and fieldsExpanded(Unique) will return [ a, b, a (alfa) ] list.
|
|
On the other hand, for query defined by "SELECT *, a FROM t" statement,
|
|
fieldsExpanded(Default) will return [ a, b, a ] list while
|
|
fieldsExpanded(Unique) will return [ a, b ] list.
|
|
|
|
If \a options is WithInternalFields or WithInternalFieldsAndRowID,
|
|
additional internal fields are also appended to the vector.
|
|
|
|
If \a options is WithInternalFieldsAndRowID,
|
|
one fake BigInteger column is appended to make space for ROWID column used
|
|
by KexiDB::Cursor implementations. For example, let persons be TABLE( surname, city_id ),
|
|
let city_number reference cities.is in TABLE cities( id, name ) and let query q be defined
|
|
by "SELECT * FROM t" statement. If we want to display persons' city names instead of city_id's.
|
|
To do this, cities.name has to be retrieved as well, so the following statement should be used:
|
|
"SELECT * FROM persons, cities.name LEFT OUTER JOIN cities ON persons.city_id=cities.id".
|
|
Thus, calling fieldsExpanded(WithInternalFieldsAndRowID) will return 4 elements instead of 2:
|
|
persons.surname, persons.city_id, cities.name, {ROWID}. The {ROWID} item is the placeholder
|
|
used for fetching ROWID by KexiDB cursors.
|
|
|
|
By default, all fields are returned in the vector even
|
|
if there are multiple occurrences of one or more (options == Default).
|
|
|
|
Note: You should assign the resulted vector in your space - it will be shared
|
|
and implicity copied on any modification.
|
|
This method's result is cached by QuerySchema object.
|
|
@todo js: UPDATE CACHE!
|
|
*/
|
|
QueryColumnInfo::Vector fieldsExpanded(FieldsExpandedOptions options = Default);
|
|
|
|
/*! \return list of fields internal fields used for lookup columns. */
|
|
QueryColumnInfo::Vector internalFields();
|
|
|
|
/*! \return info for expanded of internal field at index \a index.
|
|
The returned field can be either logical or internal (for lookup),
|
|
the latter case is true if \a index >= fieldsExpanded().count().
|
|
Equivalent of QuerySchema::fieldsExpanded(WithInternalFields).at(index). */
|
|
QueryColumnInfo* expandedOrInternalField(uint index);
|
|
|
|
/*! Options used in columnsOrder(). */
|
|
enum ColumnsOrderOptions {
|
|
UnexpandedList, //!< A map for unexpanded list is created
|
|
UnexpandedListWithoutAsterisks, //!< A map for unexpanded list is created, with asterisks skipped
|
|
ExpandedList //!< A map for expanded list is created
|
|
};
|
|
|
|
/*! \return a map for fast lookup of query columns' order.
|
|
- If \a options is UnexpandedList, each QueryColumnInfo pointer is mapped to the index
|
|
within (unexpanded) list of fields, i.e. "*" or "table.*" asterisks are considered
|
|
to be single items.
|
|
- If \a options is UnexpandedListWithoutAsterisks, each QueryColumnInfo pointer
|
|
is mapped to the index within (unexpanded) list of columns that come from asterisks
|
|
like "*" or "table.*" are not included in the map at all.
|
|
- If \a options is ExpandedList (the default) this method provides is exactly opposite
|
|
information compared to vector returned by fieldsExpanded().
|
|
|
|
This method's result is cached by the QuerySchema object.
|
|
Note: indices of internal fields (see internalFields()) are also returned
|
|
here - in this case the index is counted as a sum of size(e) + i (where "e" is
|
|
the list of expanded fields and i is the column index within internal fields list).
|
|
This feature is used eg. at the end of Connection::updateRow() where need indices of
|
|
fields (including internal) to update all the values in memory.
|
|
|
|
Example use: let t be table (int id, name text, surname text) and q be query
|
|
defined by a statement "select * from t".
|
|
|
|
- columnsOrder(ExpandedList) will return the following map: QueryColumnInfo(id)->0,
|
|
QueryColumnInfo(name)->1, QueryColumnInfo(surname)->2.
|
|
- columnsOrder(UnexpandedList) will return the following map: QueryColumnInfo(id)->0,
|
|
QueryColumnInfo(name)->0, QueryColumnInfo(surname)->0 because the column
|
|
list is not expanded. This way you can use the returned index to get Field*
|
|
pointer using field(uint) method of FieldList superclass.
|
|
- columnsOrder(UnexpandedListWithoutAsterisks) will return the following map:
|
|
QueryColumnInfo(id)->0,
|
|
*/
|
|
QMap<QueryColumnInfo*,int> columnsOrder(ColumnsOrderOptions options = ExpandedList);
|
|
|
|
/*! \return table describing order of primary key (PKEY) fields within the query.
|
|
Indexing is performed against vector returned by fieldsExpanded().
|
|
It is usable for e.g. Conenction::updateRow(), when we need
|
|
to locate each primary key's field in a constant time.
|
|
|
|
Returned vector is owned and cached by QuerySchema object. When you assign it,
|
|
it is implicity shared. Its size is equal to number of primary key
|
|
fields defined for master table (masterTable()->primaryKey()->fieldCount()).
|
|
|
|
Each element of the returned vector:
|
|
- can belong to [0..fieldsExpanded().count()-1] if there is such
|
|
primary key's field in the fieldsExpanded() list.
|
|
- can be equal to -1 if there is no such primary key's field
|
|
in the fieldsExpanded() list.
|
|
|
|
If there are more than one primary key's field included in the query,
|
|
only first-found column (oin the fieldsExpanded() list) for each pkey's field is included.
|
|
|
|
Returns empty vector if there is no master table or no master table's pkey.
|
|
@see example for pkeyFieldsCount().
|
|
@todo js: UPDATE CACHE!
|
|
*/
|
|
QValueVector<int> pkeyFieldsOrder();
|
|
|
|
/*! \return number of master table's primary key fields included in this query.
|
|
This method is useful to quickly check whether the vector returned by pkeyFieldsOrder()
|
|
if filled completely.
|
|
|
|
User e.g. in Connection::updateRow() to check if entire primary
|
|
key information is specified.
|
|
|
|
Examples: let table T has (ID1 INTEGER, ID2 INTEGER, A INTEGER) fields,
|
|
and let (ID1, ID2) is T's primary key.
|
|
-# The query defined by "SELECT * FROM T" statement contains all T's
|
|
primary key's fields as T is the master table, and thus pkeyFieldsCount()
|
|
will return 2 (both primary key's fields are in the fieldsExpanded() list),
|
|
and pkeyFieldsOrder() will return vector {0, 1}.
|
|
-# The query defined by "SELECT A, ID2 FROM T" statement, and thus pkeyFieldsCount()
|
|
will return 1 (only one primary key's field is in the fieldsExpanded() list),
|
|
and pkeyFieldsOrder() will return vector {-1, 1}, as second primary key's field
|
|
is at position #1 and first field is not specified at all within the query.
|
|
*/
|
|
uint pkeyFieldsCount();
|
|
|
|
/*! \return a list of field infos for all auto-incremented fields
|
|
from master table of this query. This result is cached for efficiency.
|
|
fieldsExpanded() is used for that.
|
|
*/
|
|
QueryColumnInfo::List* autoIncrementFields();
|
|
|
|
/*! \return a preset statement (if any). */
|
|
QString statement() const;
|
|
|
|
/*! Forces a query statement (i.e. no statement is composed from QuerySchema's content) */
|
|
void setStatement(const QString &s);
|
|
|
|
/*! \return a string that is a result of concatenating all column names
|
|
for \a infolist, with "," between each one.
|
|
This is usable e.g. as argument like "field1,field2"
|
|
for "INSERT INTO (xxx) ..". The result of this method is effectively cached,
|
|
and it is invalidated when set of fields changes (e.g. using clear()
|
|
or addField()).
|
|
|
|
This method is similar to FieldList::sqlFieldsList() it just uses
|
|
QueryColumnInfo::List instead of Field::List.
|
|
*/
|
|
static QString sqlColumnsList(QueryColumnInfo::List* infolist, Driver *driver);
|
|
|
|
/*! \return cached sql list created using sqlColumnsList() on a list returned
|
|
by autoIncrementFields(). */
|
|
QString autoIncrementSQLFieldsList(Driver *driver);
|
|
|
|
/*! Sets a WHERE expression \a exp. It will be owned by this query,
|
|
so you can forget about it. Previously set WHERE expression will be deleted.
|
|
You can pass 0 to remove expresssion. */
|
|
void setWhereExpression(BaseExpr *expr);
|
|
|
|
/*! \return WHERE expression or 0 if this query has no WHERE expression */
|
|
BaseExpr *whereExpression() const;
|
|
|
|
/*! Adds a part to WHERE expression.
|
|
Simplifies creating of WHERE expression, if used instead
|
|
of setWhereExpression(BaseExpr *expr). */
|
|
void addToWhereExpression(KexiDB::Field *field, const QVariant& value, int relation = '=');
|
|
|
|
/*! Sets a list of columns for ORDER BY section of the query.
|
|
Each name on the list must be a field or alias present within the query
|
|
and must not be covered by aliases. If one or more names cannot be found
|
|
within the query, the method will have no effect.
|
|
Any previous ORDER BY settings will be removed.
|
|
|
|
Note that this information is cleared whenever you call methods that
|
|
modify list of columns (QueryColumnInfo), i.e. insertFiled(),
|
|
addField(), removeField(), addExpression(), etc.
|
|
(because OrderByColumn items can point to a QueryColumnInfo that's removed by these
|
|
methods), so you should use setOrderByColumnList() method after the query
|
|
is completely built. */
|
|
void setOrderByColumnList(const OrderByColumnList& list);
|
|
|
|
/*! \return a list of columns listed in ORDER BY section of the query.
|
|
Read notes for \ref setOrderByColumnList(). */
|
|
OrderByColumnList& orderByColumnList() const;
|
|
|
|
/*! \return query schema parameters. These are taked from the WHERE section
|
|
(a tree of expression items). */
|
|
QuerySchemaParameterList parameters();
|
|
|
|
protected:
|
|
void init();
|
|
|
|
void computeFieldsExpanded();
|
|
|
|
QuerySchemaPrivate *d;
|
|
|
|
friend class Connection;
|
|
friend class QuerySchemaPrivate;
|
|
};
|
|
|
|
//! @short KexiDB::QueryAsterisk class encapsulates information about single asterisk in query definition
|
|
/*! There are two types of query asterisks:
|
|
|
|
1. "Single-table" asterisk, that references all fields of given table used
|
|
in the query.
|
|
Example SQL statement:
|
|
\code
|
|
SELECT staff.*, cars.model from staff, cars WHERE staff.car = cars.number;
|
|
\endcode
|
|
The "staff.*" element is our "single-table" asterisk;
|
|
this tells us that we want to get all fields of table "staff".
|
|
|
|
2. "All-tables" asterisk, that references all fields of all tables used in the query.
|
|
Example SQL statement:
|
|
\code
|
|
SELECT * from staff, cars WHERE staff.car = cars.number;
|
|
\endcode
|
|
The "*" is our "all-tables" asterisk;
|
|
this tells us that we want to get all fields of all used tables (here: "staff" and "cars").
|
|
|
|
There can be many asterisks of 1st type defined for given single query.
|
|
There can be one asterisk of 2nd type defined for given single query.
|
|
*/
|
|
class KEXI_DB_EXPORT QueryAsterisk : public Field
|
|
{
|
|
public:
|
|
/*! Constructs query asterisk definition object.
|
|
Pass table schema to \a table if this asterisk should be
|
|
of type "single-table", otherwise (if you want to define
|
|
"all-tables" type asterisk), omit this parameter.
|
|
|
|
QueryAsterisk objects are owned by QuerySchema object
|
|
(not by TableSchema object like for ordinary Field objects)
|
|
for that the QueryAsterisk object was added (using QuerySchema::addField()).
|
|
*/
|
|
QueryAsterisk( QuerySchema *query, TableSchema *table = 0 );
|
|
|
|
virtual ~QueryAsterisk();
|
|
|
|
/*! \return Query object for that this asterisk object is defined */
|
|
QuerySchema *query() const { return static_cast<QuerySchema*>(m_parent); }
|
|
|
|
/*! \return Table schema for this asterisk
|
|
if it has "single-table" type (1st type)
|
|
or NULL if it has "all-tables" type (2nd type) defined. */
|
|
virtual TableSchema* table() const { return m_table; }
|
|
|
|
/*! Sets table schema for this asterisk.
|
|
\a table may be NULL - then the asterisk becames "all-tables" type asterisk. */
|
|
virtual void setTable(TableSchema *table);
|
|
|
|
/*! Reimplemented. */
|
|
virtual bool isQueryAsterisk() const { return true; }
|
|
|
|
/*! This is convenience method that returns true
|
|
if the asterisk has "all-tables" type (2nd type).*/
|
|
bool isSingleTableAsterisk() const { return m_table!=NULL; }
|
|
|
|
/*! This is convenience method that returns true
|
|
if the asterisk has "single-tables" type (2nd type).*/
|
|
bool isAllTableAsterisk() const { return m_table==NULL; }
|
|
|
|
/*! \return String for debugging purposes. */
|
|
virtual QString debugString() const;
|
|
|
|
protected:
|
|
//! \return a deep copy of this object. Used in FieldList(const FieldList& fl).
|
|
virtual Field* copy() const;
|
|
|
|
/*! Table schema for this asterisk */
|
|
TableSchema* m_table;
|
|
|
|
friend class QuerySchema;
|
|
};
|
|
|
|
} //namespace KexiDB
|
|
|
|
#endif
|