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