Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <stdio.h>
22 : #include <string.h>
23 : #include <osl/diagnose.h>
24 : #include "diagnose_ex.h"
25 : #include "odbc/OPreparedStatement.hxx"
26 : #include "odbc/OBoundParam.hxx"
27 : #include <com/sun/star/sdbc/DataType.hpp>
28 : #include "odbc/OTools.hxx"
29 : #include "odbc/ODriver.hxx"
30 : #include "odbc/OResultSet.hxx"
31 : #include "odbc/OResultSetMetaData.hxx"
32 : #include <cppuhelper/typeprovider.hxx>
33 : #include <comphelper/processfactory.hxx>
34 : #include <comphelper/sequence.hxx>
35 : #include <com/sun/star/lang/DisposedException.hpp>
36 : #include "connectivity/dbtools.hxx"
37 : #include <comphelper/types.hxx>
38 : #include "connectivity/FValue.hxx"
39 : #include "resource/common_res.hrc"
40 : #include "connectivity/sqlparse.hxx"
41 : #include <boost/type_traits/remove_reference.hpp>
42 : #include <boost/type_traits/is_same.hpp>
43 :
44 : using namespace ::comphelper;
45 : using namespace connectivity;
46 : using namespace connectivity::odbc;
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 0 : IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement");
57 :
58 : namespace
59 : {
60 : // for now, never use wchar,
61 : // but most of code is prepared to handle it
62 : // in case we make this configurable
63 : const bool useWChar = false;
64 : }
65 :
66 0 : OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const ::rtl::OUString& sql)
67 : :OStatement_BASE2(_pConnection)
68 : ,numParams(0)
69 : ,boundParams(NULL)
70 0 : ,m_bPrepared(sal_False)
71 : {
72 0 : m_sSqlStatement = sql;
73 : try
74 : {
75 0 : if(_pConnection->isParameterSubstitutionEnabled())
76 : {
77 0 : OSQLParser aParser( comphelper::getComponentContext(_pConnection->getDriver()->getORB()) );
78 0 : ::rtl::OUString sErrorMessage;
79 0 : ::rtl::OUString sNewSql;
80 0 : ::std::auto_ptr<OSQLParseNode> pNode( aParser.parseTree(sErrorMessage,sql) );
81 0 : if ( pNode.get() )
82 : { // special handling for parameters
83 0 : OSQLParseNode::substituteParameterNames(pNode.get());
84 0 : pNode->parseNodeToStr( sNewSql, _pConnection );
85 0 : m_sSqlStatement = sNewSql;
86 0 : }
87 : }
88 : }
89 0 : catch(Exception&)
90 : {
91 : }
92 0 : }
93 : // -----------------------------------------------------------------------------
94 0 : void SAL_CALL OPreparedStatement::acquire() throw()
95 : {
96 0 : OStatement_BASE2::acquire();
97 0 : }
98 : // -----------------------------------------------------------------------------
99 0 : void SAL_CALL OPreparedStatement::release() throw()
100 : {
101 0 : OStatement_BASE2::release();
102 0 : }
103 : // -----------------------------------------------------------------------------
104 0 : Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) throw(RuntimeException)
105 : {
106 0 : Any aRet = OStatement_BASE2::queryInterface(rType);
107 0 : return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType);
108 : }
109 : // -------------------------------------------------------------------------
110 0 : ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) throw(::com::sun::star::uno::RuntimeException)
111 : {
112 0 : return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes());
113 : }
114 : // -------------------------------------------------------------------------
115 :
116 0 : Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) throw(SQLException, RuntimeException)
117 : {
118 0 : ::osl::MutexGuard aGuard( m_aMutex );
119 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
120 :
121 :
122 0 : prepareStatement();
123 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
124 0 : if(!m_xMetaData.is())
125 0 : m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle);
126 0 : return m_xMetaData;
127 : }
128 : // -------------------------------------------------------------------------
129 :
130 0 : void SAL_CALL OPreparedStatement::close( ) throw(SQLException, RuntimeException)
131 : {
132 0 : ::osl::MutexGuard aGuard( m_aMutex );
133 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
134 :
135 :
136 : // Close/clear our result set
137 0 : clearMyResultSet ();
138 :
139 : // Reset last warning message
140 :
141 : try {
142 0 : clearWarnings ();
143 0 : OStatement_BASE2::close();
144 0 : FreeParams();
145 : }
146 0 : catch (SQLException &) {
147 : // If we get an error, ignore
148 0 : }
149 :
150 : // Remove this Statement object from the Connection object's
151 : // list
152 0 : }
153 : // -------------------------------------------------------------------------
154 :
155 0 : sal_Bool SAL_CALL OPreparedStatement::execute( ) throw(SQLException, RuntimeException)
156 : {
157 0 : ::osl::MutexGuard aGuard( m_aMutex );
158 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
159 :
160 :
161 0 : sal_Bool needData = sal_False;
162 :
163 : // Reset warnings
164 :
165 0 : clearWarnings ();
166 :
167 : // Reset the statement handle, warning and saved Resultset
168 :
169 0 : reset();
170 :
171 : // Call SQLExecute
172 0 : prepareStatement();
173 :
174 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
175 : try
176 : {
177 0 : SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle);
178 :
179 0 : OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
180 0 : needData = nReturn == SQL_NEED_DATA;
181 :
182 : // Now loop while more data is needed (i.e. a data-at-
183 : // execution parameter was given). For each parameter
184 : // that needs data, put the data from the input stream.
185 :
186 0 : while (needData) {
187 :
188 : // Get the parameter number that requires data
189 :
190 0 : sal_Int32* paramIndex = 0;
191 0 : nReturn = N3SQLParamData(m_aStatementHandle,(SQLPOINTER*)¶mIndex);
192 :
193 : // If the parameter index is -1, there is no
194 : // more data required
195 :
196 0 : if ( !paramIndex || ( *paramIndex == -1 ) )
197 0 : needData = sal_False;
198 : else
199 : {
200 : // Now we have the proper parameter
201 : // index, get the data from the input
202 : // stream and do a SQLPutData
203 0 : putParamData (*paramIndex);
204 : }
205 : }
206 :
207 : }
208 0 : catch (const SQLWarning&)
209 : {
210 : }
211 :
212 : // Now determine if there is a result set associated with
213 : // the SQL statement that was executed. Get the column
214 : // count, and if it is not zero, there is a result set.
215 :
216 :
217 0 : return getColumnCount() > 0;
218 : }
219 : // -------------------------------------------------------------------------
220 :
221 0 : sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) throw(SQLException, RuntimeException)
222 : {
223 0 : ::osl::MutexGuard aGuard( m_aMutex );
224 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
225 :
226 0 : sal_Int32 numRows = -1;
227 :
228 0 : prepareStatement();
229 : // Execute the statement. If execute returns sal_False, a
230 : // row count exists.
231 :
232 0 : if (!execute())
233 0 : numRows = getUpdateCount ();
234 : else
235 : {
236 : // No update count was produced (a ResultSet was). Raise
237 : // an exception
238 0 : m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this);
239 : }
240 0 : return numRows;
241 : }
242 : // -------------------------------------------------------------------------
243 :
244 0 : void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const ::rtl::OUString& x ) throw(SQLException, RuntimeException)
245 : {
246 0 : setParameter(parameterIndex, DataType::CHAR, invalid_scale, x);
247 0 : }
248 : // -------------------------------------------------------------------------
249 :
250 0 : Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) throw(SQLException, RuntimeException)
251 : {
252 0 : ::osl::MutexGuard aGuard( m_aMutex );
253 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
254 :
255 0 : return (Reference< XConnection >)m_pConnection;
256 : }
257 : // -------------------------------------------------------------------------
258 :
259 0 : Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) throw(SQLException, RuntimeException)
260 : {
261 0 : ::osl::MutexGuard aGuard( m_aMutex );
262 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
263 :
264 0 : Reference< XResultSet > rs = NULL;
265 :
266 0 : prepareStatement();
267 :
268 0 : if (execute())
269 0 : rs = getResultSet(sal_False);
270 : else
271 : {
272 : // No ResultSet was produced. Raise an exception
273 0 : m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
274 : }
275 0 : return rs;
276 : }
277 : // -------------------------------------------------------------------------
278 :
279 0 : void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) throw(SQLException, RuntimeException)
280 : {
281 : // Set the parameter as if it were an integer
282 0 : setInt (parameterIndex, x ? 1 : 0 );
283 0 : }
284 : // -------------------------------------------------------------------------
285 : // The MutexGuard must _already_ be taken!
286 0 : void OPreparedStatement::setParameterPre(sal_Int32 parameterIndex)
287 : {
288 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
289 0 : prepareStatement();
290 0 : checkParameterIndex(parameterIndex);
291 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
292 0 : }
293 : // -------------------------------------------------------------------------
294 :
295 0 : template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, const T i_Value)
296 : {
297 0 : ::osl::MutexGuard aGuard( m_aMutex );
298 0 : setParameterPre(parameterIndex);
299 :
300 : typedef typename boost::remove_reference< T >::type TnoRef;
301 :
302 0 : TnoRef *bindBuf = static_cast< TnoRef* >( allocBindBuf(parameterIndex, sizeof(i_Value)) );
303 0 : *bindBuf = i_Value;
304 :
305 0 : setParameter(parameterIndex, i_nType, i_nColSize, invalid_scale, bindBuf, sizeof(i_Value), sizeof(i_Value));
306 0 : }
307 : // -------------------------------------------------------------------------
308 :
309 0 : void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const sal_Int16 _nScale, const ::rtl::OUString &_sData)
310 : {
311 0 : ::osl::MutexGuard aGuard( m_aMutex );
312 0 : setParameterPre(parameterIndex);
313 :
314 : assert (_nType == DataType::VARCHAR || _nType == DataType::CHAR || _nType == DataType::DECIMAL || _nType == DataType::NUMERIC);
315 :
316 : sal_Int32 nCharLen;
317 : sal_Int32 nByteLen;
318 : void *pData;
319 : if (useWChar)
320 : {
321 : /*
322 : * On Windows, wchar is 16 bits (UTF-16 encoding), the ODBC "W" variants functions take UTF-16 encoded strings
323 : * and character lengths are number of UTF-16 codepoints.
324 : * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716246%28v=vs.85%29.aspx
325 : * ODBC Programmer's reference > Developing Applications > Programming Considerations > Unicode > Unicode Function Arguments
326 : * http://support.microsoft.com/kb/294169
327 : *
328 : * UnixODBC can be configured at compile-time so that the "W" variants expect
329 : * UTF-16 or UTF-32 encoded strings, and character lengths are number of codepoints.
330 : * However, UTF-16 is the default, what all/most distributions do
331 : * and the established API that most drivers implement.
332 : * As wchar is often 32 bits, this differs from C-style strings of wchar!
333 : *
334 : * Our internal OUString storage is always UTF-16, so no conversion to do here.
335 : */
336 : BOOST_STATIC_ASSERT( sizeof(sal_Unicode) == 2 );
337 : BOOST_STATIC_ASSERT( sizeof(SQLWCHAR) == 2 );
338 : nCharLen = _sData.getLength();
339 : nByteLen = nCharLen * sizeof(sal_Unicode);
340 : pData = allocBindBuf(parameterIndex, nByteLen);
341 : memcpy(pData, _sData.getStr(), nByteLen);
342 : }
343 : else
344 : {
345 0 : ::rtl::OString sOData( ::rtl::OUStringToOString(_sData, getOwnConnection()->getTextEncoding()) );
346 0 : nCharLen = sOData.getLength();
347 0 : nByteLen = nCharLen;
348 0 : pData = allocBindBuf(parameterIndex, nByteLen);
349 0 : memcpy(pData, sOData.getStr(), nByteLen);
350 : }
351 :
352 0 : setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen );
353 0 : }
354 : // -------------------------------------------------------------------------
355 0 : void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const Sequence< sal_Int8 > &x)
356 : {
357 0 : ::osl::MutexGuard aGuard( m_aMutex );
358 0 : setParameterPre(parameterIndex);
359 :
360 : assert(_nType == DataType::BINARY || _nType == DataType::VARBINARY);
361 :
362 : // don't copy the sequence, just point the ODBC directly at the sequence's storage array
363 : // Why BINARY/Sequence is treated differently than strings (which are copied), I'm not sure
364 0 : OSL_VERIFY(allocBindBuf(parameterIndex, 0) == NULL);
365 0 : boundParams[parameterIndex-1].setSequence(x); // this ensures that the sequence stays alive
366 :
367 0 : setParameter( parameterIndex, _nType, x.getLength(), invalid_scale, x.getConstArray(), x.getLength(), x.getLength() );
368 0 : }
369 : // -------------------------------------------------------------------------
370 0 : void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const SQLULEN _nColumnSize, const sal_Int32 _nScale, const void* const _pData, const SQLULEN _nDataLen, const SQLLEN _nDataAllocLen)
371 : {
372 : SQLSMALLINT fCType, fSqlType;
373 0 : OTools::getBindTypes(useWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
374 :
375 0 : SQLLEN *pDataLen=boundParams[parameterIndex-1].getBindLengthBuffer();
376 0 : *pDataLen=_nDataLen;
377 :
378 : SQLRETURN nRetcode;
379 0 : nRetcode = (*(T3SQLBindParameter)m_pConnection->getOdbcFunction(ODBC3SQLBindParameter))(
380 : m_aStatementHandle,
381 : // checkParameterIndex guarantees this is safe
382 : static_cast<SQLUSMALLINT>(parameterIndex),
383 : SQL_PARAM_INPUT,
384 : fCType,
385 : fSqlType,
386 : _nColumnSize,
387 : _nScale,
388 : // we trust the ODBC driver not to touch it because SQL_PARAM_INPUT
389 : const_cast<void*>(_pData),
390 : _nDataAllocLen,
391 0 : pDataLen);
392 :
393 0 : OTools::ThrowException(m_pConnection, nRetcode, m_aStatementHandle, SQL_HANDLE_STMT, *this);
394 0 : }
395 : // -----------------------------------------------------------------------------
396 0 : void SAL_CALL OPreparedStatement::setByte( const sal_Int32 parameterIndex, const sal_Int8 x ) throw(SQLException, RuntimeException)
397 : {
398 0 : setScalarParameter(parameterIndex, DataType::TINYINT, 3, x);
399 0 : }
400 : // -------------------------------------------------------------------------
401 : // For older compilers (that do not support partial specialisation of class templates)
402 : // uncomment if necessary (safe also on compilers that *do* support partial specialisation)
403 : //BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(DATE_STRUCT);
404 : //BOOST_STATIC_ASSERT((boost::is_same<DATE_STRUCT, boost::remove_reference<DATE_STRUCT&>::type>::value));
405 0 : void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData ) throw(SQLException, RuntimeException)
406 : {
407 0 : DATE_STRUCT x(OTools::DateToOdbcDate(aData));
408 0 : setScalarParameter<DATE_STRUCT&>(parameterIndex, DataType::DATE, 10, x);
409 0 : }
410 : // -------------------------------------------------------------------------
411 :
412 0 : void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const Time& aVal ) throw(SQLException, RuntimeException)
413 : {
414 0 : const sal_uInt16 hundredths (aVal.HundredthSeconds);
415 : SQLULEN nColSize;
416 0 : if(hundredths == 0)
417 0 : nColSize = 8;
418 0 : else if(hundredths % 10 == 0)
419 0 : nColSize = 10;
420 : else
421 0 : nColSize = 11;
422 0 : TIME_STRUCT x(OTools::TimeToOdbcTime(aVal));
423 0 : setScalarParameter<TIME_STRUCT&>(parameterIndex, DataType::TIME, nColSize, x);
424 0 : }
425 : // -------------------------------------------------------------------------
426 :
427 0 : void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal ) throw(SQLException, RuntimeException)
428 : {
429 0 : sal_uInt16 s(aVal.Seconds);
430 0 : sal_uInt16 hundredths(aVal.HundredthSeconds);
431 : SQLULEN nColSize;
432 0 : if(hundredths == 0)
433 : {
434 0 : if (s == 0)
435 0 : nColSize=16;
436 : else
437 0 : nColSize=19;
438 : }
439 0 : else if(hundredths % 10 == 0)
440 0 : nColSize = 21;
441 : else
442 0 : nColSize = 22;
443 :
444 0 : TIMESTAMP_STRUCT x(OTools::DateTimeToTimestamp(aVal));
445 0 : setScalarParameter<TIMESTAMP_STRUCT&>(parameterIndex, DataType::TIMESTAMP, nColSize, x);
446 0 : }
447 : // -------------------------------------------------------------------------
448 :
449 0 : void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) throw(SQLException, RuntimeException)
450 : {
451 0 : setScalarParameter(parameterIndex, DataType::DOUBLE, 15, x);
452 0 : }
453 :
454 : // -------------------------------------------------------------------------
455 :
456 0 : void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) throw(SQLException, RuntimeException)
457 : {
458 0 : setScalarParameter(parameterIndex, DataType::FLOAT, 15, x);
459 0 : }
460 : // -------------------------------------------------------------------------
461 :
462 0 : void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) throw(SQLException, RuntimeException)
463 : {
464 0 : setScalarParameter(parameterIndex, DataType::INTEGER, 10, x);
465 0 : }
466 : // -------------------------------------------------------------------------
467 :
468 0 : void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) throw(SQLException, RuntimeException)
469 : {
470 : try
471 : {
472 0 : setScalarParameter(parameterIndex, DataType::BIGINT, 19, x);
473 : }
474 0 : catch(SQLException&)
475 : {
476 0 : setString(parameterIndex, ORowSetValue(x));
477 : }
478 0 : }
479 : // -------------------------------------------------------------------------
480 :
481 0 : void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_Int32 _nType ) throw(SQLException, RuntimeException)
482 : {
483 0 : ::osl::MutexGuard aGuard( m_aMutex );
484 0 : setParameterPre(parameterIndex);
485 :
486 0 : OSL_VERIFY(allocBindBuf(parameterIndex, 0) == NULL);
487 0 : SQLLEN * const lenBuf = getLengthBuf (parameterIndex);
488 0 : *lenBuf = SQL_NULL_DATA;
489 :
490 :
491 : SQLSMALLINT fCType;
492 : SQLSMALLINT fSqlType;
493 :
494 : OTools::getBindTypes( useWChar,
495 0 : m_pConnection->useOldDateFormat(),
496 0 : OTools::jdbcTypeToOdbc(_nType),
497 : fCType,
498 0 : fSqlType);
499 :
500 0 : SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle,
501 : static_cast<SQLUSMALLINT>(parameterIndex),
502 : SQL_PARAM_INPUT,
503 : fCType,
504 : fSqlType,
505 : 0,
506 : 0,
507 : NULL,
508 : 0,
509 : lenBuf
510 : );
511 0 : OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
512 0 : }
513 : // -------------------------------------------------------------------------
514 :
515 0 : void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException)
516 : {
517 0 : if ( x.is() )
518 0 : setStream(parameterIndex, x->getCharacterStream(), x->length(), DataType::LONGVARCHAR);
519 0 : }
520 : // -------------------------------------------------------------------------
521 :
522 0 : void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) throw(SQLException, RuntimeException)
523 : {
524 0 : if ( x.is() )
525 0 : setStream(parameterIndex, x->getBinaryStream(), x->length(), DataType::LONGVARBINARY);
526 0 : }
527 : // -------------------------------------------------------------------------
528 :
529 0 : void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) throw(SQLException, RuntimeException)
530 : {
531 0 : ::dbtools::throwFunctionNotSupportedException( "XParameters::setArray", *this );
532 0 : }
533 : // -------------------------------------------------------------------------
534 :
535 0 : void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) throw(SQLException, RuntimeException)
536 : {
537 0 : ::dbtools::throwFunctionNotSupportedException( "XParameters::setRef", *this );
538 0 : }
539 : // -------------------------------------------------------------------------
540 0 : void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException)
541 : {
542 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
543 0 : ::osl::MutexGuard aGuard( m_aMutex );
544 :
545 0 : prepareStatement();
546 : // For each known SQL Type, call the appropriate
547 : // set routine
548 :
549 0 : switch (sqlType)
550 : {
551 : case DataType::CHAR:
552 : case DataType::VARCHAR:
553 : case DataType::LONGVARCHAR:
554 0 : if(x.hasValue())
555 : {
556 0 : ::rtl::OUString sStr;
557 0 : x >>= sStr;
558 0 : setParameter(parameterIndex, sqlType, scale, sStr);
559 : }
560 : else
561 0 : setNull(parameterIndex,sqlType);
562 0 : break;
563 : case DataType::DECIMAL:
564 : case DataType::NUMERIC:
565 0 : if(x.hasValue())
566 : {
567 0 : ORowSetValue aValue;
568 0 : aValue.fill(x);
569 : // TODO: make sure that this calls the string overload
570 0 : setParameter(parameterIndex, sqlType, scale, aValue);
571 : }
572 : else
573 0 : setNull(parameterIndex,sqlType);
574 0 : break;
575 : default:
576 0 : ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
577 0 : }
578 0 : }
579 : // -------------------------------------------------------------------------
580 :
581 0 : void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& /*typeName*/ ) throw(SQLException, RuntimeException)
582 : {
583 0 : setNull(parameterIndex,sqlType);
584 0 : }
585 : // -------------------------------------------------------------------------
586 :
587 0 : void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) throw(SQLException, RuntimeException)
588 : {
589 0 : if (!::dbtools::implSetObject(this, parameterIndex, x))
590 : { // there is no other setXXX call which can handle the value in x
591 0 : throw SQLException();
592 : }
593 0 : }
594 : // -------------------------------------------------------------------------
595 :
596 0 : void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) throw(SQLException, RuntimeException)
597 : {
598 0 : setScalarParameter(parameterIndex, DataType::SMALLINT, 5, x);
599 0 : }
600 : // -------------------------------------------------------------------------
601 :
602 0 : void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) throw(SQLException, RuntimeException)
603 : {
604 0 : setParameter(parameterIndex, DataType::BINARY, x);
605 0 : }
606 : // -------------------------------------------------------------------------
607 :
608 :
609 0 : void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException)
610 : {
611 : // LEM: It is quite unclear to me what the interface here is.
612 : // The XInputStream provides *bytes*, not characters.
613 0 : setStream(parameterIndex, x, length, DataType::LONGVARCHAR);
614 0 : }
615 : // -------------------------------------------------------------------------
616 :
617 0 : void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException)
618 : {
619 0 : setStream(parameterIndex, x, length, DataType::LONGVARBINARY);
620 0 : }
621 : // -------------------------------------------------------------------------
622 :
623 0 : void SAL_CALL OPreparedStatement::clearParameters( ) throw(SQLException, RuntimeException)
624 : {
625 0 : ::osl::MutexGuard aGuard( m_aMutex );
626 0 : prepareStatement();
627 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
628 0 : SQLRETURN nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS);
629 0 : nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND);
630 0 : OSL_UNUSED(nRet);
631 0 : }
632 : // -------------------------------------------------------------------------
633 0 : void SAL_CALL OPreparedStatement::clearBatch( ) throw(SQLException, RuntimeException)
634 : {
635 0 : ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::clearBatch", *this );
636 : // clearParameters( );
637 : // m_aBatchList.erase();
638 0 : }
639 : // -------------------------------------------------------------------------
640 :
641 0 : void SAL_CALL OPreparedStatement::addBatch( ) throw(SQLException, RuntimeException)
642 : {
643 0 : ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::addBatch", *this );
644 0 : }
645 : // -------------------------------------------------------------------------
646 :
647 0 : Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( ) throw(SQLException, RuntimeException)
648 : {
649 0 : ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::executeBatch", *this );
650 : // not reached, but keep -Werror happy
651 0 : return Sequence< sal_Int32 > ();
652 : }
653 : // -------------------------------------------------------------------------
654 :
655 : //====================================================================
656 : // methods
657 : //====================================================================
658 :
659 : //--------------------------------------------------------------------
660 : // initBoundParam
661 : // Initialize the bound parameter objects
662 : //--------------------------------------------------------------------
663 :
664 0 : void OPreparedStatement::initBoundParam () throw(SQLException)
665 : {
666 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
667 : // Get the number of parameters
668 0 : numParams = 0;
669 0 : N3SQLNumParams (m_aStatementHandle,&numParams);
670 :
671 : // There are parameter markers, allocate the bound
672 : // parameter objects
673 :
674 0 : if (numParams > 0)
675 : {
676 : // Allocate an array of bound parameter objects
677 :
678 0 : boundParams = new OBoundParam[numParams];
679 :
680 : }
681 0 : }
682 : // -------------------------------------------------------------------------
683 :
684 : //--------------------------------------------------------------------
685 : // allocBindBuf
686 : // Allocate storage for the permanent data buffer for the bound
687 : // parameter.
688 : //--------------------------------------------------------------------
689 :
690 0 : void* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen)
691 : {
692 0 : void* b = NULL;
693 :
694 : // Sanity check the parameter number
695 :
696 0 : if ((index >= 1) && (index <= numParams))
697 : {
698 0 : b = boundParams[index - 1].allocBindDataBuffer(bufLen);
699 : }
700 :
701 0 : return b;
702 : }
703 : // -------------------------------------------------------------------------
704 :
705 : //--------------------------------------------------------------------
706 : // getLengthBuf
707 : // Gets the length buffer for the given parameter index
708 : //--------------------------------------------------------------------
709 :
710 0 : SQLLEN* OPreparedStatement::getLengthBuf (sal_Int32 index)
711 : {
712 0 : SQLLEN* b = NULL;
713 :
714 : // Sanity check the parameter number
715 :
716 0 : if ((index >= 1) &&
717 : (index <= numParams))
718 : {
719 0 : b = boundParams[index - 1].getBindLengthBuffer ();
720 : }
721 :
722 0 : return b;
723 : }
724 : // -------------------------------------------------------------------------
725 :
726 : //--------------------------------------------------------------------
727 : // putParamData
728 : // Puts parameter data from a previously bound input stream. The
729 : // input stream was bound using SQL_LEN_DATA_AT_EXEC.
730 : //--------------------------------------------------------------------
731 :
732 0 : void OPreparedStatement::putParamData (sal_Int32 index) throw(SQLException)
733 : {
734 : // Sanity check the parameter index
735 0 : if ((index < 1) ||
736 : (index > numParams))
737 : {
738 0 : return;
739 : }
740 :
741 : // We'll transfer up to MAX_PUT_DATA_LENGTH at a time
742 0 : Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH );
743 :
744 : // Get the information about the input stream
745 :
746 0 : Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream ();
747 0 : if ( !inputStream.is() )
748 : {
749 0 : ::connectivity::SharedResources aResources;
750 0 : const ::rtl::OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM));
751 0 : throw SQLException (sError, *this,::rtl::OUString(),0,Any());
752 : }
753 :
754 0 : sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen ();
755 :
756 : // Loop while more data from the input stream
757 0 : sal_Int32 haveRead = 0;
758 : try
759 : {
760 :
761 0 : do
762 : {
763 0 : sal_Int32 toReadThisRound = ::std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft );
764 :
765 : // Read some data from the input stream
766 0 : haveRead = inputStream->readBytes( buf, toReadThisRound );
767 : OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" );
768 :
769 0 : if ( !haveRead )
770 : // no more data in the stream - the given stream length was a maximum which could not be
771 : // fulfilled by the stream
772 0 : break;
773 :
774 : // Put the data
775 : OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" );
776 0 : N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() );
777 :
778 : // decrement the number of bytes still needed
779 0 : maxBytesLeft -= haveRead;
780 : }
781 : while ( maxBytesLeft > 0 );
782 : }
783 0 : catch (const IOException& ex)
784 : {
785 :
786 : // If an I/O exception was generated, turn
787 : // it into a SQLException
788 :
789 0 : throw SQLException(ex.Message,*this,::rtl::OUString(),0,Any());
790 0 : }
791 : }
792 : // -------------------------------------------------------------------------
793 :
794 : //--------------------------------------------------------------------
795 : // setStream
796 : // Sets an input stream as a parameter, using the given SQL type
797 : //--------------------------------------------------------------------
798 :
799 0 : void OPreparedStatement::setStream(
800 : sal_Int32 ParameterIndex,
801 : const Reference< XInputStream>& x,
802 : SQLLEN length,
803 : sal_Int32 _nType)
804 : throw(SQLException)
805 : {
806 0 : ::osl::MutexGuard aGuard( m_aMutex );
807 0 : checkDisposed(OStatement_BASE::rBHelper.bDisposed);
808 :
809 :
810 0 : prepareStatement();
811 :
812 0 : checkParameterIndex(ParameterIndex);
813 : // Get the buffer needed for the length
814 :
815 0 : SQLLEN * const lenBuf = getLengthBuf(ParameterIndex);
816 :
817 : // Allocate a new buffer for the parameter data. This buffer
818 : // will be returned by SQLParamData (it is set to the parameter
819 : // number, a sal_Int32)
820 :
821 0 : sal_Int32* dataBuf = static_cast<sal_Int32*>( allocBindBuf(ParameterIndex, sizeof(ParameterIndex)) );
822 0 : *dataBuf = ParameterIndex;
823 :
824 : // Bind the parameter with SQL_LEN_DATA_AT_EXEC
825 0 : *lenBuf = SQL_LEN_DATA_AT_EXEC (length);
826 :
827 : SQLSMALLINT fCType, fSqlType;
828 0 : OTools::getBindTypes(useWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
829 :
830 :
831 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
832 0 : N3SQLBindParameter(m_aStatementHandle,
833 : static_cast<SQLUSMALLINT>(ParameterIndex),
834 : SQL_PARAM_INPUT,
835 : fCType,
836 : fSqlType,
837 : length,
838 : invalid_scale,
839 : dataBuf,
840 : sizeof(ParameterIndex),
841 0 : lenBuf);
842 :
843 : // Save the input stream
844 0 : boundParams[ParameterIndex - 1].setInputStream (x, length);
845 0 : }
846 : // -------------------------------------------------------------------------
847 :
848 : // -------------------------------------------------------------------------
849 :
850 0 : void OPreparedStatement::FreeParams()
851 : {
852 0 : numParams = 0;
853 0 : delete [] boundParams;
854 0 : boundParams = NULL;
855 0 : }
856 : // -------------------------------------------------------------------------
857 0 : void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception)
858 : {
859 : try
860 : {
861 0 : switch(nHandle)
862 : {
863 : case PROPERTY_ID_RESULTSETCONCURRENCY:
864 0 : if(!isPrepared())
865 0 : setResultSetConcurrency(comphelper::getINT32(rValue));
866 0 : break;
867 : case PROPERTY_ID_RESULTSETTYPE:
868 0 : if(!isPrepared())
869 0 : setResultSetType(comphelper::getINT32(rValue));
870 0 : break;
871 : case PROPERTY_ID_FETCHDIRECTION:
872 0 : if(!isPrepared())
873 0 : setFetchDirection(comphelper::getINT32(rValue));
874 0 : break;
875 : case PROPERTY_ID_USEBOOKMARKS:
876 0 : if(!isPrepared())
877 0 : setUsingBookmarks(comphelper::getBOOL(rValue));
878 0 : break;
879 : default:
880 0 : OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue);
881 : }
882 : }
883 0 : catch(const SQLException&)
884 : {
885 : // throw Exception(e.Message,*this);
886 : }
887 0 : }
888 : // -----------------------------------------------------------------------------
889 0 : void OPreparedStatement::prepareStatement()
890 : {
891 0 : if(!isPrepared())
892 : {
893 : OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
894 0 : ::rtl::OString aSql(::rtl::OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding()));
895 0 : SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle,(SDB_ODBC_CHAR *) aSql.getStr(),aSql.getLength());
896 0 : OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
897 0 : m_bPrepared = sal_True;
898 0 : initBoundParam();
899 : }
900 0 : }
901 : // -----------------------------------------------------------------------------
902 0 : void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex)
903 : {
904 0 : if( _parameterIndex > numParams ||
905 : _parameterIndex < 1 ||
906 0 : _parameterIndex > std::numeric_limits<SQLUSMALLINT>::max() )
907 : {
908 0 : ::connectivity::SharedResources aResources;
909 : const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX,
910 : "$pos$", ::rtl::OUString::valueOf(_parameterIndex),
911 : "$count$", ::rtl::OUString::valueOf((sal_Int32)numParams)
912 0 : ));
913 0 : SQLException aNext(sError,*this, ::rtl::OUString(),0,Any());
914 :
915 0 : ::dbtools::throwInvalidIndexException(*this,makeAny(aNext));
916 : }
917 0 : }
918 : // -----------------------------------------------------------------------------
919 0 : OResultSet* OPreparedStatement::createResulSet()
920 : {
921 0 : OResultSet* pReturn = new OResultSet(m_aStatementHandle,this);
922 0 : pReturn->setMetaData(getMetaData());
923 0 : return pReturn;
924 : }
925 : // -----------------------------------------------------------------------------
926 :
927 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|