nss: upgrade to release 3.73
[LibreOffice.git] / include / connectivity / sqlnode.hxx
blob7f394ef49de3b9949aad84bab6fad0a37568efb9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <memory>
26 #include <set>
27 #include <vector>
28 #include <rtl/ustrbuf.hxx>
30 namespace com::sun::star::lang { struct Locale; }
31 namespace com::sun::star::sdbc { class SQLException; }
32 namespace com::sun::star::sdbc { class XDatabaseMetaData; }
34 namespace com::sun::star
36 namespace beans
38 class XPropertySet;
40 namespace util
42 class XNumberFormatter;
44 namespace container
46 class XNameAccess;
50 #define ORDER_BY_CHILD_POS 5
51 #define TABLE_EXPRESSION_CHILD_COUNT 9
53 namespace connectivity
55 class OSQLParser;
56 class IParseContext;
58 enum class SQLNodeType { Rule, ListRule, CommaListRule,
59 Keyword, Name,
60 String, IntNum, ApproxNum,
61 Equal, Less, Great, LessEq, GreatEq, NotEqual,
62 Punctuation, AccessDate, Concat};
64 typedef ::std::set< OUString > QueryNameSet;
66 //= SQLParseNodeParameter
68 struct SQLParseNodeParameter
70 const css::lang::Locale& rLocale;
71 ::dbtools::DatabaseMetaData aMetaData;
72 OSQLParser* pParser;
73 std::shared_ptr< QueryNameSet > pSubQueryHistory;
74 css::uno::Reference< css::util::XNumberFormatter > xFormatter;
75 css::uno::Reference< css::beans::XPropertySet > xField;
76 OUString sPredicateTableAlias;
77 css::uno::Reference< css::container::XNameAccess > xQueries; // see bParseToSDBCLevel
78 const IParseContext& m_rContext;
79 OUString sDecSep;
80 bool bQuote : 1; /// should we quote identifiers?
81 bool bInternational : 1; /// should we internationalize keywords and placeholders?
82 bool bPredicate : 1; /// are we going to parse a mere predicate?
83 bool bParseToSDBCLevel : 1; /// should we create an SDBC-level statement (e.g. with substituted sub queries)?
85 SQLParseNodeParameter(
86 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
87 const css::uno::Reference< css::util::XNumberFormatter >& _xFormatter,
88 const css::uno::Reference< css::beans::XPropertySet >& _xField,
89 const OUString &_sPredicateTableAlias,
90 const css::lang::Locale& _rLocale,
91 const IParseContext* _pContext,
92 bool _bIntl,
93 bool _bQuote,
94 OUString _sDecSep,
95 bool _bPredicate,
96 bool _bParseToSDBC
100 //= OSQLParseNode
102 class OOO_DLLPUBLIC_DBTOOLS OSQLParseNode
104 friend class OSQLParser;
106 std::vector< std::unique_ptr<OSQLParseNode> >
107 m_aChildren;
108 OSQLParseNode* m_pParent; // pParent for reverse linkage in the tree
109 OUString m_aNodeValue; // token name, or empty in case of rules,
110 // or OUString in case of
111 // OUString, INT, etc.
112 SQLNodeType m_eNodeType; // see above
113 sal_uInt32 m_nNodeID; // Rule ID (if IsRule())
114 // or Token ID (if !IsRule())
115 // Rule IDs and Token IDs can't
116 // be distinguished by their values,
117 // IsRule has to be used for that!
118 public:
119 enum Rule
121 UNKNOWN_RULE = 0, // ID indicating that a node is no rule with a matching Rule-enum value (see getKnownRuleID)
122 // we make sure it is 0 so that it is the default-constructor value of this enum
123 // and std::map<foo,Rule>::operator[](bar) default-inserts UNKNOWN_RULE rather than select_statement (!)
124 select_statement,
125 table_exp,
126 table_ref_commalist,
127 table_ref,
128 catalog_name,
129 schema_name,
130 table_name,
131 opt_column_commalist,
132 column_commalist,
133 column_ref_commalist,
134 column_ref,
135 opt_order_by_clause,
136 ordering_spec_commalist,
137 ordering_spec,
138 opt_asc_desc,
139 where_clause,
140 opt_where_clause,
141 search_condition,
142 comparison,
143 comparison_predicate,
144 between_predicate,
145 like_predicate,
146 opt_escape,
147 test_for_null,
148 scalar_exp_commalist,
149 scalar_exp,
150 parameter_ref,
151 parameter,
152 general_set_fct,
153 range_variable,
154 column,
155 delete_statement_positioned,
156 delete_statement_searched,
157 update_statement_positioned,
158 update_statement_searched,
159 assignment_commalist,
160 assignment,
161 values_or_query_spec,
162 insert_statement,
163 insert_atom_commalist,
164 insert_atom,
165 from_clause,
166 qualified_join,
167 cross_union,
168 select_sublist,
169 derived_column,
170 column_val,
171 set_fct_spec,
172 boolean_term,
173 boolean_primary,
174 num_value_exp,
175 join_type,
176 position_exp,
177 extract_exp,
178 length_exp,
179 char_value_fct,
180 odbc_call_spec,
181 in_predicate,
182 existence_test,
183 unique_test,
184 all_or_any_predicate,
185 named_columns_join,
186 join_condition,
187 joined_table,
188 boolean_factor,
189 sql_not,
190 manipulative_statement,
191 subquery,
192 value_exp_commalist,
193 odbc_fct_spec,
194 union_statement,
195 outer_join_type,
196 char_value_exp,
197 term,
198 value_exp_primary,
199 value_exp,
200 selection,
201 fold,
202 char_substring_fct,
203 factor,
204 base_table_def,
205 base_table_element_commalist,
206 data_type,
207 column_def,
208 table_node,
209 as_clause,
210 opt_as,
211 op_column_commalist,
212 table_primary_as_range_column,
213 datetime_primary,
214 concatenation,
215 char_factor,
216 bit_value_fct,
217 comparison_predicate_part_2,
218 parenthesized_boolean_value_expression,
219 character_string_type,
220 other_like_predicate_part_2,
221 between_predicate_part_2,
222 null_predicate_part_2,
223 cast_spec,
224 window_function,
225 rule_count // last value
228 // must be ascii encoding for the value
229 OSQLParseNode(const char* _pValueStr,
230 SQLNodeType _eNodeType,
231 sal_uInt32 _nNodeID = 0);
233 OSQLParseNode(const OString& _rValue,
234 SQLNodeType eNewNodeType,
235 sal_uInt32 nNewNodeID=0);
237 OSQLParseNode(const OUString& _rValue,
238 SQLNodeType _eNodeType,
239 sal_uInt32 _nNodeID = 0);
241 // copies the respective ParseNode
242 OSQLParseNode(const OSQLParseNode& rParseNode);
243 OSQLParseNode& operator=(const OSQLParseNode& rParseNode);
245 bool operator==(OSQLParseNode const & rParseNode) const;
247 // destructor destructs the tree recursively
248 virtual ~OSQLParseNode();
250 OSQLParseNode* getParent() const {return m_pParent;};
252 void setParent(OSQLParseNode* pParseNode) {m_pParent = pParseNode;};
254 size_t count() const {return m_aChildren.size();};
255 inline OSQLParseNode* getChild(sal_uInt32 nPos) const;
257 void append(OSQLParseNode* pNewSubTree);
258 void insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree);
260 OSQLParseNode* replace(OSQLParseNode* pOldSubTree, OSQLParseNode* pNewSubTree);
262 OSQLParseNode* removeAt(sal_uInt32 nPos);
264 void replaceNodeValue(const OUString& rTableAlias,const OUString& rColumnName);
266 /** parses the node to a string which can be passed to a driver's connection for execution
268 Any particles of the parse tree which represent application-level features - such
269 as queries appearing in the FROM part - are substituted, so that the resulting statement can
270 be executed at an SDBC-level connection.
272 @param _out_rString
273 is an output parameter taking the resulting SQL statement
275 @param _rxConnection
276 the connection relative to which to parse. This must be an SDB-level connection (e.g.
277 support the XQueriesSupplier interface) for the method to be able to do all necessary
278 substitutions.
280 @param _rParser
281 the SQLParser used to create the node. This is needed in case we need to parse
282 sub queries which are present in the SQL statement - those sub queries need to be parsed,
283 too, to check whether they contain nested sub queries.
285 @param _pErrorHolder
286 takes the error which occurred while generating the statement, if any. Might be <NULL/>,
287 in this case the error is not reported back, and can only be recognized by examining the
288 return value.
290 @return
291 <TRUE/> if and only if the parsing was successful.<br/>
293 Currently, there's only one condition how this method can fail: If it contains a nested
294 query which causes a cycle. E.g., consider a statement <code>SELECT * from "foo"</code>,
295 where <code>foo</code> is a query defined as <code>SELECT * FROM "bar"</code>, where
296 <code>bar</code> is defined as <code>SELECT * FROM "foo"</code>. This statement obviously
297 cannot be parsed to an executable statement.
299 If this method returns <FALSE/>, you're encouraged to check and handle the error in
300 <arg>_pErrorHolder</arg>.
302 bool parseNodeToExecutableStatement( OUString& _out_rString,
303 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
304 OSQLParser& _rParser,
305 css::sdbc::SQLException* _pErrorHolder ) const;
307 void parseNodeToStr(OUString& rString,
308 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
309 const IParseContext* pContext = nullptr,
310 bool _bIntl = false,
311 bool _bQuote= true) const;
313 // quoted and internationalised
314 void parseNodeToPredicateStr(OUString& rString,
315 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
316 const css::uno::Reference< css::util::XNumberFormatter > & xFormatter,
317 const css::lang::Locale& rIntl,
318 OUString _sDec,
319 const IParseContext* pContext = nullptr ) const;
321 void parseNodeToPredicateStr(OUString& rString,
322 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
323 const css::uno::Reference< css::util::XNumberFormatter > & xFormatter,
324 const css::uno::Reference< css::beans::XPropertySet > & _xField,
325 const OUString &_sTableAlias,
326 const css::lang::Locale& rIntl,
327 OUString strDec,
328 const IParseContext* pContext = nullptr ) const;
330 OSQLParseNode* getByRule(OSQLParseNode::Rule eRule) const;
332 #if OSL_DEBUG_LEVEL > 1
333 // shows the ParseTree with tabs and linefeeds
334 void showParseTree( OUString& rString ) const;
335 void showParseTree( OUStringBuffer& _inout_rBuf, sal_uInt32 nLevel ) const;
336 #endif
338 SQLNodeType getNodeType() const {return m_eNodeType;};
340 // RuleId returns the RuleID of the node's rule (only if IsRule())
341 sal_uInt32 getRuleID() const {return m_nNodeID;}
343 /** returns the ID of the rule represented by the node
344 If the node does not represent a rule, UNKNOWN_RULE is returned
346 Rule getKnownRuleID() const;
348 // returns the TokenId of the node's token (only if !isRule())
349 sal_uInt32 getTokenID() const {return m_nNodeID;}
351 // IsRule tests whether a node is a rule (NonTerminal)
352 // ATTENTION: rules can be leaves, for example empty lists
353 bool isRule() const
354 { return (m_eNodeType == SQLNodeType::Rule) || (m_eNodeType == SQLNodeType::ListRule)
355 || (m_eNodeType == SQLNodeType::CommaListRule);}
357 // IsToken tests whether a Node is a Token (Terminal but not a rule)
358 bool isToken() const {return !isRule();}
360 const OUString& getTokenValue() const {return m_aNodeValue;}
362 bool isLeaf() const {return m_aChildren.empty();}
364 // negate only a searchcondition, any other rule could cause a gpf
365 static void negateSearchCondition(OSQLParseNode*& pSearchCondition, bool bNegate=false);
367 // normalize a logic form
368 // e.q. (a or b) and (c or d) <=> a and c or a and d or b and c or b and d
369 static void disjunctiveNormalForm(OSQLParseNode*& pSearchCondition);
371 // Simplifies logic expressions
372 // a and a = a
373 // a or a = a
374 // a and ( a + b) = a
375 // a or a and b = a
376 static void absorptions(OSQLParseNode*& pSearchCondition);
378 // erase unnecessary braces
379 static void eraseBraces(OSQLParseNode*& pSearchCondition);
381 // makes the logic formula a little smaller
382 static void compress(OSQLParseNode*& pSearchCondition);
383 // return the catalog, schema and tablename from this node
384 // _pTableNode must be a rule of that above or a SQL_TOKEN_NAME
385 static bool getTableComponents(const OSQLParseNode* _pTableNode,
386 css::uno::Any &_rCatalog,
387 OUString &_rSchema,
388 OUString &_rTable,
389 const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData);
391 // substitute all occurrences of :var or [name] into the dynamic parameter ?
392 // _pNode will be modified if parameters exists
393 static void substituteParameterNames(OSQLParseNode const * _pNode);
395 /** return a table range when it exists.
397 static OUString getTableRange(const OSQLParseNode* _pTableRef);
399 protected:
400 // ParseNodeToStr concatenates all Tokens (leaves) of the ParseNodes.
401 void parseNodeToStr(OUString& rString,
402 const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
403 const css::uno::Reference< css::util::XNumberFormatter > & xFormatter,
404 const css::uno::Reference< css::beans::XPropertySet > & _xField,
405 const OUString &_sPredicateTableAlias,
406 const css::lang::Locale& rIntl,
407 const IParseContext* pContext,
408 bool _bIntl,
409 bool _bQuote,
410 OUString _sDecSep,
411 bool _bPredicate) const;
413 private:
414 void impl_parseNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple=true ) const;
415 void impl_parseLikeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple=true ) const;
416 void impl_parseTableRangeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const;
418 /** parses a table_name node into a SQL statement particle.
419 @return
420 <TRUE/> if and only if parsing was successful, <FALSE/> if default handling should
421 be applied.
423 bool impl_parseTableNameNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const;
425 bool addDateValue(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const;
426 static OUString convertDateTimeString(const SQLParseNodeParameter& rParam, const OUString& rString);
427 static OUString convertDateString(const SQLParseNodeParameter& rParam, const OUString& rString);
428 static OUString convertTimeString(const SQLParseNodeParameter& rParam, const OUString& rString);
429 void parseLeaf(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const;
432 inline OSQLParseNode* OSQLParseNode::getChild(sal_uInt32 nPos) const
434 return m_aChildren[nPos].get();
437 // utilities to query for a specific rule, token or punctuation
438 #define SQL_ISRULE(pParseNode, eRule) ((pParseNode)->isRule() && (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::eRule))
439 #define SQL_ISRULEOR2(pParseNode, e1, e2) ((pParseNode)->isRule() && ( \
440 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \
441 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2)))
442 #define SQL_ISRULEOR3(pParseNode, e1, e2, e3) ((pParseNode)->isRule() && ( \
443 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e1) || \
444 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e2) || \
445 (pParseNode)->getRuleID() == OSQLParser::RuleID(OSQLParseNode::e3)))
446 #define SQL_ISTOKEN(pParseNode, token) ((pParseNode)->isToken() && (pParseNode)->getTokenID() == SQL_TOKEN_##token)
447 #define SQL_ISTOKENOR2(pParseNode, tok0, tok1) ((pParseNode)->isToken() && ( (pParseNode)->getTokenID() == SQL_TOKEN_##tok0 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok1 ))
448 #define SQL_ISTOKENOR3(pParseNode, tok0, tok1, tok2) ((pParseNode)->isToken() && ( (pParseNode)->getTokenID() == SQL_TOKEN_##tok0 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok1 || (pParseNode)->getTokenID() == SQL_TOKEN_##tok2 ))
449 #define SQL_ISPUNCTUATION(pParseNode, aString) ((pParseNode)->getNodeType() == SQLNodeType::Punctuation && (pParseNode)->getTokenValue() == (aString))
452 #endif // INCLUDED_CONNECTIVITY_SQLNODE_HXX
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */