1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #ifndef _CONNECTIVITY_SQLNODE_HXX 28 #define _CONNECTIVITY_SQLNODE_HXX 29 30 #include "connectivity/dbtoolsdllapi.hxx" 31 #include "connectivity/dbmetadata.hxx" 32 #include <com/sun/star/uno/Reference.hxx> 33 #include <com/sun/star/util/XNumberFormatTypes.hpp> 34 #include <com/sun/star/beans/XPropertySet.hpp> 35 #include <vector> 36 #include <functional> 37 #include <set> 38 #include <boost/shared_ptr.hpp> 39 #include <rtl/ustrbuf.hxx> 40 41 // forward declarations 42 namespace com 43 { 44 namespace sun 45 { 46 namespace star 47 { 48 namespace beans 49 { 50 class XPropertySet; 51 } 52 namespace util 53 { 54 class XNumberFormatter; 55 } 56 namespace container 57 { 58 class XNameAccess; 59 } 60 } 61 } 62 } 63 64 namespace rtl 65 { 66 class OUStringBuffer; 67 } 68 #define ORDER_BY_CHILD_POS 5 69 #define TABLE_EXPRESSION_CHILD_COUNT 9 70 71 namespace connectivity 72 { 73 class OSQLParser; 74 class OSQLParseNode; 75 class IParseContext; 76 77 typedef ::std::vector< OSQLParseNode* > OSQLParseNodes; 78 79 enum SQLNodeType {SQL_NODE_RULE, SQL_NODE_LISTRULE, SQL_NODE_COMMALISTRULE, 80 SQL_NODE_KEYWORD, SQL_NODE_COMPARISON, SQL_NODE_NAME, 81 SQL_NODE_STRING, SQL_NODE_INTNUM, SQL_NODE_APPROXNUM, 82 SQL_NODE_EQUAL,SQL_NODE_LESS,SQL_NODE_GREAT,SQL_NODE_LESSEQ,SQL_NODE_GREATEQ,SQL_NODE_NOTEQUAL, 83 SQL_NODE_PUNCTUATION, SQL_NODE_AMMSC, SQL_NODE_ACCESS_DATE,SQL_NODE_DATE,SQL_NODE_CONCAT}; 84 85 typedef ::std::set< ::rtl::OUString > QueryNameSet; 86 //================================================================== 87 //= SQLParseNodeParameter 88 //================================================================== 89 struct OOO_DLLPUBLIC_DBTOOLS SQLParseNodeParameter 90 { 91 const ::com::sun::star::lang::Locale& rLocale; 92 ::dbtools::DatabaseMetaData aMetaData; 93 OSQLParser* pParser; 94 ::boost::shared_ptr< QueryNameSet > pSubQueryHistory; 95 ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > xFormatter; 96 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xField; 97 ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > xQueries; // see bParseToSDBCLevel 98 const IParseContext& m_rContext; 99 sal_Char cDecSep; 100 bool bQuote : 1; /// should we quote identifiers? 101 bool bInternational : 1; /// should we internationalize keywords and placeholders? 102 bool bPredicate : 1; /// are we going to parse a mere predicate? 103 bool bParseToSDBCLevel : 1; /// should we create an SDBC-level statement (e.g. with substituted sub queries)? 104 105 SQLParseNodeParameter( 106 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 107 const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >& _xFormatter, 108 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _xField, 109 const ::com::sun::star::lang::Locale& _rLocale, 110 const IParseContext* _pContext, 111 bool _bIntl, 112 bool _bQuote, 113 sal_Char _cDecSep, 114 bool _bPredicate, 115 bool _bParseToSDBC 116 ); 117 ~SQLParseNodeParameter(); 118 }; 119 120 //========================================================================== 121 //= OSQLParseNode 122 //========================================================================== 123 class OOO_DLLPUBLIC_DBTOOLS OSQLParseNode 124 { 125 friend class OSQLParser; 126 127 OSQLParseNodes m_aChildren; 128 OSQLParseNode* m_pParent; // pParent fuer Reuckverkettung im Baum 129 ::rtl::OUString m_aNodeValue; // Token-Name oder leer bei Regeln oder ::rtl::OUString bei 130 // ::rtl::OUString, INT, usw. -Werten 131 SQLNodeType m_eNodeType; // s. o. 132 sal_uInt32 m_nNodeID; // ::com::sun::star::chaos::Rule ID (bei IsRule()) oder Token ID (bei !IsRule()) 133 // ::com::sun::star::chaos::Rule IDs und Token IDs koennen nicht anhand des Wertes 134 // unterschieden werden, dafuer ist IsRule() abzufragen! 135 public: 136 enum Rule 137 { 138 select_statement = 0, 139 table_exp, 140 table_ref_commalist, 141 table_ref, 142 catalog_name, 143 schema_name, 144 table_name, 145 opt_column_commalist, 146 column_commalist, 147 column_ref_commalist, 148 column_ref, 149 opt_order_by_clause, 150 ordering_spec_commalist, 151 ordering_spec, 152 opt_asc_desc, 153 where_clause, 154 opt_where_clause, 155 search_condition, 156 comparison_predicate, 157 between_predicate, 158 like_predicate, 159 opt_escape, 160 test_for_null, 161 scalar_exp_commalist, 162 scalar_exp, 163 parameter_ref, 164 parameter, 165 general_set_fct, 166 range_variable, 167 column, 168 delete_statement_positioned, 169 delete_statement_searched, 170 update_statement_positioned, 171 update_statement_searched, 172 assignment_commalist, 173 assignment, 174 values_or_query_spec, 175 insert_statement, 176 insert_atom_commalist, 177 insert_atom, 178 predicate_check, 179 from_clause, 180 qualified_join, 181 cross_union, 182 select_sublist, 183 derived_column, 184 column_val, 185 set_fct_spec, 186 boolean_term, 187 boolean_primary, 188 num_value_exp, 189 join_type, 190 position_exp, 191 extract_exp, 192 length_exp, 193 char_value_fct, 194 odbc_call_spec, 195 in_predicate, 196 existence_test, 197 unique_test, 198 all_or_any_predicate, 199 named_columns_join, 200 join_condition, 201 joined_table, 202 boolean_factor, 203 sql_not, 204 boolean_test, 205 manipulative_statement, 206 subquery, 207 value_exp_commalist, 208 odbc_fct_spec, 209 union_statement, 210 outer_join_type, 211 char_value_exp, 212 term, 213 value_exp_primary, 214 value_exp, 215 selection, 216 fold, 217 char_substring_fct, 218 factor, 219 base_table_def, 220 base_table_element_commalist, 221 data_type, 222 column_def, 223 table_node, 224 as, 225 op_column_commalist, 226 table_primary_as_range_column, 227 datetime_primary, 228 concatenation, 229 char_factor, 230 bit_value_fct, 231 comparison_predicate_part_2, 232 parenthesized_boolean_value_expression, 233 character_string_type, 234 other_like_predicate_part_2, 235 between_predicate_part_2, 236 cast_spec, 237 rule_count, // letzter_wert 238 UNKNOWN_RULE // ID indicating that a node is no rule with a matching Rule-enum value (see getKnownRuleID) 239 }; 240 241 // must be ascii encoding for the value 242 OSQLParseNode(const sal_Char* _pValueStr, 243 SQLNodeType _eNodeType, 244 sal_uInt32 _nNodeID = 0); 245 246 OSQLParseNode(const ::rtl::OString& _rValue, 247 SQLNodeType eNewNodeType, 248 sal_uInt32 nNewNodeID=0); 249 250 OSQLParseNode(const sal_Unicode* _pValue, 251 SQLNodeType _eNodeType, 252 sal_uInt32 _nNodeID = 0); 253 254 OSQLParseNode(const ::rtl::OUString& _rValue, 255 SQLNodeType _eNodeType, 256 sal_uInt32 _nNodeID = 0); 257 258 // Kopiert den entsprechenden ParseNode 259 OSQLParseNode(const OSQLParseNode& rParseNode); 260 OSQLParseNode& operator=(const OSQLParseNode& rParseNode); 261 262 sal_Bool operator==(OSQLParseNode& rParseNode) const; 263 264 // Destruktor raeumt rekursiv den Baum ab 265 virtual ~OSQLParseNode(); 266 267 // Parent gibt den Zeiger auf den Parent zurueck 268 OSQLParseNode* getParent() const {return m_pParent;}; 269 270 // SetParent setzt den Parent-Zeiger eines ParseNodes 271 void setParent(OSQLParseNode* pParseNode) {m_pParent = pParseNode;}; 272 273 // ChildCount liefert die Anzahl der Kinder eines Knotens 274 sal_uInt32 count() const {return m_aChildren.size();}; 275 inline OSQLParseNode* getChild(sal_uInt32 nPos) const; 276 277 void append(OSQLParseNode* pNewSubTree); 278 void insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree); 279 280 OSQLParseNode* replaceAt(sal_uInt32 nPos, OSQLParseNode* pNewSubTree); 281 OSQLParseNode* replace(OSQLParseNode* pOldSubTree, OSQLParseNode* pNewSubTree); 282 283 OSQLParseNode* removeAt(sal_uInt32 nPos); 284 OSQLParseNode* remove(OSQLParseNode* pSubTree); 285 286 void replaceNodeValue(const ::rtl::OUString& rTableAlias,const ::rtl::OUString& rColumnName); 287 288 /** parses the node to a string which can be passed to a driver's connection for execution 289 290 Any particles of the parse tree which represent application-level features - such 291 as queries appearing in the FROM part - are subsituted, so that the resulting statement can 292 be executed at an SDBC-level connection. 293 294 @param _out_rString 295 is an output parameter taking the resulting SQL statement 296 297 @param _rxConnection 298 the connection relative to which to parse. This must be an SDB-level connection (e.g. 299 support the XQueriesSupplier interface) for the method to be able to do all necessary 300 substitutions. 301 302 @param _rParser 303 the SQLParser used to create the node. This is needed in case we need to parse 304 sub queries which are present in the SQL statement - those sub queries need to be parsed, 305 too, to check whether they contain nested sub queries. 306 307 @param _pErrorHolder 308 takes the error which occured while generating the statement, if any. Might be <NULL/>, 309 in this case the error is not reported back, and can only be recognized by examing the 310 return value. 311 312 @return 313 <TRUE/> if and only if the parsing was successful.<br/> 314 315 Currently, there's only one condition how this method can fail: If it contains a nested 316 query which causes a cycle. E.g., consider a statement <code>SELECT * from "foo"</code>, 317 where <code>bar </code> is a query defined as <code>SELECT * FROM "bar"</code>, where 318 <code>bar</code> is defined as <code>SELECT * FROM "foo"</code>. This statement obviously 319 cannot be parsed to an executable statement. 320 321 If this method returns <FALSE/>, you're encouraged to check and handle the error in 322 <arg>_pErrorHolder</arg>. 323 */ 324 bool parseNodeToExecutableStatement( ::rtl::OUString& _out_rString, 325 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 326 OSQLParser& _rParser, 327 ::com::sun::star::sdbc::SQLException* _pErrorHolder ) const; 328 329 void parseNodeToStr(::rtl::OUString& rString, 330 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 331 const IParseContext* pContext = NULL, 332 sal_Bool _bIntl = sal_False, 333 sal_Bool _bQuote= sal_True) const; 334 335 // quoted und internationalisert 336 void parseNodeToPredicateStr(::rtl::OUString& rString, 337 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 338 const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter, 339 const ::com::sun::star::lang::Locale& rIntl, 340 sal_Char _cDec, 341 const IParseContext* pContext = NULL ) const; 342 343 void parseNodeToPredicateStr(::rtl::OUString& rString, 344 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 345 const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter, 346 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & _xField, 347 const ::com::sun::star::lang::Locale& rIntl, 348 sal_Char _cDec, 349 const IParseContext* pContext = NULL ) const; 350 351 OSQLParseNode* getByRule(OSQLParseNode::Rule eRule) const; 352 353 #if OSL_DEBUG_LEVEL > 0 354 // zeigt den ParseTree mit tabs und linefeeds 355 void showParseTree( ::rtl::OUString& rString ) const; 356 void showParseTree( ::rtl::OUStringBuffer& _inout_rBuf, sal_uInt32 nLevel ) const; 357 #endif 358 359 // GetNodeType gibt den Knotentyp zurueck 360 SQLNodeType getNodeType() const {return m_eNodeType;}; 361 362 // RuleId liefert die RuleId der Regel des Knotens (nur bei IsRule()) 363 sal_uInt32 getRuleID() const {return m_nNodeID;} 364 365 /** returns the ID of the rule represented by the node 366 367 If the node does not represent a rule, UNKNOWN_RULE is returned 368 */ 369 Rule getKnownRuleID() const; 370 371 // RuleId liefert die TokenId des Tokens des Knotens (nur bei ! IsRule()) 372 sal_uInt32 getTokenID() const {return m_nNodeID;} 373 374 // IsRule testet ob ein Node eine Regel (NonTerminal) ist 375 // Achtung : Regeln koenne auch Blaetter sein, z.B. leere Listen 376 sal_Bool isRule() const 377 { return (m_eNodeType == SQL_NODE_RULE) || (m_eNodeType == SQL_NODE_LISTRULE) 378 || (m_eNodeType == SQL_NODE_COMMALISTRULE);} 379 380 // IsToken testet ob ein Node ein Token (Terminal) ist 381 sal_Bool isToken() const {return !isRule();} // ein Token ist keine Regel 382 383 // TokenValue liefert den NodeValue eines Tokens 384 const ::rtl::OUString& getTokenValue() const {return m_aNodeValue;} 385 386 // SetTokenValue setzt den NodeValue 387 void setTokenValue(const ::rtl::OUString& rString) { if (isToken()) m_aNodeValue = rString;} 388 389 // IsLeaf testet ob ein Node ein Blatt ist 390 sal_Bool isLeaf() const {return m_aChildren.empty();} 391 392 // negate only a searchcondition, any other rule could cause a gpf 393 static void negateSearchCondition(OSQLParseNode*& pSearchCondition,sal_Bool bNegate=sal_False); 394 395 // normalize a logic form 396 // e.q. (a or b) and (c or d) <=> a and c or a and d or b and c or b and d 397 static void disjunctiveNormalForm(OSQLParseNode*& pSearchCondition); 398 399 // Simplies logic expressions 400 // a * a = a 401 // a + a = a 402 // a * ( a + b) = a 403 // a + a * b = a 404 static void absorptions(OSQLParseNode*& pSearchCondition); 405 406 // erase not nessary braces 407 static void eraseBraces(OSQLParseNode*& pSearchCondition); 408 409 // makes the logic formula a little more smaller 410 static void compress(OSQLParseNode*& pSearchCondition); 411 // return the catalog, schema and tablename form this node 412 // _pTableNode must be a rule of that above or a SQL_TOKEN_NAME 413 static sal_Bool getTableComponents(const OSQLParseNode* _pTableNode, 414 ::com::sun::star::uno::Any &_rCatalog, 415 ::rtl::OUString &_rSchema, 416 ::rtl::OUString &_rTable 417 ,const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XDatabaseMetaData >& _xMetaData); 418 419 // susbtitute all occurences of :var or [name] into the dynamic parameter ? 420 // _pNode will be modified if parameters exists 421 static void substituteParameterNames(OSQLParseNode* _pNode); 422 423 /** return a table range when it exists. 424 */ 425 static ::rtl::OUString getTableRange(const OSQLParseNode* _pTableRef); 426 427 protected: 428 // ParseNodeToStr konkateniert alle Token (Blaetter) des ParseNodes 429 void parseNodeToStr(::rtl::OUString& rString, 430 const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _rxConnection, 431 const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter > & xFormatter, 432 const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > & _xField, 433 const ::com::sun::star::lang::Locale& rIntl, 434 const IParseContext* pContext, 435 bool _bIntl, 436 bool _bQuote, 437 sal_Char _cDecSep, 438 bool _bPredicate, 439 bool _bSubstitute) const; 440 441 private: 442 void impl_parseNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const; 443 void impl_parseLikeNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const; 444 void impl_parseTableRangeNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const; 445 446 /** parses a table_name node into a SQL statement particle. 447 @return 448 <TRUE/> if and only if parsing was successful, <FALSE/> if default handling should 449 be applied. 450 */ 451 bool impl_parseTableNameNodeToString_throw( ::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const; 452 453 sal_Bool addDateValue(::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const; 454 ::rtl::OUString convertDateTimeString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const; 455 ::rtl::OUString convertDateString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const; 456 ::rtl::OUString convertTimeString(const SQLParseNodeParameter& rParam, const ::rtl::OUString& rString) const; 457 void parseLeaf(::rtl::OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const; 458 }; 459 460 //----------------------------------------------------------------------------- 461 inline OSQLParseNode* OSQLParseNode::getChild(sal_uInt32 nPos) const 462 { 463 OSL_ENSURE(nPos < m_aChildren.size(), "Invalid Position"); 464 465 // return m_aChildren[nPos]; 466 return m_aChildren.at(nPos); 467 } 468 469 // Utility-Methoden zum Abfragen auf bestimmte Rules, Token oder Punctuation: 470 #define SQL_ISRULE(pParseNode, eRule) ((pParseNode)->isRule() && (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::eRule)) 471 #define SQL_ISTOKEN(pParseNode, token) ((pParseNode)->isToken() && (pParseNode)->getTokenID() == SQL_TOKEN_##token) 472 #define SQL_ISPUNCTUATION(pParseNode, aString) ((pParseNode)->getNodeType() == SQL_NODE_PUNCTUATION && !(pParseNode)->getTokenValue().compareToAscii(aString)) 473 } 474 475 #endif //_CONNECTIVITY_SQLNODE_HXX 476