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 <sal/log.hxx>
38 #include "pq_statement.hxx"
39 #include "pq_fakedupdateableresultset.hxx"
40 #include "pq_updateableresultset.hxx"
41 #include "pq_tools.hxx"
42 #include "pq_statics.hxx"
46 #include <rtl/ustrbuf.hxx>
48 #include <comphelper/sequence.hxx>
50 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
51 #include <com/sun/star/sdbc/ResultSetType.hpp>
52 #include <com/sun/star/sdbc/SQLException.hpp>
53 #include <com/sun/star/sdbc/XParameters.hpp>
55 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
56 #include <com/sun/star/sdbcx/KeyType.hpp>
57 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
59 #include <com/sun/star/container/XIndexAccess.hpp>
60 #include <com/sun/star/container/XEnumerationAccess.hpp>
64 #include <string_view>
66 using osl::MutexGuard
;
69 using com::sun::star::uno::Any
;
70 using com::sun::star::uno::Type
;
71 using com::sun::star::uno::Sequence
;
72 using com::sun::star::uno::Reference
;
73 using com::sun::star::uno::XInterface
;
74 using com::sun::star::uno::UNO_QUERY
;
76 using com::sun::star::lang::IllegalArgumentException
;
78 using com::sun::star::sdbc::XCloseable
;
79 using com::sun::star::sdbc::XStatement
;
80 using com::sun::star::sdbc::XPreparedStatement
;
81 using com::sun::star::sdbc::XParameters
;
82 using com::sun::star::sdbc::XRow
;
83 using com::sun::star::sdbc::XResultSet
;
84 using com::sun::star::sdbc::XConnection
;
85 using com::sun::star::sdbc::SQLException
;
87 using com::sun::star::sdbcx::XColumnsSupplier
;
88 using com::sun::star::sdbcx::XKeysSupplier
;
90 using com::sun::star::beans::Property
;
91 using com::sun::star::beans::XPropertySetInfo
;
92 using com::sun::star::beans::XPropertySet
;
94 using com::sun::star::container::XNameAccess
;
95 using com::sun::star::container::XEnumerationAccess
;
96 using com::sun::star::container::XEnumeration
;
97 using com::sun::star::container::XIndexAccess
;
99 namespace pq_sdbc_driver
101 static ::cppu::IPropertyArrayHelper
& getStatementPropertyArrayHelper()
103 static ::cppu::OPropertyArrayHelper
arrayHelper(
106 u
"CursorName"_ustr
, 0,
107 ::cppu::UnoType
<OUString
>::get() , 0 ),
109 u
"EscapeProcessing"_ustr
, 1,
110 cppu::UnoType
<bool>::get() , 0 ),
112 u
"FetchDirection"_ustr
, 2,
113 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
115 u
"FetchSize"_ustr
, 3,
116 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
118 u
"MaxFieldSize"_ustr
, 4,
119 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
122 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
124 u
"QueryTimeOut"_ustr
, 6,
125 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
127 u
"ResultSetConcurrency"_ustr
, 7,
128 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
130 u
"ResultSetType"_ustr
, 8,
131 ::cppu::UnoType
<sal_Int32
>::get() , 0 )},
137 Statement::Statement( const ::rtl::Reference
< comphelper::RefCountedMutex
> & refMutex
,
138 const Reference
< XConnection
> & conn
,
139 struct ConnectionSettings
*pSettings
)
140 : Statement_BASE( refMutex
->GetMutex() )
141 , OPropertySetHelper( Statement_BASE::rBHelper
)
142 , m_connection( conn
)
143 , m_pSettings( pSettings
)
144 , m_xMutex( refMutex
)
145 , m_multipleResultAvailable(false)
146 , m_multipleResultUpdateCount(0)
147 , m_lastOidInserted(InvalidOid
)
149 m_props
[STATEMENT_QUERY_TIME_OUT
] <<= sal_Int32(0);
150 m_props
[STATEMENT_MAX_ROWS
] <<= sal_Int32(0);
151 m_props
[STATEMENT_RESULT_SET_CONCURRENCY
] <<=
152 css::sdbc::ResultSetConcurrency::READ_ONLY
;
153 m_props
[STATEMENT_RESULT_SET_TYPE
] <<=
154 css::sdbc::ResultSetType::SCROLL_INSENSITIVE
;
157 Statement::~Statement()
161 void Statement::checkClosed()
163 if( ! m_pSettings
|| ! m_pSettings
->pConnection
)
165 u
"pq_driver: Statement or connection has already been closed !"_ustr
,
166 *this, OUString(),1,Any());
169 Any
Statement::queryInterface( const Type
& rType
)
171 Any aRet
= Statement_BASE::queryInterface(rType
);
172 return aRet
.hasValue() ? aRet
: OPropertySetHelper::queryInterface(rType
);
176 Sequence
< Type
> Statement::getTypes()
178 static Sequence
< Type
> collection(
179 ::comphelper::concatSequences(
180 OPropertySetHelper::getTypes(),
181 Statement_BASE::getTypes()));
186 Sequence
< sal_Int8
> Statement::getImplementationId()
188 return css::uno::Sequence
<sal_Int8
>();
191 void Statement::close( )
193 // let the connection die without acquired mutex !
194 Reference
< XConnection
> r
;
195 Reference
< XCloseable
> resultSet
;
197 MutexGuard
guard( m_xMutex
->GetMutex() );
198 m_pSettings
= nullptr;
200 m_connection
.clear();
202 resultSet
= m_lastResultset
;
203 m_lastResultset
.clear();
212 void Statement::raiseSQLException(
213 std::u16string_view sql
, const char * errorMsg
)
215 OUString error
= "pq_driver: "
216 + OUString( errorMsg
, strlen(errorMsg
), ConnectionSettings::encoding
)
217 + " (caused by statement '" + sql
+ "')";
218 SAL_WARN("connectivity.postgresql", error
);
219 throw SQLException( error
, *this, OUString(), 1, Any() );
222 Reference
< XResultSet
> Statement::executeQuery(const OUString
& sql
)
224 if( ! execute( sql
) )
226 raiseSQLException( sql
, "not a query" );
228 return Reference
< XResultSet
> ( m_lastResultset
, css::uno::UNO_QUERY
);
231 sal_Int32
Statement::executeUpdate( const OUString
& sql
)
235 raiseSQLException( sql
, "not a command" );
237 return m_multipleResultUpdateCount
;
240 /// @throws SQLException
241 static void raiseSQLException(
242 const Reference
< XInterface
> & owner
,
243 std::string_view sql
,
244 const char * errorMsg
,
245 const char *errorType
= nullptr )
247 OUStringBuffer
buf(128);
248 buf
.append( "pq_driver: ");
252 buf
.appendAscii( errorType
);
256 OUString( errorMsg
, strlen(errorMsg
) , ConnectionSettings::encoding
)
257 + " (caused by statement '"
258 + OStringToOUString( sql
, ConnectionSettings::encoding
)
260 OUString error
= buf
.makeStringAndClear();
261 SAL_WARN("connectivity.postgresql", error
);
262 throw SQLException( error
, owner
, OUString(), 1, Any() );
266 // returns the elements of the primary key of the given table
267 // static Sequence< Reference< css::beans::XPropertySet > > lookupKeys(
268 static std::vector
< OUString
> lookupKeys(
269 const Reference
< css::container::XNameAccess
> &tables
,
270 const OUString
& table
,
274 std::vector
< OUString
> ret
;
275 Reference
< XKeysSupplier
> keySupplier
;
276 Statics
& st
= getStatics();
278 if( tables
->hasByName( table
) )
279 tables
->getByName( table
) >>= keySupplier
;
280 else if( -1 == table
.indexOf( '.' ) )
282 // it wasn't a fully qualified name. Now need to skip through all tables.
283 Reference
< XEnumerationAccess
> enumerationAccess( tables
, UNO_QUERY
);
285 Reference
< css::container::XEnumeration
> enumeration
=
286 enumerationAccess
->createEnumeration();
287 while( enumeration
->hasMoreElements() )
289 Reference
< XPropertySet
> set
;
290 enumeration
->nextElement() >>= set
;
294 if( set
->getPropertyValue( st
.NAME
) >>= name
)
296 // printf( "searching %s %s\n",
297 // OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
298 // OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
302 if( keySupplier
.is() )
304 // is ambiguous, as I don't know postgresql searchpath,
305 // I can't continue here, as I may write to a different table
307 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name
<< " is duplicated, add schema to resolve ambiguity");
310 keySupplier
.set( set
, UNO_QUERY
);
317 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table
<< " is unknown)");
320 if( keySupplier
.is() )
322 Reference
< XPropertySet
> set( keySupplier
, UNO_QUERY
);
323 set
->getPropertyValue( getStatics().NAME
) >>= *pTable
;
324 set
->getPropertyValue( getStatics().SCHEMA_NAME
) >>= *pSchema
;
327 Reference
< XEnumerationAccess
> keys ( keySupplier
->getKeys(), UNO_QUERY
);
328 Reference
< XEnumeration
> enumeration
= keys
->createEnumeration();
329 while( enumeration
->hasMoreElements() )
331 enumeration
->nextElement() >>= set
;
332 sal_Int32 keyType
= 0;
333 if( (set
->getPropertyValue( st
.TYPE
) >>= keyType
) &&
334 keyType
== css::sdbcx::KeyType::PRIMARY
)
336 Reference
< XColumnsSupplier
> columns( set
, UNO_QUERY
);
337 Reference
< XIndexAccess
> indexAccess( columns
->getColumns(), UNO_QUERY
);
339 int length
= indexAccess
->getCount();
340 ret
.resize( length
);
341 // printf( "primary key for Table %s is ",
342 // OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
343 for( int i
= 0 ; i
< length
; i
++ )
345 indexAccess
->getByIndex( i
) >>= set
;
347 set
->getPropertyValue( st
.NAME
) >>= name
;
349 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
356 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table
<< " does not have a primary key)");
362 bool executePostgresCommand( const OString
& cmd
, struct CommandData
*data
)
364 ConnectionSettings
*pSettings
= *(data
->ppSettings
);
366 sal_Int32 duration
= osl_getGlobalTimer();
367 PGresult
*result
= PQexec( pSettings
->pConnection
, cmd
.getStr() );
368 duration
= osl_getGlobalTimer() - duration
;
371 data
->owner
, cmd
, PQerrorMessage( pSettings
->pConnection
) );
373 ExecStatusType state
= PQresultStatus( result
);
374 *(data
->pLastOidInserted
) = 0;
375 data
->pLastTableInserted
->clear();
376 *(data
->pLastQuery
) = cmd
;
381 case PGRES_COMMAND_OK
:
383 *(data
->pMultipleResultUpdateCount
) = atoi( PQcmdTuples( result
) );
384 *(data
->pMultipleResultAvailable
) = false;
386 // in case an oid value is available, we retrieve it
387 *(data
->pLastOidInserted
) = PQoidValue( result
);
389 // in case it was a single insert, extract the name of the table,
390 // otherwise the table name is empty
391 *(data
->pLastTableInserted
) =
392 extractTableFromInsert( OStringToOUString( cmd
, ConnectionSettings::encoding
) );
394 OString strMain
= "executed command '" + cmd
+ "' successfully ('" + OString::number(*( data
->pMultipleResultUpdateCount
))
395 + "), duration=" + OString::number(duration
) + "ms";
398 if( *(data
->pLastOidInserted
) )
400 strOption
+= ", usedOid=" + OString::number( *(data
->pLastOidInserted
) ) + ", diagnosedTable="
401 + OUStringToOString(*data
->pLastTableInserted
, ConnectionSettings::encoding
);
403 SAL_INFO("connectivity.postgresql", strMain
+ strOption
);
407 case PGRES_TUPLES_OK
: // success
409 // In case it is a single table, it has a primary key and all columns
410 // belonging to the primary key are in the result set, allow updateable result sets
412 OUString table
, schema
;
413 std::vector
< OString
> vec
;
414 tokenizeSQL( cmd
, vec
);
415 OUString sourceTable
=
417 extractSingleTableFromSelect( vec
), ConnectionSettings::encoding
);
419 if( data
->concurrency
==
420 css::sdbc::ResultSetConcurrency::UPDATABLE
)
423 if( sourceTable
.getLength() )
425 std::vector
< OUString
> sourceTableKeys
= lookupKeys(
426 pSettings
->tables
.is() ?
427 pSettings
->tables
: data
->tableSupplier
->getTables() ,
432 // check, whether the columns are in the result set (required !)
434 for( i
= 0 ; i
< sourceTableKeys
.size() ; i
++ )
438 OUStringToOString( sourceTableKeys
[i
] ,
439 ConnectionSettings::encoding
).getStr()) )
445 if( !sourceTableKeys
.empty() && i
== sourceTableKeys
.size() )
447 *(data
->pLastResultset
) =
448 UpdateableResultSet::createFromPGResultSet(
449 data
->refMutex
, data
->owner
, data
->ppSettings
, result
,
450 schema
, table
, std::move(sourceTableKeys
) );
452 else if( ! table
.getLength() )
454 aReason
= "can't support updateable resultset, because a single table in the "
455 "WHERE part of the statement could not be identified (" + cmd
+ ".";
457 else if( !sourceTableKeys
.empty() )
459 aReason
= "can't support updateable resultset for table "
460 + OUStringToOString( schema
, ConnectionSettings::encoding
) + "."
461 + OUStringToOString( table
, ConnectionSettings::encoding
)
462 + ", because resultset does not contain a part of the primary key ( column "
463 + OUStringToOString( sourceTableKeys
[i
], ConnectionSettings::encoding
)
469 aReason
= "can't support updateable resultset for table "
470 + OUStringToOString( schema
, ConnectionSettings::encoding
) + "."
471 + OUStringToOString( table
, ConnectionSettings::encoding
)
472 + ", because resultset table does not have a primary key ";
477 SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd
<< ")");
479 if( ! (*(data
->pLastResultset
)).is() )
481 SAL_WARN("connectivity.postgresql", aReason
);
483 // TODO: How to react here correctly ?
484 // remove this piece of code
485 *(data
->pLastResultset
) =
486 new FakedUpdateableResultSet(
487 data
->refMutex
, data
->owner
,
488 data
->ppSettings
,result
, schema
, table
,
489 OStringToOUString( aReason
, ConnectionSettings::encoding
) );
493 else if( sourceTable
.getLength() > 0)
495 splitConcatenatedIdentifier( sourceTable
, &schema
, &table
);
498 sal_Int32 returnedRows
= PQntuples( result
);
499 if( ! data
->pLastResultset
->is() )
500 *(data
->pLastResultset
) =
501 Reference
< XCloseable
> (
503 data
->refMutex
, data
->owner
,
504 data
->ppSettings
,result
, schema
, table
) );
505 *(data
->pMultipleResultAvailable
) = true;
507 SAL_INFO("connectivity.postgresql", "executed query '" << cmd
<< "' successfully, duration=" << duration
<< "ms, returnedRows=" << returnedRows
<< ".");
510 case PGRES_EMPTY_QUERY
:
513 case PGRES_BAD_RESPONSE
:
514 case PGRES_NONFATAL_ERROR
:
515 case PGRES_FATAL_ERROR
:
518 data
->owner
, cmd
, PQresultErrorMessage( result
) , PQresStatus( state
) );
524 static Sequence
< OUString
> getPrimaryKeyColumnNames(
525 const Reference
< XConnection
> & connection
, const OUString
&schemaName
, const OUString
&tableName
)
527 Sequence
< OUString
> ret
;
529 Int2StringMap mapIndex2Name
;
530 fillAttnum2attnameMap( mapIndex2Name
, connection
, schemaName
, tableName
);
532 // retrieve the primary key ...
533 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
534 u
"SELECT conkey " // 7
535 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
536 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
537 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
538 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
539 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'"_ustr
);
540 DisposeGuard
guard( stmt
);
541 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
542 paras
->setString( 1 , tableName
);
543 paras
->setString( 2 , schemaName
);
544 Reference
< XResultSet
> rs
= stmt
->executeQuery();
545 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
549 ret
= convertMappedIntArray2StringArray( mapIndex2Name
, string2intarray(xRow
->getString( 1 ) ) );
554 static void getAutoValues(
555 String2StringMap
& result
,
556 const Reference
< XConnection
> & connection
,
557 const OUString
&schemaName
,
558 const OUString
& tableName
,
559 const ConnectionSettings
*pConnectionSettings
)
561 OUString strDefaultValue
= getColExprForDefaultSettingVal(pConnectionSettings
);
562 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
563 "SELECT pg_attribute.attname, " + strDefaultValue
+
564 "FROM pg_class, pg_namespace, pg_attribute "
565 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
566 "pg_attribute.attnum = pg_attrdef.adnum "
567 "WHERE pg_attribute.attrelid = pg_class.oid AND "
568 "pg_class.relnamespace = pg_namespace.oid AND "
569 "pg_namespace.nspname = ? AND "
570 // LEM TODO: this is weird; why "LIKE" and not "="?
571 // Most probably gives problems if tableName contains '%'
572 "pg_class.relname LIKE ? AND "
573 + strDefaultValue
+ " != ''"
575 DisposeGuard
guard( stmt
);
576 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
577 paras
->setString( 1 , schemaName
);
578 paras
->setString( 2 , tableName
);
579 Reference
< XResultSet
> rs
= stmt
->executeQuery();
580 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
584 result
[ OUStringToOString( xRow
->getString( 1 ), RTL_TEXTENCODING_ASCII_US
) ] =
585 OUStringToOString( xRow
->getString(2), RTL_TEXTENCODING_ASCII_US
);
589 Reference
< XResultSet
> getGeneratedValuesFromLastInsert(
590 ConnectionSettings
*pConnectionSettings
,
591 const Reference
< XConnection
> &connection
,
593 std::u16string_view lastTableInserted
,
594 const OString
& lastQuery
)
596 Reference
< XResultSet
> ret
;
598 OUString schemaName
, tableName
;
599 splitConcatenatedIdentifier(
600 lastTableInserted
, &schemaName
, &tableName
);
602 if( nLastOid
&& lastTableInserted
.size() )
604 OUStringBuffer
buf( 128 );
605 buf
.append( "SELECT * FROM " );
606 if( schemaName
.getLength() )
607 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
609 bufferQuoteIdentifier( buf
, lastTableInserted
, pConnectionSettings
);
610 buf
.append( " WHERE oid = " + OUString::number(nLastOid
) );
611 query
= buf
.makeStringAndClear();
613 else if ( lastTableInserted
.size() && lastQuery
.getLength() )
615 // extract nameValue Pairs
616 String2StringMap namedValues
;
617 extractNameValuePairsFromInsert( namedValues
, lastQuery
);
620 // OStringBuffer buf( 128);
621 // buf.append( "extracting name/value from '" );
622 // buf.append( lastQuery.getStr() );
623 // buf.append( "' to [" );
624 // for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
626 // buf.append( ii->first.getStr() );
627 // buf.append( "=" );
628 // buf.append( ii->second.getStr() );
629 // buf.append( "," );
631 // buf.append( "]\n" );
632 // printf( "%s", buf.makeStringAndClear() );
634 // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
637 const Sequence
< OUString
> keyColumnNames
= getPrimaryKeyColumnNames( connection
, schemaName
, tableName
);
638 if( keyColumnNames
.hasElements() )
640 OUStringBuffer
buf( 128 );
641 buf
.append( "SELECT * FROM " );
642 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
643 buf
.append( " WHERE " );
644 bool bAdditionalCondition
= false;
645 String2StringMap autoValues
;
646 for( OUString
const & columnNameUnicode
: keyColumnNames
)
649 OString columnName
= OUStringToOString( columnNameUnicode
, ConnectionSettings::encoding
);
650 bool bColumnMatchNamedValue
= false;
651 for (auto const& namedValue
: namedValues
)
653 if( columnName
.equalsIgnoreAsciiCase( namedValue
.first
) )
655 value
= OStringToOUString( namedValue
.second
, ConnectionSettings::encoding
);
656 bColumnMatchNamedValue
= true;
661 // check, if a column of the primary key was not inserted explicitly,
662 if( !bColumnMatchNamedValue
)
664 if( autoValues
.empty() )
666 getAutoValues( autoValues
, connection
, schemaName
, tableName
, pConnectionSettings
);
668 // this could mean, that the column is a default or auto value, check this ...
669 bool bColumnMatchAutoValue
= false;
670 for (auto const& autoValue
: autoValues
)
672 if( columnName
.equalsIgnoreAsciiCase( autoValue
.first
) )
674 // it is indeed an auto value.
675 value
= OStringToOUString(autoValue
.second
, RTL_TEXTENCODING_ASCII_US
);
676 // check, whether it is a sequence
678 if( autoValue
.second
.startsWith("nextval(") )
680 // retrieve current sequence value:
681 OUStringBuffer
myBuf(128 );
682 myBuf
.append( "SELECT currval(" );
683 myBuf
.appendAscii( &(autoValue
.second
.getStr()[8]));
684 value
= querySingleValue( connection
, myBuf
.makeStringAndClear() );
686 bColumnMatchAutoValue
= true;
690 if( !bColumnMatchAutoValue
)
692 // it even was no autovalue, no sense to continue as we can't query the
699 if( bAdditionalCondition
)
700 buf
.append( " AND " );
701 bufferQuoteIdentifier( buf
, columnNameUnicode
, pConnectionSettings
);
702 buf
.append( " = " + value
);
703 bAdditionalCondition
= true;
705 query
= buf
.makeStringAndClear();
709 if( query
.getLength() )
711 Reference
< css::sdbc::XStatement
> stmt
= connection
->createStatement();
712 ret
= stmt
->executeQuery( query
);
719 sal_Bool
Statement::execute( const OUString
& sql
)
721 osl::MutexGuard
guard( m_xMutex
->GetMutex() );
723 OString cmd
= OUStringToOString( sql
, m_pSettings
);
725 Reference
< XCloseable
> lastResultSetHolder
= m_lastResultset
;
726 if( lastResultSetHolder
.is() )
727 lastResultSetHolder
->close();
729 m_lastResultset
.clear();
730 m_lastTableInserted
.clear();
732 struct CommandData data
;
733 data
.refMutex
= m_xMutex
;
734 data
.ppSettings
= &m_pSettings
;
735 data
.pLastOidInserted
= &m_lastOidInserted
;
736 data
.pLastQuery
= &m_lastQuery
;
737 data
.pMultipleResultUpdateCount
= &m_multipleResultUpdateCount
;
738 data
.pMultipleResultAvailable
= &m_multipleResultAvailable
;
739 data
.pLastTableInserted
= &m_lastTableInserted
;
740 data
.pLastResultset
= &m_lastResultset
;
742 data
.tableSupplier
.set( m_connection
, UNO_QUERY
);
744 extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY
);
745 return executePostgresCommand( cmd
, &data
);
748 Reference
< XConnection
> Statement::getConnection( )
750 Reference
< XConnection
> ret
;
752 MutexGuard
guard( m_xMutex
->GetMutex() );
760 Any
Statement::getWarnings( )
765 void Statement::clearWarnings( )
769 Reference
< css::sdbc::XResultSetMetaData
> Statement::getMetaData()
771 Reference
< css::sdbc::XResultSetMetaData
> ret
;
772 Reference
< css::sdbc::XResultSetMetaDataSupplier
> supplier( m_lastResultset
, UNO_QUERY
);
774 ret
= supplier
->getMetaData();
779 ::cppu::IPropertyArrayHelper
& Statement::getInfoHelper()
781 return getStatementPropertyArrayHelper();
785 sal_Bool
Statement::convertFastPropertyValue(
786 Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
788 rOldValue
= m_props
[nHandle
];
792 case STATEMENT_CURSOR_NAME
:
795 bRet
= ( rValue
>>= val
);
796 rConvertedValue
<<= val
;
799 case STATEMENT_ESCAPE_PROCESSING
:
802 bRet
= ( rValue
>>= val
);
803 rConvertedValue
<<= val
;
806 case STATEMENT_FETCH_DIRECTION
:
807 case STATEMENT_FETCH_SIZE
:
808 case STATEMENT_MAX_FIELD_SIZE
:
809 case STATEMENT_MAX_ROWS
:
810 case STATEMENT_QUERY_TIME_OUT
:
811 case STATEMENT_RESULT_SET_CONCURRENCY
:
812 case STATEMENT_RESULT_SET_TYPE
:
815 bRet
= ( rValue
>>= val
);
816 rConvertedValue
<<= val
;
821 throw IllegalArgumentException(
822 "pq_statement: Invalid property handle ("
823 + OUString::number( nHandle
) + ")",
831 void Statement::setFastPropertyValue_NoBroadcast(
832 sal_Int32 nHandle
,const Any
& rValue
)
834 m_props
[nHandle
] = rValue
;
837 void Statement::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
839 rValue
= m_props
[nHandle
];
842 Reference
< XPropertySetInfo
> Statement::getPropertySetInfo()
844 return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
848 Reference
< XResultSet
> Statement::getResultSet( )
850 return Reference
< XResultSet
> ( m_lastResultset
, css::uno::UNO_QUERY
);
853 sal_Int32
Statement::getUpdateCount( )
855 return m_multipleResultUpdateCount
;
858 sal_Bool
Statement::getMoreResults( )
860 // The PostgreSQL C interface always returns a single result,
861 // so we will never have multiple ones.
862 // Implicitly close the open resultset (if any) as per spec,
863 // and setup to signal "no more result, neither as resultset,
864 // nor as update count".
865 Reference
< XCloseable
> lastResultSetHolder
= m_lastResultset
;
866 if( lastResultSetHolder
.is() )
867 lastResultSetHolder
->close();
868 m_multipleResultUpdateCount
= -1;
873 void Statement::disposing()
878 Reference
< XResultSet
> Statement::getGeneratedValues( )
880 osl::MutexGuard
guard( m_xMutex
->GetMutex() );
881 return getGeneratedValuesFromLastInsert(
882 m_pSettings
, m_connection
, m_lastOidInserted
, m_lastTableInserted
, m_lastQuery
);
887 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */