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