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