Files
libreoffice/connectivity/inc/connectivity/sqlnode.hxx

458 lines
20 KiB
C++
Raw Normal View History

2000-09-18 15:18:56 +00:00
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2000-09-18 15:18:56 +00:00
*
* Copyright 2008 by Sun Microsystems, Inc.
2000-09-18 15:18:56 +00:00
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 15:18:56 +00:00
*
* $RCSfile: sqlnode.hxx,v $
* $Revision: 1.24 $
2000-09-18 15:18:56 +00:00
*
* This file is part of OpenOffice.org.
2000-09-18 15:18:56 +00:00
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
2000-09-18 15:18:56 +00:00
*
* OpenOffice.org 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 Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
2000-09-18 15:18:56 +00:00
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
2000-09-18 15:18:56 +00:00
*
************************************************************************/
#ifndef _CONNECTIVITY_SQLNODE_HXX
#define _CONNECTIVITY_SQLNODE_HXX
#include "connectivity/dbmetadata.hxx"
#include <com/sun/star/uno/Reference.hxx>
2000-09-18 15:18:56 +00:00
#include <com/sun/star/util/XNumberFormatTypes.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
2000-11-22 15:51:52 +00:00
#include <vector>
#include <functional>
#include <set>
#include <boost/shared_ptr.hpp>
2000-09-18 15:18:56 +00:00
// forward declarations
namespace com
{
namespace sun
{
namespace star
{
namespace beans
{
class XPropertySet;
}
namespace util
{
class XNumberFormatter;
}
namespace container
{
class XNameAccess;
}
2000-09-18 15:18:56 +00:00
}
}
}
namespace connectivity
{
class OSQLParser;
2000-09-18 15:18:56 +00:00
class OSQLParseNode;
2002-09-27 10:01:52 +00:00
class IParseContext;
2000-09-18 15:18:56 +00:00
typedef ::std::vector< OSQLParseNode* > OSQLParseNodes;
enum SQLNodeType {SQL_NODE_RULE, SQL_NODE_LISTRULE, SQL_NODE_COMMALISTRULE,
SQL_NODE_KEYWORD, SQL_NODE_COMPARISON, SQL_NODE_NAME,
SQL_NODE_STRING, SQL_NODE_INTNUM, SQL_NODE_APPROXNUM,
SQL_NODE_EQUAL,SQL_NODE_LESS,SQL_NODE_GREAT,SQL_NODE_LESSEQ,SQL_NODE_GREATEQ,SQL_NODE_NOTEQUAL,
SQL_NODE_PUNCTUATION, SQL_NODE_AMMSC, SQL_NODE_ACCESS_DATE,SQL_NODE_DATE,SQL_NODE_CONCAT};
2000-09-18 15:18:56 +00:00
typedef ::std::set< ::rtl::OUString > QueryNameSet;
//==================================================================
//= SQLParseNodeParameter
//==================================================================
struct SQLParseNodeParameter
{
const ::com::sun::star::lang::Locale& rLocale;
::dbtools::DatabaseMetaData aMetaData;
OSQLParser* pParser;
::boost::shared_ptr< QueryNameSet > pSubQueryHistory;
::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > xFormatter;
::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xField;
::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > xQueries; // see bParseToSDBCLevel
const IParseContext& m_rContext;
sal_Char cDecSep;
bool bQuote : 1; /// should we quote identifiers?
bool bInternational : 1; /// should we internationalize keywords and placeholders?
bool bPredicate : 1; /// are we going to parse a mere predicate?
bool bParseToSDBCLevel : 1; /// should we create an SDBC-level statement (e.g. with substituted sub queries)?
SQLParseNodeParameter(
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >& _xFormatter,
const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _xField,
const ::com::sun::star::lang::Locale& _rLocale,
const IParseContext* _pContext,
bool _bIntl,
bool _bQuote,
sal_Char _cDecSep,
bool _bPredicate,
bool _bParseToSDBC
);
~SQLParseNodeParameter();
};
2000-09-18 15:18:56 +00:00
//==========================================================================
//= OSQLParseNode
//==========================================================================
class OSQLParseNode
{
friend class OSQLParser;
OSQLParseNodes m_aChilds;
OSQLParseNode* m_pParent; // pParent fuer Reuckverkettung im Baum
2000-10-19 10:47:14 +00:00
::rtl::OUString m_aNodeValue; // Token-Name oder leer bei Regeln oder ::rtl::OUString bei
// ::rtl::OUString, INT, usw. -Werten
2000-09-18 15:18:56 +00:00
SQLNodeType m_eNodeType; // s. o.
sal_uInt32 m_nNodeID; // ::com::sun::star::chaos::Rule ID (bei IsRule()) oder Token ID (bei !IsRule())
// ::com::sun::star::chaos::Rule IDs und Token IDs koennen nicht anhand des Wertes
// unterschieden werden, dafuer ist IsRule() abzufragen!
public:
enum Rule
{
select_statement = 0,
table_exp,
table_ref_commalist,
table_ref,
2001-01-09 12:11:07 +00:00
catalog_name,
schema_name,
2000-09-18 15:18:56 +00:00
table_name,
opt_column_commalist,
column_commalist,
column_ref_commalist,
column_ref,
opt_order_by_clause,
ordering_spec_commalist,
ordering_spec,
opt_asc_desc,
where_clause,
opt_where_clause,
search_condition,
comparison_predicate,
between_predicate,
like_predicate,
opt_escape,
test_for_null,
scalar_exp_commalist,
scalar_exp,
parameter_ref,
parameter,
general_set_fct,
range_variable,
column,
delete_statement_positioned,
delete_statement_searched,
update_statement_positioned,
update_statement_searched,
assignment_commalist,
assignment,
values_or_query_spec,
insert_statement,
insert_atom_commalist,
insert_atom,
predicate_check,
from_clause,
qualified_join,
cross_union,
select_sublist,
derived_column,
column_val,
set_fct_spec,
boolean_term,
boolean_primary,
num_value_exp,
join_type,
position_exp,
extract_exp,
length_exp,
char_value_fct,
odbc_call_spec,
in_predicate,
existence_test,
unique_test,
all_or_any_predicate,
named_columns_join,
join_condition,
joined_table,
2000-09-18 15:18:56 +00:00
boolean_factor,
sql_not,
2000-09-18 15:18:56 +00:00
boolean_test,
manipulative_statement,
subquery,
value_exp_commalist,
odbc_fct_spec,
union_statement,
outer_join_type,
char_value_exp,
term,
value_exp_primary,
value_exp,
2002-07-15 06:14:04 +00:00
selection,
fold,
char_substring_fct,
factor,
base_table_def,
base_table_element_commalist,
data_type,
column_def,
table_node,
as,
op_column_commalist,
table_primary_as_range_column,
rule_count, // letzter_wert
UNKNOWN_RULE // ID indicating that a node is no rule with a matching Rule-enum value (see getKnownRuleID)
2000-09-18 15:18:56 +00:00
};
// must be ascii encoding for the value
OSQLParseNode(const sal_Char* _pValueStr,
SQLNodeType _eNodeType,
sal_uInt32 _nNodeID = 0);
2000-10-19 10:47:14 +00:00
OSQLParseNode(const ::rtl::OString& _rValue,
2000-09-18 15:18:56 +00:00
SQLNodeType eNewNodeType,
sal_uInt32 nNewNodeID=0);
OSQLParseNode(const sal_Unicode* _pValue,
SQLNodeType _eNodeType,
sal_uInt32 _nNodeID = 0);
2000-10-19 10:47:14 +00:00
OSQLParseNode(const ::rtl::OUString& _rValue,
2000-09-18 15:18:56 +00:00
SQLNodeType _eNodeType,
sal_uInt32 _nNodeID = 0);
// Kopiert den entsprechenden ParseNode
OSQLParseNode(const OSQLParseNode& rParseNode);
OSQLParseNode& operator=(const OSQLParseNode& rParseNode);
sal_Bool operator==(OSQLParseNode& rParseNode) const;
// Destruktor raeumt rekursiv den Baum ab
virtual ~OSQLParseNode();
// Parent gibt den Zeiger auf den Parent zurueck
OSQLParseNode* getParent() const {return m_pParent;};
// SetParent setzt den Parent-Zeiger eines ParseNodes
void setParent(OSQLParseNode* pParseNode) {m_pParent = pParseNode;};
// ChildCount liefert die Anzahl der Kinder eines Knotens
sal_uInt32 count() const {return m_aChilds.size();};
inline OSQLParseNode* getChild(sal_uInt32 nPos) const;
void append(OSQLParseNode* pNewSubTree);
void insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree);
OSQLParseNode* replaceAt(sal_uInt32 nPos, OSQLParseNode* pNewSubTree);
OSQLParseNode* replace(OSQLParseNode* pOldSubTree, OSQLParseNode* pNewSubTree);
OSQLParseNode* removeAt(sal_uInt32 nPos);
OSQLParseNode* remove(OSQLParseNode* pSubTree);
2000-10-19 10:47:14 +00:00
void replaceNodeValue(const ::rtl::OUString& rTableAlias,const ::rtl::OUString& rColumnName);
2000-09-18 15:18:56 +00:00
/** parses the node to a string which can be passed to a driver's connection for execution
Any particles of the parse tree which represent application-level features - such
as queries appearing in the FROM part - are subsituted, so that the resulting statement can
be executed at an SDBC-level connection.
@param _out_rString
is an output parameter taking the resulting SQL statement
@param _rxConnection
the connection relative to which to parse. This must be an SDB-level connection (e.g.
support the XQueriesSupplier interface) for the method to be able to do all necessary
substitutions.
@param _rParser
the SQLParser used to create the node. This is needed in case we need to parse
sub queries which are present in the SQL statement - those sub queries need to be parsed,
too, to check whether they contain nested sub queries.
@param _pErrorHolder
takes the error which occured while generating the statement, if any. Might be <NULL/>,
in this case the error is not reported back, and can only be recognized by examing the
return value.
@return
<TRUE/> if and only if the parsing was successful.<br/>
Currently, there's only one condition how this method can fail: If it contains a nested
query which causes a cycle. E.g., consider a statement <code>SELECT * from "foo"</code>,
where <code>bar </code> is a query defined as <code>SELECT * FROM "bar"</code>, where
<code>bar</code> is defined as <code>SELECT * FROM "foo"</code>. This statement obviously
cannot be parsed to an executable statement.
If this method returns <FALSE/>, you're encouraged to check and handle the error in
<arg>_pErrorHolder</arg>.
*/
bool parseNodeToExecutableStatement( ::rtl::OUString& _out_rString,
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
OSQLParser& _rParser,
::com::sun::star::sdbc::SQLException* _pErrorHolder ) const;
2000-10-19 10:47:14 +00:00
void parseNodeToStr(::rtl::OUString& rString,
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
2002-09-27 10:01:52 +00:00
const IParseContext* pContext = NULL,
2000-09-18 15:18:56 +00:00
sal_Bool _bIntl = sal_False,
sal_Bool _bQuote= sal_True) const;
// quoted und internationalisert
2000-10-19 10:47:14 +00:00
void parseNodeToPredicateStr(::rtl::OUString& rString,
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
2000-09-18 15:18:56 +00:00
const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter,
2000-10-19 10:47:14 +00:00
const ::com::sun::star::lang::Locale& rIntl,
sal_Char _cDec,
2002-09-27 10:01:52 +00:00
const IParseContext* pContext = NULL ) const;
2000-09-18 15:18:56 +00:00
2000-10-19 10:47:14 +00:00
void parseNodeToPredicateStr(::rtl::OUString& rString,
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
2000-09-18 15:18:56 +00:00
const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter,
const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & _xField,
2000-10-19 10:47:14 +00:00
const ::com::sun::star::lang::Locale& rIntl,
sal_Char _cDec,
2002-09-27 10:01:52 +00:00
const IParseContext* pContext = NULL ) const;
2000-09-18 15:18:56 +00:00
OSQLParseNode* getByRule(OSQLParseNode::Rule eRule) const;
#if OSL_DEBUG_LEVEL > 0
2000-09-18 15:18:56 +00:00
// zeigt den ParseTree mit tabs und linefeeds
2000-10-19 10:47:14 +00:00
void showParseTree(::rtl::OUString& rString, sal_uInt32 nLevel=0);
#endif
2000-09-18 15:18:56 +00:00
// GetNodeType gibt den Knotentyp zurueck
SQLNodeType getNodeType() const {return m_eNodeType;};
// RuleId liefert die RuleId der Regel des Knotens (nur bei IsRule())
sal_uInt32 getRuleID() const {return m_nNodeID;}
/** returns the ID of the rule represented by the node
If the node does not represent a rule, UNKNOWN_RULE is returned
*/
Rule getKnownRuleID() const;
2000-09-18 15:18:56 +00:00
// RuleId liefert die TokenId des Tokens des Knotens (nur bei ! IsRule())
sal_uInt32 getTokenID() const {return m_nNodeID;}
// IsRule testet ob ein Node eine Regel (NonTerminal) ist
// Achtung : Regeln koenne auch Blaetter sein, z.B. leere Listen
sal_Bool isRule() const
{ return (m_eNodeType == SQL_NODE_RULE) || (m_eNodeType == SQL_NODE_LISTRULE)
|| (m_eNodeType == SQL_NODE_COMMALISTRULE);}
// IsToken testet ob ein Node ein Token (Terminal) ist
sal_Bool isToken() const {return !isRule();} // ein Token ist keine Regel
// TokenValue liefert den NodeValue eines Tokens
2000-10-19 10:47:14 +00:00
const ::rtl::OUString& getTokenValue() const {return m_aNodeValue;}
2000-09-18 15:18:56 +00:00
// SetTokenValue setzt den NodeValue
2000-10-19 10:47:14 +00:00
void setTokenValue(const ::rtl::OUString& rString) { if (isToken()) m_aNodeValue = rString;}
2000-09-18 15:18:56 +00:00
// IsLeaf testet ob ein Node ein Blatt ist
sal_Bool isLeaf() const {return m_aChilds.empty();}
// negate only a searchcondition, any other rule could cause a gpf
static void negateSearchCondition(OSQLParseNode*& pSearchCondition,sal_Bool bNegate=sal_False);
// normalize a logic form
// e.q. (a or b) and (c or d) <=> a and c or a and d or b and c or b and d
static void disjunctiveNormalForm(OSQLParseNode*& pSearchCondition);
// Simplies logic expressions
// a * a = a
// a + a = a
// a * ( a + b) = a
// a + a * b = a
static void absorptions(OSQLParseNode*& pSearchCondition);
// erase not nessary braces
static void eraseBraces(OSQLParseNode*& pSearchCondition);
// makes the logic formula a little more smaller
static void compress(OSQLParseNode*& pSearchCondition);
2001-01-09 12:11:07 +00:00
// return the catalog, schema and tablename form this node
// _pTableNode must be a rule of that above or a SQL_TOKEN_NAME
static sal_Bool getTableComponents(const OSQLParseNode* _pTableNode,
::com::sun::star::uno::Any &_rCatalog,
::rtl::OUString &_rSchema,
::rtl::OUString &_rTable);
2000-09-18 15:18:56 +00:00
// susbtitute all occurences of :var or [name] into the dynamic parameter ?
// _pNode will be modified if parameters exists
static void substituteParameterNames(OSQLParseNode* _pNode);
/** return a table range when it exists.
*/
static ::rtl::OUString getTableRange(const OSQLParseNode* _pTableRef);
2000-09-18 15:18:56 +00:00
protected:
// ParseNodeToStr konkateniert alle Token (Blaetter) des ParseNodes
2000-10-19 10:47:14 +00:00
void parseNodeToStr(::rtl::OUString& rString,
const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection,
2000-09-18 15:18:56 +00:00
const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter,
const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & _xField,
2000-10-19 10:47:14 +00:00
const ::com::sun::star::lang::Locale& rIntl,
2002-09-27 10:01:52 +00:00
const IParseContext* pContext,
bool _bIntl,
bool _bQuote,
2000-10-19 10:47:14 +00:00
sal_Char _cDecSep,
bool _bPredicate,
bool _bSubstitute) const;
2000-09-18 15:18:56 +00:00
private:
void impl_parseNodeToString_throw( ::rtl::OUString& rString, const SQLParseNodeParameter& rParam) const;
void impl_parseLikeNodeToString_throw( ::rtl::OUString& rString, const SQLParseNodeParameter& rParam ) const;
void impl_parseTableRangeNodeToString_throw( ::rtl::OUString& rString, const SQLParseNodeParameter& rParam ) const;
/** parses a table_name node into a SQL statement particle.
@return
<TRUE/> if and only if parsing was successful, <FALSE/> if default handling should
be applied.
*/
bool impl_parseTableNameNodeToString_throw( ::rtl::OUString& rString, const SQLParseNodeParameter& rParam ) const;
2000-10-19 10:47:14 +00:00
sal_Bool addDateValue(::rtl::OUString& rString, const SQLParseNodeParameter& rParam) const;
::rtl::OUString convertDateTimeString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const;
::rtl::OUString convertDateString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const;
::rtl::OUString convertTimeString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const;
void parseLeaf(::rtl::OUString & rString, const SQLParseNodeParameter& rParam) const;
2000-09-18 15:18:56 +00:00
};
//-----------------------------------------------------------------------------
inline OSQLParseNode* OSQLParseNode::getChild(sal_uInt32 nPos) const
{
2001-03-20 15:49:26 +00:00
OSL_ENSURE(nPos < m_aChilds.size(), "Invalid Position");
// return m_aChilds[nPos];
return m_aChilds.at(nPos);
2000-09-18 15:18:56 +00:00
}
// Utility-Methoden zum Abfragen auf bestimmte Rules, Token oder Punctuation:
#define SQL_ISRULE(pParseNode, eRule) ((pParseNode)->isRule() && (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::eRule))
2000-09-18 15:18:56 +00:00
#define SQL_ISTOKEN(pParseNode, token) ((pParseNode)->isToken() && (pParseNode)->getTokenID() == SQL_TOKEN_##token)
2000-10-19 10:47:14 +00:00
#define SQL_ISPUNCTUATION(pParseNode, aString) ((pParseNode)->getNodeType() == SQL_NODE_PUNCTUATION && !(pParseNode)->getTokenValue().compareToAscii(aString))
2000-09-18 15:18:56 +00:00
}
#endif //_CONNECTIVITY_SQLNODE_HXX