diff options
Diffstat (limited to 'connectivity/inc/connectivity/sqlnode.hxx')
-rw-r--r-- | connectivity/inc/connectivity/sqlnode.hxx | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/connectivity/inc/connectivity/sqlnode.hxx b/connectivity/inc/connectivity/sqlnode.hxx new file mode 100644 index 000000000000..fa283cb5cf04 --- /dev/null +++ b/connectivity/inc/connectivity/sqlnode.hxx @@ -0,0 +1,472 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * 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. + * + * 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). + * + * 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. + * + ************************************************************************/ +#ifndef _CONNECTIVITY_SQLNODE_HXX +#define _CONNECTIVITY_SQLNODE_HXX + +#include "connectivity/dbtoolsdllapi.hxx" +#include "connectivity/dbmetadata.hxx" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <vector> +#include <functional> +#include <set> +#include <boost/shared_ptr.hpp> +#include <rtl/ustrbuf.hxx> + +// forward declarations +namespace com +{ + namespace sun + { + namespace star + { + namespace beans + { + class XPropertySet; + } + namespace util + { + class XNumberFormatter; + } + namespace container + { + class XNameAccess; + } + } + } +} + +namespace rtl +{ + class OUStringBuffer; +} + +namespace connectivity +{ + class OSQLParser; + class OSQLParseNode; + class IParseContext; + + 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}; + + typedef ::std::set< ::rtl::OUString > QueryNameSet; + //================================================================== + //= SQLParseNodeParameter + //================================================================== + struct OOO_DLLPUBLIC_DBTOOLS 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(); + }; + + //========================================================================== + //= OSQLParseNode + //========================================================================== + class OOO_DLLPUBLIC_DBTOOLS OSQLParseNode + { + friend class OSQLParser; + + OSQLParseNodes m_aChildren; + OSQLParseNode* m_pParent; // pParent fuer Reuckverkettung im Baum + ::rtl::OUString m_aNodeValue; // Token-Name oder leer bei Regeln oder ::rtl::OUString bei + // ::rtl::OUString, INT, usw. -Werten + 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, + catalog_name, + schema_name, + 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, + boolean_factor, + sql_not, + 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, + 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, + datetime_primary, + concatenation, + char_factor, + bit_value_fct, + comparison_predicate_part_2, + parenthesized_boolean_value_expression, + character_string_type, + other_like_predicate_part_2, + between_predicate_part_2, + rule_count, // letzter_wert + UNKNOWN_RULE // ID indicating that a node is no rule with a matching Rule-enum value (see getKnownRuleID) + }; + + // must be ascii encoding for the value + OSQLParseNode(const sal_Char* _pValueStr, + SQLNodeType _eNodeType, + sal_uInt32 _nNodeID = 0); + + OSQLParseNode(const ::rtl::OString& _rValue, + SQLNodeType eNewNodeType, + sal_uInt32 nNewNodeID=0); + + OSQLParseNode(const sal_Unicode* _pValue, + SQLNodeType _eNodeType, + sal_uInt32 _nNodeID = 0); + + OSQLParseNode(const ::rtl::OUString& _rValue, + 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_aChildren.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); + + void replaceNodeValue(const ::rtl::OUString& rTableAlias,const ::rtl::OUString& rColumnName); + + /** 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; + + void parseNodeToStr(::rtl::OUString& rString, + const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, + const IParseContext* pContext = NULL, + sal_Bool _bIntl = sal_False, + sal_Bool _bQuote= sal_True) const; + + // quoted und internationalisert + void parseNodeToPredicateStr(::rtl::OUString& rString, + 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::lang::Locale& rIntl, + sal_Char _cDec, + const IParseContext* pContext = NULL ) const; + + void parseNodeToPredicateStr(::rtl::OUString& rString, + 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& rIntl, + sal_Char _cDec, + const IParseContext* pContext = NULL ) const; + + OSQLParseNode* getByRule(OSQLParseNode::Rule eRule) const; + +#if OSL_DEBUG_LEVEL > 0 + // zeigt den ParseTree mit tabs und linefeeds + void showParseTree( ::rtl::OUString& rString ) const; + void showParseTree( ::rtl::OUStringBuffer& _inout_rBuf, sal_uInt32 nLevel ) const; +#endif + + // 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; + + // 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 + const ::rtl::OUString& getTokenValue() const {return m_aNodeValue;} + + // SetTokenValue setzt den NodeValue + void setTokenValue(const ::rtl::OUString& rString) { if (isToken()) m_aNodeValue = rString;} + + // IsLeaf testet ob ein Node ein Blatt ist + sal_Bool isLeaf() const {return m_aChildren.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); + // 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 + ,const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData >& _xMetaData); + + // 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); + + protected: + // ParseNodeToStr konkateniert alle Token (Blaetter) des ParseNodes + void parseNodeToStr(::rtl::OUString& rString, + 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& rIntl, + const IParseContext* pContext, + bool _bIntl, + bool _bQuote, + sal_Char _cDecSep, + bool _bPredicate, + bool _bSubstitute) const; + + private: + void impl_parseNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const; + void impl_parseLikeNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const; + void impl_parseTableRangeNodeToString_throw( ::rtl::OUStringBuffer& 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::OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const; + + sal_Bool addDateValue(::rtl::OUStringBuffer& 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::OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const; + }; + + //----------------------------------------------------------------------------- + inline OSQLParseNode* OSQLParseNode::getChild(sal_uInt32 nPos) const + { + OSL_ENSURE(nPos < m_aChildren.size(), "Invalid Position"); + + // return m_aChildren[nPos]; + return m_aChildren.at(nPos); + } + + // Utility-Methoden zum Abfragen auf bestimmte Rules, Token oder Punctuation: + #define SQL_ISRULE(pParseNode, eRule) ((pParseNode)->isRule() && (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::eRule)) + #define SQL_ISTOKEN(pParseNode, token) ((pParseNode)->isToken() && (pParseNode)->getTokenID() == SQL_TOKEN_##token) + #define SQL_ISPUNCTUATION(pParseNode, aString) ((pParseNode)->getNodeType() == SQL_NODE_PUNCTUATION && !(pParseNode)->getTokenValue().compareToAscii(aString)) +} + +#endif //_CONNECTIVITY_SQLNODE_HXX |