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