xref: /AOO41X/main/connectivity/source/drivers/kab/KStatement.cxx (revision 9b5730f6ddef7eb82608ca4d31dc0d7678e652cf)
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 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 
27 #include "KStatement.hxx"
28 #include "KConnection.hxx"
29 #include "KDriver.hxx"
30 #include "KResultSet.hxx"
31 #include "KResultSetMetaData.hxx"
32 #include "kcondition.hxx"
33 #include "korder.hxx"
34 #include "TConnection.hxx"
35 #include <connectivity/dbexception.hxx>
36 #include "resource/kab_res.hrc"
37 #include "resource/sharedresources.hxx"
38 
39 
40 #if OSL_DEBUG_LEVEL > 0
41 # define OUtoCStr( x ) ( ::rtl::OUStringToOString ( (x), RTL_TEXTENCODING_ASCII_US).getStr())
42 #else /* OSL_DEBUG_LEVEL */
43 # define OUtoCStr( x ) ("dummy")
44 #endif /* OSL_DEBUG_LEVEL */
45 
46 using namespace connectivity::kab;
47 using namespace com::sun::star::uno;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::beans;
50 using namespace com::sun::star::sdbc;
51 using namespace com::sun::star::sdbcx;
52 using namespace com::sun::star::container;
53 using namespace com::sun::star::io;
54 using namespace com::sun::star::util;
55 
56 namespace
57 {
lcl_throwError(sal_uInt16 _nErrorId)58     void lcl_throwError(sal_uInt16 _nErrorId)
59     {
60         ::connectivity::SharedResources aResources;
61         const ::rtl::OUString sError( aResources.getResourceString(_nErrorId) );
62         ::dbtools::throwGenericSQLException(sError,NULL);
63     }
64 }
65 
66 IMPLEMENT_SERVICE_INFO(KabStatement, "com.sun.star.sdbc.drivers.KabStatement", "com.sun.star.sdbc.Statement");
67 //------------------------------------------------------------------------------
KabCommonStatement(KabConnection * _pConnection)68 KabCommonStatement::KabCommonStatement(KabConnection* _pConnection )
69     : KabCommonStatement_BASE(m_aMutex),
70     OPropertySetHelper(KabCommonStatement_BASE::rBHelper),
71     m_aParser(_pConnection->getDriver()->getMSFactory()),
72     m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser, NULL ),
73     m_pParseTree(NULL),
74     m_pConnection(_pConnection),
75     rBHelper(KabCommonStatement_BASE::rBHelper)
76 {
77     m_pConnection->acquire();
78 }
79 // -----------------------------------------------------------------------------
~KabCommonStatement()80 KabCommonStatement::~KabCommonStatement()
81 {
82 }
83 // -----------------------------------------------------------------------------
disposing()84 void KabCommonStatement::disposing()
85 {
86     KabCommonStatement_BASE::disposing();
87 }
88 // -----------------------------------------------------------------------------
resetParameters() const89 void KabCommonStatement::resetParameters() const throw(::com::sun::star::sdbc::SQLException)
90 {
91     lcl_throwError(STR_PARA_ONLY_PREPARED);
92 }
93 // -----------------------------------------------------------------------------
getNextParameter(::rtl::OUString &) const94 void KabCommonStatement::getNextParameter(::rtl::OUString &) const throw(::com::sun::star::sdbc::SQLException)
95 {
96     lcl_throwError(STR_PARA_ONLY_PREPARED);
97 }
98 // -----------------------------------------------------------------------------
analyseWhereClause(const OSQLParseNode * pParseNode) const99 KabCondition *KabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const throw(SQLException)
100 {
101     if (pParseNode->count() == 3)
102     {
103         const OSQLParseNode *pLeft = pParseNode->getChild(0),
104                             *pMiddle = pParseNode->getChild(1),
105                             *pRight = pParseNode->getChild(2);
106 
107         // WHERE ( ... ) ?
108         if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")"))
109         {
110             return analyseWhereClause(pMiddle);
111         }
112         else if (SQL_ISRULE(pParseNode, comparison_predicate))
113         {
114             if (pLeft->isToken() && pRight->isToken())
115             {
116                 switch (pMiddle->getNodeType())
117                 {
118                     case SQL_NODE_EQUAL:
119                         // WHERE 0 = 1
120                         return new KabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue());
121 
122                     case SQL_NODE_NOTEQUAL:
123                         // WHERE 0 <> 1
124                         // (might not be correct SQL... don't care, handling anyway)
125                         return new KabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue());
126 
127                     default:
128                         break;
129                 }
130             }
131             else if (SQL_ISRULE(pLeft, column_ref))
132             {
133                 ::rtl::OUString sColumnName,
134                                 sTableRange;
135 
136                 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
137 
138                 if (pRight->isToken() || SQL_ISRULE(pRight, parameter))
139                 {
140                     ::rtl::OUString sMatchString;
141 
142                     if (pRight->isToken())                      // WHERE Name = 'Doe'
143                         sMatchString = pRight->getTokenValue();
144                     else if (SQL_ISRULE(pRight, parameter))     // WHERE Name = ?
145                         getNextParameter(sMatchString);
146 
147                     switch (pMiddle->getNodeType())
148                     {
149                         case SQL_NODE_EQUAL:
150                             // WHERE Name = 'Smith'
151                             return new KabConditionEqual(sColumnName, sMatchString);
152 
153                         case SQL_NODE_NOTEQUAL:
154                             // WHERE Name <> 'Jones'
155                             return new KabConditionDifferent(sColumnName, sMatchString);
156 
157                         default:
158                             break;
159                     }
160                 }
161             }
162         }
163         else if (SQL_ISRULE(pParseNode, search_condition))
164         {
165             if (SQL_ISTOKEN(pMiddle, OR))
166             {
167                 // WHERE Name = 'Smith' OR Name = 'Jones'
168                 return new KabConditionOr(
169                     analyseWhereClause(pLeft),
170                     analyseWhereClause(pRight));
171             }
172         }
173         else if (SQL_ISRULE(pParseNode, boolean_term))
174         {
175             if (SQL_ISTOKEN(pMiddle, AND))
176             {
177                 // WHERE Name = 'Smith' AND "Given Name" = 'Peter'
178                 return new KabConditionAnd(
179                     analyseWhereClause(pLeft),
180                     analyseWhereClause(pRight));
181             }
182         }
183     }
184     else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate))
185     {
186         const OSQLParseNode *pLeft = pParseNode->getChild(0);
187         const OSQLParseNode* pPart2 = pParseNode->getChild(1);
188         const OSQLParseNode *pMiddleLeft = pPart2->getChild(0),
189                             *pMiddleRight = pPart2->getChild(1),
190                             *pRight = pPart2->getChild(2);
191 
192         if (SQL_ISRULE(pParseNode, test_for_null))
193         {
194             if (SQL_ISRULE(pLeft, column_ref) &&
195                             SQL_ISTOKEN(pMiddleLeft, IS) &&
196                             SQL_ISTOKEN(pRight, NULL))
197             {
198                 ::rtl::OUString sColumnName,
199                                 sTableRange;
200 
201                 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
202 
203                 if (SQL_ISTOKEN(pMiddleRight, NOT))
204                 {
205                     // WHERE "Mobile Phone" IS NOT NULL
206                     return new KabConditionNotNull(sColumnName);
207                 }
208                 else
209                 {
210                     // WHERE "Mobile Phone" IS NULL
211                     return new KabConditionNull(sColumnName);
212                 }
213             }
214         }
215         else if (SQL_ISRULE(pParseNode, like_predicate))
216         {
217             if (SQL_ISRULE(pLeft, column_ref))
218             {
219                 ::rtl::OUString sColumnName,
220                                 sTableRange;
221 
222                 m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange);
223 
224                 if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter))
225                 {
226                     ::rtl::OUString sMatchString;
227 
228                     if (pMiddleRight->isToken())                    // WHERE Name LIKE 'Sm%'
229                         sMatchString = pMiddleRight->getTokenValue();
230                     else if (SQL_ISRULE(pMiddleRight, parameter))   // WHERE Name LIKE ?
231                         getNextParameter(sMatchString);
232 
233                     return new KabConditionSimilar(sColumnName, sMatchString);
234                 }
235             }
236         }
237     }
238 
239     lcl_throwError(STR_QUERY_TOO_COMPLEX);
240 
241     // Unreachable:
242     OSL_ASSERT(false);
243     return 0;
244 }
245 // -----------------------------------------------------------------------------
analyseOrderByClause(const OSQLParseNode * pParseNode) const246 KabOrder *KabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const throw(SQLException)
247 {
248     if (SQL_ISRULE(pParseNode, ordering_spec_commalist))
249     {
250         KabComplexOrder *list = new KabComplexOrder();
251         sal_uInt32 n = pParseNode->count();
252 
253         // Iterate through the ordering columns
254         for (sal_uInt32 i = 0; i < n; i++)
255         {
256             list->addOrder
257                 (analyseOrderByClause(pParseNode->getChild(i)));
258         }
259 
260         return list;
261     }
262     else if (SQL_ISRULE(pParseNode, ordering_spec))
263     {
264         if (pParseNode->count() == 2)
265         {
266             OSQLParseNode* pColumnRef = pParseNode->getChild(0);
267             OSQLParseNode* pAscendingDescending = pParseNode->getChild(1);
268 
269             if (SQL_ISRULE(pColumnRef, column_ref))
270             {
271                 if (pColumnRef->count() == 3)
272                     pColumnRef = pColumnRef->getChild(2);
273 
274                 if (pColumnRef->count() == 1)
275                 {
276                     ::rtl::OUString sColumnName =
277                         pColumnRef->getChild(0)->getTokenValue();
278                     sal_Bool bAscending =
279                         SQL_ISTOKEN(pAscendingDescending, DESC)?
280                         sal_False:
281                         sal_True;
282 
283                     return new KabSimpleOrder(sColumnName, bAscending);
284                 }
285             }
286         }
287     }
288     lcl_throwError(STR_QUERY_TOO_COMPLEX);
289     // Unreachable:
290     OSL_ASSERT(false);
291     return 0;
292 }
293 //------------------------------------------------------------------------------
isTableKnown(KabResultSet * pResult) const294 sal_Bool KabCommonStatement::isTableKnown(KabResultSet *pResult) const
295 {
296     // can handle requests like        SELECT * FROM addresses addresses
297     // but cannot handle requests like SELECT * FROM addresses persons
298     if (m_aSQLIterator.getTables().size() != 1)
299         return sal_False;
300 
301     if (m_aSQLIterator.getTables().begin()->first != pResult->getMetaData()->getTableName(0))
302         return sal_False;
303 
304     return sal_True;
305 }
306 //------------------------------------------------------------------------------
setKabFields(KabResultSet * pResult) const307 void KabCommonStatement::setKabFields(KabResultSet *pResult) const throw(SQLException)
308 {
309     ::vos::ORef<connectivity::OSQLColumns> xColumns;    // selected columns
310     KabResultSetMetaData *pMeta;                // meta information - holds the list of KAddressBook fields
311 
312     xColumns = m_aSQLIterator.getSelectColumns();
313     if (!xColumns.isValid())
314     {
315         lcl_throwError(STR_INVALID_COLUMN_SELECTION);
316     }
317     pMeta = static_cast<KabResultSetMetaData *>(pResult->getMetaData().get());
318     pMeta->setKabFields(xColumns);
319 }
320 // -------------------------------------------------------------------------
selectAddressees(KabResultSet * pResult) const321 void KabCommonStatement::selectAddressees(KabResultSet *pResult) const throw(SQLException)
322 {
323     const OSQLParseNode *pParseNode;
324     KabCondition *pCondition;
325 
326     pParseNode = m_aSQLIterator.getWhereTree();
327     if (pParseNode != NULL)
328     {
329         if (SQL_ISRULE(pParseNode, where_clause))
330         {
331             resetParameters();
332             pParseNode = pParseNode->getChild(1);
333             pCondition = analyseWhereClause(pParseNode);
334             if (pCondition->isAlwaysTrue())
335                 pResult->allKabAddressees();
336             else if (!pCondition->isAlwaysFalse())
337                 pResult->someKabAddressees(pCondition);
338             delete pCondition;
339             return;
340         }
341     }
342 
343     // no WHERE clause: get all rows
344     pResult->allKabAddressees();
345 }
346 // -------------------------------------------------------------------------
sortAddressees(KabResultSet * pResult) const347 void KabCommonStatement::sortAddressees(KabResultSet *pResult) const throw(SQLException)
348 {
349     const OSQLParseNode *pParseNode;
350     KabOrder *pOrder;
351 
352     pParseNode = m_aSQLIterator.getOrderTree();
353     if (pParseNode != NULL)
354     {
355         if (SQL_ISRULE(pParseNode, opt_order_by_clause))
356         {
357             pParseNode = pParseNode->getChild(2);
358             pOrder = analyseOrderByClause(pParseNode);
359             pResult->sortKabAddressees(pOrder);
360             delete pOrder;
361         }
362     }
363 }
364 //-----------------------------------------------------------------------------
queryInterface(const Type & rType)365 Any SAL_CALL KabCommonStatement::queryInterface( const Type & rType ) throw(RuntimeException)
366 {
367     Any aRet = KabCommonStatement_BASE::queryInterface(rType);
368     if (!aRet.hasValue())
369         aRet = OPropertySetHelper::queryInterface(rType);
370     return aRet;
371 }
372 // -------------------------------------------------------------------------
getTypes()373 Sequence< Type > SAL_CALL KabCommonStatement::getTypes(  ) throw(RuntimeException)
374 {
375     ::cppu::OTypeCollection aTypes( ::getCppuType( (const Reference< XMultiPropertySet > *)0 ),
376                                     ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
377                                     ::getCppuType( (const Reference< XPropertySet > *)0 ));
378 
379     return comphelper::concatSequences(aTypes.getTypes(),KabCommonStatement_BASE::getTypes());
380 }
381 // -------------------------------------------------------------------------
cancel()382 void SAL_CALL KabCommonStatement::cancel(  ) throw(RuntimeException)
383 {
384     ::osl::MutexGuard aGuard( m_aMutex );
385 
386     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
387     // cancel the current sql statement
388 }
389 // -------------------------------------------------------------------------
close()390 void SAL_CALL KabCommonStatement::close(  ) throw(SQLException, RuntimeException)
391 {
392     {
393         ::osl::MutexGuard aGuard( m_aMutex );
394         checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
395 
396     }
397     dispose();
398 }
399 // -------------------------------------------------------------------------
execute(const::rtl::OUString & sql)400 sal_Bool SAL_CALL KabCommonStatement::execute(
401         const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
402 {
403     ::osl::MutexGuard aGuard( m_aMutex );
404     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
405 
406     Reference< XResultSet > xRS = executeQuery(sql);
407 
408     return xRS.is();
409 }
410 // -------------------------------------------------------------------------
executeQuery(const::rtl::OUString & sql)411 Reference< XResultSet > SAL_CALL KabCommonStatement::executeQuery(
412         const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
413 {
414     ::osl::MutexGuard aGuard( m_aMutex );
415     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
416 
417 OSL_TRACE("KDE Address book - SQL Request: %s", OUtoCStr(sql));
418 
419     KabResultSet* pResult = new KabResultSet(this);
420     Reference< XResultSet > xRS = pResult;
421     ::rtl::OUString aErr;
422 
423     m_pParseTree = m_aParser.parseTree(aErr, sql);
424     if (m_pParseTree == NULL)
425         throw SQLException(aErr, *this, aErr, 0, Any());
426 
427     m_aSQLIterator.setParseTree(m_pParseTree);
428     m_aSQLIterator.traverseAll();
429     switch (m_aSQLIterator.getStatementType())
430     {
431         case SQL_STATEMENT_SELECT:
432             if (isTableKnown(pResult))      // FROM which table ?
433             {
434                 setKabFields(pResult);      // SELECT which columns ?
435                 selectAddressees(pResult);  // WHERE which condition ?
436                 sortAddressees(pResult);    // ORDER BY which columns ?
437 // To be continued: DISTINCT
438 //                  etc...
439             }
440             break;
441 
442         default:
443 // To be continued: UPDATE
444 //                  DELETE
445 //                  etc...
446             lcl_throwError(STR_QUERY_TOO_COMPLEX);
447     }
448 
449     return xRS;
450 }
451 // -------------------------------------------------------------------------
getConnection()452 Reference< XConnection > SAL_CALL KabCommonStatement::getConnection(  ) throw(SQLException, RuntimeException)
453 {
454     ::osl::MutexGuard aGuard( m_aMutex );
455     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
456 
457     // just return our connection here
458     return (Reference< XConnection >) m_pConnection;
459 }
460 // -------------------------------------------------------------------------
executeUpdate(const::rtl::OUString &)461 sal_Int32 SAL_CALL KabCommonStatement::executeUpdate( const ::rtl::OUString& ) throw(SQLException, RuntimeException)
462 {
463     ::osl::MutexGuard aGuard( m_aMutex );
464     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
465 
466     // the return values gives information about how many rows are affected by executing the sql statement
467     return 0;
468 }
469 // -------------------------------------------------------------------------
getWarnings()470 Any SAL_CALL KabCommonStatement::getWarnings(  ) throw(SQLException, RuntimeException)
471 {
472     ::osl::MutexGuard aGuard( m_aMutex );
473     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
474 
475     return makeAny(m_aLastWarning);
476 }
477 // -------------------------------------------------------------------------
clearWarnings()478 void SAL_CALL KabCommonStatement::clearWarnings(  ) throw(SQLException, RuntimeException)
479 {
480     ::osl::MutexGuard aGuard( m_aMutex );
481     checkDisposed(KabCommonStatement_BASE::rBHelper.bDisposed);
482 
483     m_aLastWarning = SQLWarning();
484 }
485 // -------------------------------------------------------------------------
createArrayHelper() const486 ::cppu::IPropertyArrayHelper* KabCommonStatement::createArrayHelper( ) const
487 {
488     // this properties are defined by the service statement
489     // they must be in alphabetic order
490     Sequence< Property > aProps(10);
491     Property* pProperties = aProps.getArray();
492     sal_Int32 nPos = 0;
493     DECL_PROP0(CURSORNAME,  ::rtl::OUString);
494     DECL_BOOL_PROP0(ESCAPEPROCESSING);
495     DECL_PROP0(FETCHDIRECTION,sal_Int32);
496     DECL_PROP0(FETCHSIZE,   sal_Int32);
497     DECL_PROP0(MAXFIELDSIZE,sal_Int32);
498     DECL_PROP0(MAXROWS,     sal_Int32);
499     DECL_PROP0(QUERYTIMEOUT,sal_Int32);
500     DECL_PROP0(RESULTSETCONCURRENCY,sal_Int32);
501     DECL_PROP0(RESULTSETTYPE,sal_Int32);
502     DECL_BOOL_PROP0(USEBOOKMARKS);
503 
504     return new ::cppu::OPropertyArrayHelper(aProps);
505 }
506 // -------------------------------------------------------------------------
getInfoHelper()507 ::cppu::IPropertyArrayHelper & KabCommonStatement::getInfoHelper()
508 {
509     return *const_cast<KabCommonStatement*>(this)->getArrayHelper();
510 }
511 // -------------------------------------------------------------------------
convertFastPropertyValue(Any &,Any &,sal_Int32,const Any &)512 sal_Bool KabCommonStatement::convertFastPropertyValue(
513         Any &,
514         Any &,
515         sal_Int32,
516         const Any&) throw (::com::sun::star::lang::IllegalArgumentException)
517 {
518     sal_Bool bConverted = sal_False;
519     // here we have to try to convert
520     return bConverted;
521 }
522 // -------------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any &)523 void KabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) throw (Exception)
524 {
525     // set the value to whatever is nescessary
526     switch (nHandle)
527     {
528         case PROPERTY_ID_QUERYTIMEOUT:
529         case PROPERTY_ID_MAXFIELDSIZE:
530         case PROPERTY_ID_MAXROWS:
531         case PROPERTY_ID_CURSORNAME:
532         case PROPERTY_ID_RESULTSETCONCURRENCY:
533         case PROPERTY_ID_RESULTSETTYPE:
534         case PROPERTY_ID_FETCHDIRECTION:
535         case PROPERTY_ID_FETCHSIZE:
536         case PROPERTY_ID_ESCAPEPROCESSING:
537         case PROPERTY_ID_USEBOOKMARKS:
538         default:
539             ;
540     }
541 }
542 // -------------------------------------------------------------------------
getFastPropertyValue(Any &,sal_Int32 nHandle) const543 void KabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const
544 {
545     switch (nHandle)
546     {
547         case PROPERTY_ID_QUERYTIMEOUT:
548         case PROPERTY_ID_MAXFIELDSIZE:
549         case PROPERTY_ID_MAXROWS:
550         case PROPERTY_ID_CURSORNAME:
551         case PROPERTY_ID_RESULTSETCONCURRENCY:
552         case PROPERTY_ID_RESULTSETTYPE:
553         case PROPERTY_ID_FETCHDIRECTION:
554         case PROPERTY_ID_FETCHSIZE:
555         case PROPERTY_ID_ESCAPEPROCESSING:
556         case PROPERTY_ID_USEBOOKMARKS:
557         default:
558             ;
559     }
560 }
561 // -----------------------------------------------------------------------------
acquire()562 void SAL_CALL KabCommonStatement::acquire() throw()
563 {
564     KabCommonStatement_BASE::acquire();
565 }
566 // -----------------------------------------------------------------------------
release()567 void SAL_CALL KabCommonStatement::release() throw()
568 {
569     KabCommonStatement_BASE::release();
570 }
571 // -----------------------------------------------------------------------------
getPropertySetInfo()572 Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL KabCommonStatement::getPropertySetInfo(  ) throw(RuntimeException)
573 {
574     return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
575 }
576 // -----------------------------------------------------------------------------
KabStatement(KabConnection * _pConnection)577 KabStatement::KabStatement(KabConnection* _pConnection)
578     : KabStatement_BASE(_pConnection)
579 {
580 }
581