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,
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>
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(
93 ::cppu::UnoType
<OUString
>::get() , 0 ),
95 "EscapeProcessing", 1,
96 cppu::UnoType
<bool>::get() , 0 ),
99 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
102 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
105 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
108 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
111 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
113 "ResultSetConcurrency", 7,
114 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
117 ::cppu::UnoType
<sal_Int32
>::get() , 0 )},
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
)
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
)
155 , m_pSettings(pSettings
)
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
);
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
178 // the ? cannot be the first part of the token , so we start
180 for( int index
= 1 ; index
< str
.getLength() ; index
++ )
182 if( str
[index
] == '?' ||
183 isNamedParameterStart( str
, index
)
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()) )
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
)
209 *this, OUString(), 1, Any () );
212 void PreparedStatement::checkClosed()
214 if( ! m_pSettings
|| ! m_pSettings
->pConnection
)
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()));
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;
251 m_connection
.clear();
253 resultSet
= m_lastResultset
;
254 m_lastResultset
.clear();
262 void PreparedStatement::raiseSQLException( const char * errorMsg
)
264 OUStringBuffer
buf(128);
265 buf
.append( "pq_driver: ");
267 OUString( errorMsg
, strlen(errorMsg
) , ConnectionSettings::encoding
) );
268 buf
.append( " (caused by statement '" );
269 buf
.appendAscii( m_executedStatement
.getStr() );
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( )
280 raiseSQLException( "not a query" );
282 return Reference
< XResultSet
> ( m_lastResultset
, css::uno::UNO_QUERY
);
285 sal_Int32
PreparedStatement::executeUpdate( )
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
) )
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
] );
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
])))
344 // if( index +1 >= str.getLength() )
346 buf
.append( str
.getStr() + start
, index
-start
);
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
;
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() );
388 void PreparedStatement::setNull( sal_Int32 parameterIndex
, sal_Int32
)
390 MutexGuard
guard( m_xMutex
->GetMutex() );
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() );
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() );
410 checkColumnIndex( parameterIndex
);
412 m_vars
[parameterIndex
-1] = OString( "'t'" );
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() );
432 checkColumnIndex( parameterIndex
);
433 OStringBuffer
buf( 20 );
437 m_vars
[parameterIndex
-1] = buf
.makeStringAndClear();
440 void PreparedStatement::setLong( sal_Int32 parameterIndex
, sal_Int64 x
)
442 MutexGuard
guard(m_xMutex
->GetMutex() );
444 checkColumnIndex( parameterIndex
);
445 OStringBuffer
buf( 20 );
449 m_vars
[parameterIndex
-1] = buf
.makeStringAndClear();
452 void PreparedStatement::setFloat( sal_Int32 parameterIndex
, float x
)
454 MutexGuard
guard(m_xMutex
->GetMutex() );
456 checkColumnIndex( parameterIndex
);
457 OStringBuffer
buf( 20 );
461 m_vars
[parameterIndex
-1] = buf
.makeStringAndClear();
464 void PreparedStatement::setDouble( sal_Int32 parameterIndex
, double x
)
466 MutexGuard
guard(m_xMutex
->GetMutex() );
468 checkColumnIndex( parameterIndex
);
469 OStringBuffer
buf( 20 );
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() );
482 checkColumnIndex( parameterIndex
);
483 OStringBuffer
buf( 20 );
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
);
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() );
498 checkColumnIndex( parameterIndex
);
499 OStringBuffer
buf( 20 );
502 unsigned char * escapedString
=
503 PQescapeBytea( reinterpret_cast<unsigned char const *>(x
.getConstArray()), x
.getLength(), &len
);
504 if( ! escapedString
)
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
);
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(
535 const Reference
< css::io::XInputStream
>&,
539 "pq_preparedstatement: setBinaryStream not implemented",
540 *this, OUString(), 1, Any () );
543 void PreparedStatement::setCharacterStream(
545 const Reference
< css::io::XInputStream
>&,
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
))
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
,
566 sal_Int32 targetSqlType
,
569 if( css::sdbc::DataType::DECIMAL
== targetSqlType
||
570 css::sdbc::DataType::NUMERIC
== targetSqlType
)
572 double myDouble
= 0.0;
576 myString
= OUString::number( myDouble
);
582 if( myString
.isEmpty() )
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
);
594 setObject( parameterIndex
, x
);
599 void PreparedStatement::setRef(
601 const Reference
< XRef
>& )
604 "pq_preparedstatement: setRef not implemented",
605 *this, OUString(), 1, Any () );
608 void PreparedStatement::setBlob(
610 const Reference
< XBlob
>& )
613 "pq_preparedstatement: setBlob not implemented",
614 *this, OUString(), 1, Any () );
617 void PreparedStatement::setClob(
619 const Reference
< XClob
>& )
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( )
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
);
653 ret
= supplier
->getMetaData();
657 ::cppu::IPropertyArrayHelper
& PreparedStatement::getInfoHelper()
659 return getPreparedStatementPropertyArrayHelper();
663 sal_Bool
PreparedStatement::convertFastPropertyValue(
664 Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
667 rOldValue
= m_props
[nHandle
];
670 case PREPARED_STATEMENT_CURSOR_NAME
:
673 bRet
= ( rValue
>>= val
);
674 rConvertedValue
<<= val
;
677 case PREPARED_STATEMENT_ESCAPE_PROCESSING
:
680 bRet
= ( rValue
>>= val
);
681 rConvertedValue
<<= val
;
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
:
693 bRet
= ( rValue
>>= val
);
694 rConvertedValue
<<= val
;
699 throw IllegalArgumentException(
700 "pq_statement: Invalid property handle ("
701 + OUString::number( nHandle
) + ")",
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()
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;
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: */