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