bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_preparedstatement.cxx
blob13fbcdf035790a6c127ef273755ef3d18882d77c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18 * MA 02111-1307 USA
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 ************************************************************************/
37 #include "pq_preparedstatement.hxx"
38 #include "pq_resultset.hxx"
39 #include "pq_tools.hxx"
40 #include "pq_statics.hxx"
41 #include "pq_statement.hxx"
43 #include <rtl/strbuf.hxx>
44 #include <rtl/ustrbuf.hxx>
47 #include <cppuhelper/typeprovider.hxx>
48 #include <cppuhelper/queryinterface.hxx>
49 #include <comphelper/sequence.hxx>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
53 #include <com/sun/star/sdbc/ResultSetType.hpp>
54 #include <com/sun/star/sdbc/SQLException.hpp>
56 #include <string.h>
58 #include <connectivity/dbconversion.hxx>
60 using osl::MutexGuard;
63 using com::sun::star::uno::Any;
64 using com::sun::star::uno::Type;
65 using com::sun::star::uno::Sequence;
66 using com::sun::star::uno::Reference;
67 using com::sun::star::uno::UNO_QUERY;
69 using com::sun::star::lang::IllegalArgumentException;
71 using com::sun::star::sdbc::XCloseable;
72 using com::sun::star::sdbc::XResultSet;
73 using com::sun::star::sdbc::XRef;
74 using com::sun::star::sdbc::XBlob;
75 using com::sun::star::sdbc::XClob;
76 using com::sun::star::sdbc::XArray;
77 using com::sun::star::sdbc::XConnection;
78 using com::sun::star::sdbc::SQLException;
80 using com::sun::star::beans::Property;
81 using com::sun::star::beans::XPropertySetInfo;
83 using namespace dbtools;
85 namespace pq_sdbc_driver
87 static ::cppu::IPropertyArrayHelper & getPreparedStatementPropertyArrayHelper()
89 static ::cppu::OPropertyArrayHelper arrayHelper(
90 Sequence<Property>{
91 Property(
92 "CursorName", 0,
93 ::cppu::UnoType<OUString>::get() , 0 ),
94 Property(
95 "EscapeProcessing", 1,
96 cppu::UnoType<bool>::get() , 0 ),
97 Property(
98 "FetchDirection", 2,
99 ::cppu::UnoType<sal_Int32>::get() , 0 ),
100 Property(
101 "FetchSize", 3,
102 ::cppu::UnoType<sal_Int32>::get() , 0 ),
103 Property(
104 "MaxFieldSize", 4,
105 ::cppu::UnoType<sal_Int32>::get() , 0 ),
106 Property(
107 "MaxRows", 5,
108 ::cppu::UnoType<sal_Int32>::get() , 0 ),
109 Property(
110 "QueryTimeOut", 6,
111 ::cppu::UnoType<sal_Int32>::get() , 0 ),
112 Property(
113 "ResultSetConcurrency", 7,
114 ::cppu::UnoType<sal_Int32>::get() , 0 ),
115 Property(
116 "ResultSetType", 8,
117 ::cppu::UnoType<sal_Int32>::get() , 0 )},
118 true );
119 static ::cppu::IPropertyArrayHelper *pArrayHelper = &arrayHelper;
121 return *pArrayHelper;
124 static bool isOperator( char c )
126 static const char * const operators = "<>=()!/&%.,;";
128 const char * w = operators;
129 while (*w && *w != c)
131 ++w;
133 return *w != 0;
136 static bool isNamedParameterStart( const OString & o , int index )
138 return o[index] == ':' && (
139 isWhitespace( o[index-1] ) || isOperator(o[index-1]) );
142 static bool isQuoted( const OString & str )
144 return str[0] == '"' || str[0] == '\'';
147 PreparedStatement::PreparedStatement(
148 const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
149 const Reference< XConnection > & conn,
150 struct ConnectionSettings *pSettings,
151 const OString & stmt )
152 : PreparedStatement_BASE(refMutex->GetMutex())
153 , OPropertySetHelper(PreparedStatement_BASE::rBHelper)
154 , m_connection(conn)
155 , m_pSettings(pSettings)
156 , m_stmt(stmt)
157 , m_xMutex(refMutex)
158 , m_multipleResultAvailable(false)
159 , m_multipleResultUpdateCount(0)
160 , m_lastOidInserted( InvalidOid )
162 m_props[PREPARED_STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0);
163 m_props[PREPARED_STATEMENT_MAX_ROWS] <<= sal_Int32(0);
164 m_props[PREPARED_STATEMENT_RESULT_SET_CONCURRENCY] <<=
165 css::sdbc::ResultSetConcurrency::READ_ONLY;
166 m_props[PREPARED_STATEMENT_RESULT_SET_TYPE] <<=
167 css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
169 splitSQL( m_stmt, m_splittedStatement );
170 int elements = 0;
171 for(OString & str : m_splittedStatement)
173 // ignore quoted strings ....
174 if( ! isQuoted( str ) )
176 // the ':' cannot be the first or the last part of the
177 // token,
178 // the ? cannot be the first part of the token , so we start
179 // at one
180 for( int index = 1 ; index < str.getLength() ; index ++ )
182 if( str[index] == '?' ||
183 isNamedParameterStart( str , index )
186 elements ++;
191 m_vars = std::vector< OString >( elements );
194 PreparedStatement::~PreparedStatement()
196 POSTGRE_TRACE( "dtor PreparedStatement" );
199 void PreparedStatement::checkColumnIndex( sal_Int32 parameterIndex )
201 if( parameterIndex < 1 || parameterIndex > static_cast<sal_Int32>(m_vars.size()) )
203 throw SQLException(
204 "pq_preparedstatement: parameter index out of range (expected 1 to "
205 + OUString::number( m_vars.size() )
206 + ", got " + OUString::number( parameterIndex )
207 + ", statement '" + OStringToOUString( m_stmt, ConnectionSettings::encoding )
208 + "')",
209 *this, OUString(), 1, Any () );
212 void PreparedStatement::checkClosed()
214 if( ! m_pSettings || ! m_pSettings->pConnection )
215 throw SQLException(
216 "pq_driver: PreparedStatement or connection has already been closed !",
217 *this, OUString(),1,Any());
220 Any PreparedStatement::queryInterface( const Type & rType )
222 Any aRet = PreparedStatement_BASE::queryInterface(rType);
223 return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
227 Sequence< Type > PreparedStatement::getTypes()
229 static Sequence< Type > collection(
230 ::comphelper::concatSequences(
231 OPropertySetHelper::getTypes(),
232 PreparedStatement_BASE::getTypes()));
234 return collection;
237 Sequence< sal_Int8> PreparedStatement::getImplementationId()
239 return css::uno::Sequence<sal_Int8>();
242 void PreparedStatement::close( )
244 // let the connection die without acquired mutex !
245 Reference< XConnection > r;
246 Reference< XCloseable > resultSet;
248 MutexGuard guard( m_xMutex->GetMutex() );
249 m_pSettings = nullptr;
250 r = m_connection;
251 m_connection.clear();
253 resultSet = m_lastResultset;
254 m_lastResultset.clear();
256 if( resultSet.is() )
258 resultSet->close();
262 void PreparedStatement::raiseSQLException( const char * errorMsg )
264 OUStringBuffer buf(128);
265 buf.append( "pq_driver: ");
266 buf.append(
267 OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) );
268 buf.append( " (caused by statement '" );
269 buf.appendAscii( m_executedStatement.getStr() );
270 buf.append( "')" );
271 OUString error = buf.makeStringAndClear();
272 log(m_pSettings, LogLevel::Error, error);
273 throw SQLException( error, *this, OUString(), 1, Any() );
276 Reference< XResultSet > PreparedStatement::executeQuery( )
278 if( ! execute( ) )
280 raiseSQLException( "not a query" );
282 return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
285 sal_Int32 PreparedStatement::executeUpdate( )
287 if( execute( ) )
289 raiseSQLException( "not a command" );
291 return m_multipleResultUpdateCount;
294 sal_Bool PreparedStatement::execute( )
296 osl::MutexGuard guard( m_xMutex->GetMutex() );
298 OStringBuffer buf( m_stmt.getLength() *2 );
300 std::vector< OString >::size_type vars = 0;
301 for(OString & str : m_splittedStatement)
303 // LEM TODO: instead of this manual mucking with SQL
304 // could we use PQexecParams / PQExecPrepared / ...?
305 // Only snafu is giving the types of the parameters and
306 // that it needs $1, $2, etc instead of "?"
308 // printf( "Split %d %s\n" , i , str.getStr() );
309 if( isQuoted( str ) )
311 buf.append( str );
313 else
315 int start = 0,index;
316 for( index = 1 ; index < str.getLength() ; index ++ )
318 if( str[index] == '?' )
320 buf.append( str.getStr()+start, index - start );
321 buf.append( m_vars[vars] );
322 vars ++;
323 start =index+1;
325 else
327 if ( isNamedParameterStart( str, index ) )
329 buf.append( str.getStr()+start, index -start );
330 buf.append( m_vars[vars] );
332 // skip to the end of the named parameter
333 while ( index < str.getLength()
334 && !( isWhitespace(str[index])
335 || isOperator (str[index])))
337 ++index;
339 start = index;
340 vars ++;
344 // if( index +1 >= str.getLength() )
345 // {
346 buf.append( str.getStr() + start, index -start );
347 // }
351 m_executedStatement = buf.makeStringAndClear();
353 Reference< XCloseable > lastResultSet = m_lastResultset;
354 if( lastResultSet.is() )
355 lastResultSet->close();
357 m_lastResultset.clear();
358 m_lastTableInserted.clear();
360 struct CommandData data;
361 data.refMutex = m_xMutex;
362 data.ppSettings = &m_pSettings;
363 data.pLastOidInserted = &m_lastOidInserted;
364 data.pLastQuery = &m_lastQuery;
365 data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount;
366 data.pMultipleResultAvailable = &m_multipleResultAvailable;
367 data.pLastTableInserted = &m_lastTableInserted;
368 data.pLastResultset = &m_lastResultset;
369 data.owner = *this;
370 data.tableSupplier.set( m_connection, UNO_QUERY );
371 data.concurrency = extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY );
373 return executePostgresCommand( m_executedStatement , &data ); // see pq_statement.cxx
376 Reference< XConnection > PreparedStatement::getConnection( )
378 Reference< XConnection > ret;
380 MutexGuard guard( m_xMutex->GetMutex() );
381 checkClosed();
382 ret = m_connection;
384 return ret;
388 void PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 )
390 MutexGuard guard( m_xMutex->GetMutex() );
391 checkClosed();
392 checkColumnIndex( parameterIndex );
393 m_vars[parameterIndex-1] = OString( "NULL" );
396 void PreparedStatement::setObjectNull(
397 sal_Int32 parameterIndex, sal_Int32, const OUString& )
399 MutexGuard guard( m_xMutex->GetMutex() );
400 checkClosed();
401 checkColumnIndex( parameterIndex );
402 m_vars[parameterIndex-1] = OString( "NULL" );
406 void PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
408 MutexGuard guard(m_xMutex->GetMutex() );
409 checkClosed();
410 checkColumnIndex( parameterIndex );
411 if( x )
412 m_vars[parameterIndex-1] = OString( "'t'" );
413 else
414 m_vars[parameterIndex-1] = OString( "'f'" );
417 void PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
419 setInt(parameterIndex,x);
422 void PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
424 setInt(parameterIndex, x );
427 void PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
429 // printf( "setString %d %d\n ", parameterIndex, x);
430 MutexGuard guard(m_xMutex->GetMutex() );
431 checkClosed();
432 checkColumnIndex( parameterIndex );
433 OStringBuffer buf( 20 );
434 buf.append( "'" );
435 buf.append( x );
436 buf.append( "'" );
437 m_vars[parameterIndex-1] = buf.makeStringAndClear();
440 void PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
442 MutexGuard guard(m_xMutex->GetMutex() );
443 checkClosed();
444 checkColumnIndex( parameterIndex );
445 OStringBuffer buf( 20 );
446 buf.append( "'" );
447 buf.append( x );
448 buf.append( "'" );
449 m_vars[parameterIndex-1] = buf.makeStringAndClear();
452 void PreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
454 MutexGuard guard(m_xMutex->GetMutex() );
455 checkClosed();
456 checkColumnIndex( parameterIndex );
457 OStringBuffer buf( 20 );
458 buf.append( "'" );
459 buf.append( x );
460 buf.append( "'" );
461 m_vars[parameterIndex-1] = buf.makeStringAndClear();
464 void PreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
466 MutexGuard guard(m_xMutex->GetMutex() );
467 checkClosed();
468 checkColumnIndex( parameterIndex );
469 OStringBuffer buf( 20 );
470 buf.append( "'" );
471 buf.append( x );
472 buf.append( "'" );
473 m_vars[parameterIndex-1] = buf.makeStringAndClear();
476 void PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
478 // printf( "setString %d %s\n ", parameterIndex,
479 // OUStringToOString( x , RTL_TEXTENCODING_ASCII_US ).getStr());
480 MutexGuard guard(m_xMutex->GetMutex() );
481 checkClosed();
482 checkColumnIndex( parameterIndex );
483 OStringBuffer buf( 20 );
484 buf.append( "'" );
485 OString y = OUStringToOString( x, ConnectionSettings::encoding );
486 buf.ensureCapacity( y.getLength() * 2 + 2 );
487 int len = PQescapeString( const_cast<char*>(buf.getStr())+1, y.getStr() , y.getLength() );
488 buf.setLength( 1 + len );
489 buf.append( "'" );
490 m_vars[parameterIndex-1] = buf.makeStringAndClear();
493 void PreparedStatement::setBytes(
494 sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
496 MutexGuard guard(m_xMutex->GetMutex() );
497 checkClosed();
498 checkColumnIndex( parameterIndex );
499 OStringBuffer buf( 20 );
500 buf.append( "'" );
501 size_t len;
502 unsigned char * escapedString =
503 PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
504 if( ! escapedString )
506 throw SQLException(
507 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
508 *this, OUString(), 1, Any() );
510 buf.append( reinterpret_cast<char *>(escapedString), len -1 );
511 free( escapedString );
512 buf.append( "'" );
513 m_vars[parameterIndex-1] = buf.makeStringAndClear();
517 void PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
519 setString( parameterIndex, DBTypeConversion::toDateString( x ) );
522 void PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
524 setString( parameterIndex, DBTypeConversion::toTimeString( x ) );
527 void PreparedStatement::setTimestamp(
528 sal_Int32 parameterIndex, const css::util::DateTime& x )
530 setString( parameterIndex, DBTypeConversion::toDateTimeString( x ) );
533 void PreparedStatement::setBinaryStream(
534 sal_Int32,
535 const Reference< css::io::XInputStream >&,
536 sal_Int32 )
538 throw SQLException(
539 "pq_preparedstatement: setBinaryStream not implemented",
540 *this, OUString(), 1, Any () );
543 void PreparedStatement::setCharacterStream(
544 sal_Int32,
545 const Reference< css::io::XInputStream >&,
546 sal_Int32 )
548 throw SQLException(
549 "pq_preparedstatement: setCharacterStream not implemented",
550 *this, OUString(), 1, Any () );
553 void PreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
555 if( ! implSetObject( this, parameterIndex, x ))
557 throw SQLException(
558 "pq_preparedstatement::setObject: can't convert value of type " + x.getValueTypeName(),
559 *this, OUString(), 1, Any () );
563 void PreparedStatement::setObjectWithInfo(
564 sal_Int32 parameterIndex,
565 const Any& x,
566 sal_Int32 targetSqlType,
567 sal_Int32 )
569 if( css::sdbc::DataType::DECIMAL == targetSqlType ||
570 css::sdbc::DataType::NUMERIC == targetSqlType )
572 double myDouble = 0.0;
573 OUString myString;
574 if( x >>= myDouble )
576 myString = OUString::number( myDouble );
578 else
580 x >>= myString;
582 if( myString.isEmpty() )
584 throw SQLException(
585 "pq_preparedstatement::setObjectWithInfo: can't convert value of type "
586 + x.getValueTypeName() + " to type DECIMAL or NUMERIC",
587 *this, OUString(), 1, Any () );
590 setString( parameterIndex, myString );
592 else
594 setObject( parameterIndex, x );
599 void PreparedStatement::setRef(
600 sal_Int32,
601 const Reference< XRef >& )
603 throw SQLException(
604 "pq_preparedstatement: setRef not implemented",
605 *this, OUString(), 1, Any () );
608 void PreparedStatement::setBlob(
609 sal_Int32,
610 const Reference< XBlob >& )
612 throw SQLException(
613 "pq_preparedstatement: setBlob not implemented",
614 *this, OUString(), 1, Any () );
617 void PreparedStatement::setClob(
618 sal_Int32,
619 const Reference< XClob >& )
621 throw SQLException(
622 "pq_preparedstatement: setClob not implemented",
623 *this, OUString(), 1, Any () );
626 void PreparedStatement::setArray(
627 sal_Int32 parameterIndex,
628 const Reference< XArray >& x )
630 setString( parameterIndex, array2String( x->getArray( nullptr ) ) );
633 void PreparedStatement::clearParameters( )
635 MutexGuard guard(m_xMutex->GetMutex() );
636 m_vars = std::vector< OString >( m_vars.size() );
639 Any PreparedStatement::getWarnings( )
641 return Any();
644 void PreparedStatement::clearWarnings( )
648 Reference< css::sdbc::XResultSetMetaData > PreparedStatement::getMetaData()
650 Reference< css::sdbc::XResultSetMetaData > ret;
651 Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY );
652 if( supplier.is() )
653 ret = supplier->getMetaData();
654 return ret;
657 ::cppu::IPropertyArrayHelper & PreparedStatement::getInfoHelper()
659 return getPreparedStatementPropertyArrayHelper();
663 sal_Bool PreparedStatement::convertFastPropertyValue(
664 Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
666 bool bRet;
667 rOldValue = m_props[nHandle];
668 switch( nHandle )
670 case PREPARED_STATEMENT_CURSOR_NAME:
672 OUString val;
673 bRet = ( rValue >>= val );
674 rConvertedValue <<= val;
675 break;
677 case PREPARED_STATEMENT_ESCAPE_PROCESSING:
679 bool val(false);
680 bRet = ( rValue >>= val );
681 rConvertedValue <<= val;
682 break;
684 case PREPARED_STATEMENT_FETCH_DIRECTION:
685 case PREPARED_STATEMENT_FETCH_SIZE:
686 case PREPARED_STATEMENT_MAX_FIELD_SIZE:
687 case PREPARED_STATEMENT_MAX_ROWS:
688 case PREPARED_STATEMENT_QUERY_TIME_OUT:
689 case PREPARED_STATEMENT_RESULT_SET_CONCURRENCY:
690 case PREPARED_STATEMENT_RESULT_SET_TYPE:
692 sal_Int32 val;
693 bRet = ( rValue >>= val );
694 rConvertedValue <<= val;
695 break;
697 default:
699 throw IllegalArgumentException(
700 "pq_statement: Invalid property handle ("
701 + OUString::number( nHandle ) + ")",
702 *this, 2 );
705 return bRet;
709 void PreparedStatement::setFastPropertyValue_NoBroadcast(
710 sal_Int32 nHandle,const Any& rValue )
712 m_props[nHandle] = rValue;
715 void PreparedStatement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
717 rValue = m_props[nHandle];
720 Reference < XPropertySetInfo > PreparedStatement::getPropertySetInfo()
722 return OPropertySetHelper::createPropertySetInfo( getPreparedStatementPropertyArrayHelper() );
725 void PreparedStatement::disposing()
727 close();
731 Reference< XResultSet > PreparedStatement::getResultSet( )
733 return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
735 sal_Int32 PreparedStatement::getUpdateCount( )
737 return m_multipleResultUpdateCount;
739 sal_Bool PreparedStatement::getMoreResults( )
741 Reference< XCloseable > lastResultSet = m_lastResultset;
742 if( lastResultSet.is() )
743 lastResultSet->close();
744 m_multipleResultUpdateCount = -1;
745 return false;
748 Reference< XResultSet > PreparedStatement::getGeneratedValues( )
750 osl::MutexGuard guard( m_xMutex->GetMutex() );
751 return getGeneratedValuesFromLastInsert(
752 m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery );
758 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */