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