1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_CONNECTIVITY_SQLNODE_HXX
20 #define INCLUDED_CONNECTIVITY_SQLNODE_HXX
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>
30 #include <boost/shared_ptr.hpp>
31 #include <rtl/ustrbuf.hxx>
33 // forward declarations
46 class XNumberFormatter
;
56 #define ORDER_BY_CHILD_POS 5
57 #define TABLE_EXPRESSION_CHILD_COUNT 9
59 namespace connectivity
65 typedef ::std::vector
< OSQLParseNode
* > OSQLParseNodes
;
67 enum SQLNodeType
{SQL_NODE_RULE
, SQL_NODE_LISTRULE
, SQL_NODE_COMMALISTRULE
,
68 SQL_NODE_KEYWORD
, SQL_NODE_COMPARISON
, SQL_NODE_NAME
,
69 SQL_NODE_STRING
, SQL_NODE_INTNUM
, SQL_NODE_APPROXNUM
,
70 SQL_NODE_EQUAL
,SQL_NODE_LESS
,SQL_NODE_GREAT
,SQL_NODE_LESSEQ
,SQL_NODE_GREATEQ
,SQL_NODE_NOTEQUAL
,
71 SQL_NODE_PUNCTUATION
, SQL_NODE_AMMSC
, SQL_NODE_ACCESS_DATE
,SQL_NODE_DATE
,SQL_NODE_CONCAT
};
73 typedef ::std::set
< OUString
> QueryNameSet
;
74 //==================================================================
75 //= SQLParseNodeParameter
76 //==================================================================
77 struct OOO_DLLPUBLIC_DBTOOLS SQLParseNodeParameter
79 const ::com::sun::star::lang::Locale
& rLocale
;
80 ::dbtools::DatabaseMetaData aMetaData
;
82 ::boost::shared_ptr
< QueryNameSet
> pSubQueryHistory
;
83 ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
> xFormatter
;
84 ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> xField
;
85 OUString sPredicateTableAlias
;
86 ::com::sun::star::uno::Reference
< ::com::sun::star::container::XNameAccess
> xQueries
; // see bParseToSDBCLevel
87 const IParseContext
& m_rContext
;
89 bool bQuote
: 1; /// should we quote identifiers?
90 bool bInternational
: 1; /// should we internationalize keywords and placeholders?
91 bool bPredicate
: 1; /// are we going to parse a mere predicate?
92 bool bParseToSDBCLevel
: 1; /// should we create an SDBC-level statement (e.g. with substituted sub queries)?
94 SQLParseNodeParameter(
95 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
96 const ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
>& _xFormatter
,
97 const ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
>& _xField
,
98 const OUString
&_sPredicateTableAlias
,
99 const ::com::sun::star::lang::Locale
& _rLocale
,
100 const IParseContext
* _pContext
,
107 ~SQLParseNodeParameter();
110 //==========================================================================
112 //==========================================================================
113 class OOO_DLLPUBLIC_DBTOOLS OSQLParseNode
115 friend class OSQLParser
;
117 OSQLParseNodes m_aChildren
;
118 OSQLParseNode
* m_pParent
; // pParent for reverse linkage in the tree
119 OUString m_aNodeValue
; // token name, or empty in case of rules,
120 // or OUString in case of
121 // OUString, INT, etc.
122 SQLNodeType m_eNodeType
; // see above
123 sal_uInt32 m_nNodeID
; // ::com::sun::star::chaos::Rule ID (if IsRule())
124 // or Token ID (if !IsRule())
125 // ::com::sun::star::chaos::Rule IDs and Token IDs can't
126 // be distinguished by their values,
127 // IsRule has to be used for that!
131 UNKNOWN_RULE
= 0, // ID indicating that a node is no rule with a matching Rule-enum value (see getKnownRuleID)
132 // we make sure it is 0 so that it is the default-constructor value of this enum
133 // and std::map<foo,Rule>::operator[](bar) default-inserts UNKNOWN_RULE rather than select_statement (!)
141 opt_column_commalist
,
143 column_ref_commalist
,
146 ordering_spec_commalist
,
153 comparison_predicate
,
158 scalar_exp_commalist
,
165 delete_statement_positioned
,
166 delete_statement_searched
,
167 update_statement_positioned
,
168 update_statement_searched
,
169 assignment_commalist
,
171 values_or_query_spec
,
173 insert_atom_commalist
,
194 all_or_any_predicate
,
200 manipulative_statement
,
215 base_table_element_commalist
,
222 table_primary_as_range_column
,
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
,
234 rule_count
// last value
237 // must be ascii encoding for the value
238 OSQLParseNode(const sal_Char
* _pValueStr
,
239 SQLNodeType _eNodeType
,
240 sal_uInt32 _nNodeID
= 0);
242 OSQLParseNode(const OString
& _rValue
,
243 SQLNodeType eNewNodeType
,
244 sal_uInt32 nNewNodeID
=0);
246 OSQLParseNode(const OUString
& _rValue
,
247 SQLNodeType _eNodeType
,
248 sal_uInt32 _nNodeID
= 0);
250 // copies the respective ParseNode
251 OSQLParseNode(const OSQLParseNode
& rParseNode
);
252 OSQLParseNode
& operator=(const OSQLParseNode
& rParseNode
);
254 sal_Bool
operator==(OSQLParseNode
& rParseNode
) const;
256 // destructor destructs the tree recursively
257 virtual ~OSQLParseNode();
259 OSQLParseNode
* getParent() const {return m_pParent
;};
261 void setParent(OSQLParseNode
* pParseNode
) {m_pParent
= pParseNode
;};
263 size_t count() const {return m_aChildren
.size();};
264 inline OSQLParseNode
* getChild(sal_uInt32 nPos
) const;
266 void append(OSQLParseNode
* pNewSubTree
);
267 void insert(sal_uInt32 nPos
, OSQLParseNode
* pNewSubTree
);
269 OSQLParseNode
* replace(OSQLParseNode
* pOldSubTree
, OSQLParseNode
* pNewSubTree
);
271 OSQLParseNode
* removeAt(sal_uInt32 nPos
);
273 void replaceNodeValue(const OUString
& rTableAlias
,const OUString
& rColumnName
);
275 /** parses the node to a string which can be passed to a driver's connection for execution
277 Any particles of the parse tree which represent application-level features - such
278 as queries appearing in the FROM part - are substituted, so that the resulting statement can
279 be executed at an SDBC-level connection.
282 is an output parameter taking the resulting SQL statement
285 the connection relative to which to parse. This must be an SDB-level connection (e.g.
286 support the XQueriesSupplier interface) for the method to be able to do all necessary
290 the SQLParser used to create the node. This is needed in case we need to parse
291 sub queries which are present in the SQL statement - those sub queries need to be parsed,
292 too, to check whether they contain nested sub queries.
295 takes the error which occurred while generating the statement, if any. Might be <NULL/>,
296 in this case the error is not reported back, and can only be recognized by examing the
300 <TRUE/> if and only if the parsing was successful.<br/>
302 Currently, there's only one condition how this method can fail: If it contains a nested
303 query which causes a cycle. E.g., consider a statement <code>SELECT * from "foo"</code>,
304 where <code>foo</code> is a query defined as <code>SELECT * FROM "bar"</code>, where
305 <code>bar</code> is defined as <code>SELECT * FROM "foo"</code>. This statement obviously
306 cannot be parsed to an executable statement.
308 If this method returns <FALSE/>, you're encouraged to check and handle the error in
309 <arg>_pErrorHolder</arg>.
311 bool parseNodeToExecutableStatement( OUString
& _out_rString
,
312 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
313 OSQLParser
& _rParser
,
314 ::com::sun::star::sdbc::SQLException
* _pErrorHolder
) const;
316 void parseNodeToStr(OUString
& rString
,
317 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
318 const IParseContext
* pContext
= NULL
,
319 bool _bIntl
= sal_False
,
320 bool _bQuote
= sal_True
) const;
322 // quoted and internationalised
323 void parseNodeToPredicateStr(OUString
& rString
,
324 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
325 const ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
> & xFormatter
,
326 const ::com::sun::star::lang::Locale
& rIntl
,
328 const IParseContext
* pContext
= NULL
) const;
330 void parseNodeToPredicateStr(OUString
& rString
,
331 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
332 const ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
> & xFormatter
,
333 const ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> & _xField
,
334 const OUString
&_sTableAlias
,
335 const ::com::sun::star::lang::Locale
& rIntl
,
337 const IParseContext
* pContext
= NULL
) const;
339 OSQLParseNode
* getByRule(OSQLParseNode::Rule eRule
) const;
341 #if OSL_DEBUG_LEVEL > 1
342 // shows the ParseTree with tabs and linefeeds
343 void showParseTree( OUString
& rString
) const;
344 void showParseTree( OUStringBuffer
& _inout_rBuf
, sal_uInt32 nLevel
) const;
347 SQLNodeType
getNodeType() const {return m_eNodeType
;};
349 // RuleId returns the RuleID of the node's rule (only if IsRule())
350 sal_uInt32
getRuleID() const {return m_nNodeID
;}
352 /** returns the ID of the rule represented by the node
353 If the node does not represent a rule, UNKNOWN_RULE is returned
355 Rule
getKnownRuleID() const;
357 // returns the TokenId of the node's token (only if !isRule())
358 sal_uInt32
getTokenID() const {return m_nNodeID
;}
360 // IsRule tests whether a node is a rule (NonTerminal)
361 // ATTENTION: rules can be leaves, for example empty lists
362 sal_Bool
isRule() const
363 { return (m_eNodeType
== SQL_NODE_RULE
) || (m_eNodeType
== SQL_NODE_LISTRULE
)
364 || (m_eNodeType
== SQL_NODE_COMMALISTRULE
);}
366 // IsToken tests whether a Node is a Token (Terminal but not a rule)
367 sal_Bool
isToken() const {return !isRule();}
369 const OUString
& getTokenValue() const {return m_aNodeValue
;}
371 void setTokenValue(const OUString
& rString
) { if (isToken()) m_aNodeValue
= rString
;}
373 sal_Bool
isLeaf() const {return m_aChildren
.empty();}
375 // negate only a searchcondition, any other rule could cause a gpf
376 static void negateSearchCondition(OSQLParseNode
*& pSearchCondition
,sal_Bool bNegate
=sal_False
);
378 // normalize a logic form
379 // e.q. (a or b) and (c or d) <=> a and c or a and d or b and c or b and d
380 static void disjunctiveNormalForm(OSQLParseNode
*& pSearchCondition
);
382 // Simplifies logic expressions
385 // a and ( a + b) = a
387 static void absorptions(OSQLParseNode
*& pSearchCondition
);
389 // erase unnecessary braces
390 static void eraseBraces(OSQLParseNode
*& pSearchCondition
);
392 // makes the logic formula a little smaller
393 static void compress(OSQLParseNode
*& pSearchCondition
);
394 // return the catalog, schema and tablename form this node
395 // _pTableNode must be a rule of that above or a SQL_TOKEN_NAME
396 static sal_Bool
getTableComponents(const OSQLParseNode
* _pTableNode
,
397 ::com::sun::star::uno::Any
&_rCatalog
,
400 ,const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XDatabaseMetaData
>& _xMetaData
);
402 // substitute all occurrences of :var or [name] into the dynamic parameter ?
403 // _pNode will be modified if parameters exists
404 static void substituteParameterNames(OSQLParseNode
* _pNode
);
406 /** return a table range when it exists.
408 static OUString
getTableRange(const OSQLParseNode
* _pTableRef
);
411 // ParseNodeToStr concatenates all Tokens (leaves) of the ParseNodes.
412 void parseNodeToStr(OUString
& rString
,
413 const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XConnection
>& _rxConnection
,
414 const ::com::sun::star::uno::Reference
< ::com::sun::star::util::XNumberFormatter
> & xFormatter
,
415 const ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> & _xField
,
416 const OUString
&_sPredicateTableAlias
,
417 const ::com::sun::star::lang::Locale
& rIntl
,
418 const IParseContext
* pContext
,
423 bool _bSubstitute
) const;
426 void impl_parseNodeToString_throw( OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
, bool bSimple
=true ) const;
427 void impl_parseLikeNodeToString_throw( OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
, bool bSimple
=true ) const;
428 void impl_parseTableRangeNodeToString_throw( OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
) const;
430 /** parses a table_name node into a SQL statement particle.
432 <TRUE/> if and only if parsing was successful, <FALSE/> if default handling should
435 bool impl_parseTableNameNodeToString_throw( OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
) const;
437 sal_Bool
addDateValue(OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
) const;
438 OUString
convertDateTimeString(const SQLParseNodeParameter
& rParam
, const OUString
& rString
) const;
439 OUString
convertDateString(const SQLParseNodeParameter
& rParam
, const OUString
& rString
) const;
440 OUString
convertTimeString(const SQLParseNodeParameter
& rParam
, const OUString
& rString
) const;
441 void parseLeaf(OUStringBuffer
& rString
, const SQLParseNodeParameter
& rParam
) const;
444 //-----------------------------------------------------------------------------
445 inline OSQLParseNode
* OSQLParseNode::getChild(sal_uInt32 nPos
) const
447 OSL_ENSURE(nPos
< m_aChildren
.size(), "Invalid Position");
449 // return m_aChildren[nPos];
450 return m_aChildren
.at(nPos
);
453 // utilities to query for a specific rule, token or punctuation
454 #define SQL_ISRULE(pParseNode, eRule) ((pParseNode)->isRule() && (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::eRule))
455 #define SQL_ISRULEOR2(pParseNode, e1, e2) ((pParseNode)->isRule() && ( \
456 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \
457 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2)))
458 #define SQL_ISRULEOR3(pParseNode, e1, e2, e3) ((pParseNode)->isRule() && ( \
459 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \
460 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2) || \
461 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e3)))
462 #define SQL_ISTOKEN(pParseNode, token) ((pParseNode)->isToken() && (pParseNode)->getTokenID() == SQL_TOKEN_##token)
463 #define SQL_ISTOKENOR2(pParseNode, tok0, tok1) ((pParseNode)->isToken() && ( (pParseNode)->getTokenID() == SQL_TOKEN_##tok0 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok1 ))
464 #define SQL_ISTOKENOR3(pParseNode, tok0, tok1, tok2) ((pParseNode)->isToken() && ( (pParseNode)->getTokenID() == SQL_TOKEN_##tok0 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok1 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok2 ))
465 #define SQL_ISPUNCTUATION(pParseNode, aString) ((pParseNode)->getNodeType() == SQL_NODE_PUNCTUATION && !(pParseNode)->getTokenValue().compareToAscii(aString))
468 #endif // INCLUDED_CONNECTIVITY_SQLNODE_HXX
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */