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