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 occured 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 occurences 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