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>
47 #include <rtl/strbuf.hxx>
49 #include <comphelper/sequence.hxx>
51 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
52 #include <com/sun/star/sdbc/ResultSetType.hpp>
53 #include <com/sun/star/sdbc/SQLException.hpp>
54 #include <com/sun/star/sdbc/XParameters.hpp>
56 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
57 #include <com/sun/star/sdbcx/KeyType.hpp>
58 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
60 #include <com/sun/star/container/XIndexAccess.hpp>
61 #include <com/sun/star/container/XEnumerationAccess.hpp>
65 using osl::MutexGuard
;
68 using com::sun::star::uno::Any
;
69 using com::sun::star::uno::Type
;
70 using com::sun::star::uno::Sequence
;
71 using com::sun::star::uno::Reference
;
72 using com::sun::star::uno::XInterface
;
73 using com::sun::star::uno::UNO_QUERY
;
75 using com::sun::star::lang::IllegalArgumentException
;
77 using com::sun::star::sdbc::XCloseable
;
78 using com::sun::star::sdbc::XStatement
;
79 using com::sun::star::sdbc::XPreparedStatement
;
80 using com::sun::star::sdbc::XParameters
;
81 using com::sun::star::sdbc::XRow
;
82 using com::sun::star::sdbc::XResultSet
;
83 using com::sun::star::sdbc::XConnection
;
84 using com::sun::star::sdbc::SQLException
;
86 using com::sun::star::sdbcx::XColumnsSupplier
;
87 using com::sun::star::sdbcx::XKeysSupplier
;
89 using com::sun::star::beans::Property
;
90 using com::sun::star::beans::XPropertySetInfo
;
91 using com::sun::star::beans::XPropertySet
;
93 using com::sun::star::container::XNameAccess
;
94 using com::sun::star::container::XEnumerationAccess
;
95 using com::sun::star::container::XEnumeration
;
96 using com::sun::star::container::XIndexAccess
;
98 namespace pq_sdbc_driver
100 static ::cppu::IPropertyArrayHelper
& getStatementPropertyArrayHelper()
102 static ::cppu::OPropertyArrayHelper
arrayHelper(
106 ::cppu::UnoType
<OUString
>::get() , 0 ),
108 "EscapeProcessing", 1,
109 cppu::UnoType
<bool>::get() , 0 ),
112 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
115 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
118 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
121 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
124 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
126 "ResultSetConcurrency", 7,
127 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
130 ::cppu::UnoType
<sal_Int32
>::get() , 0 )},
136 Statement::Statement( const ::rtl::Reference
< comphelper::RefCountedMutex
> & refMutex
,
137 const Reference
< XConnection
> & conn
,
138 struct ConnectionSettings
*pSettings
)
139 : Statement_BASE( refMutex
->GetMutex() )
140 , OPropertySetHelper( Statement_BASE::rBHelper
)
141 , m_connection( conn
)
142 , m_pSettings( pSettings
)
143 , m_xMutex( refMutex
)
144 , m_multipleResultAvailable(false)
145 , m_multipleResultUpdateCount(0)
146 , m_lastOidInserted(InvalidOid
)
148 m_props
[STATEMENT_QUERY_TIME_OUT
] <<= sal_Int32(0);
149 m_props
[STATEMENT_MAX_ROWS
] <<= sal_Int32(0);
150 m_props
[STATEMENT_RESULT_SET_CONCURRENCY
] <<=
151 css::sdbc::ResultSetConcurrency::READ_ONLY
;
152 m_props
[STATEMENT_RESULT_SET_TYPE
] <<=
153 css::sdbc::ResultSetType::SCROLL_INSENSITIVE
;
156 Statement::~Statement()
160 void Statement::checkClosed()
162 if( ! m_pSettings
|| ! m_pSettings
->pConnection
)
164 "pq_driver: Statement or connection has already been closed !",
165 *this, OUString(),1,Any());
168 Any
Statement::queryInterface( const Type
& rType
)
170 Any aRet
= Statement_BASE::queryInterface(rType
);
171 return aRet
.hasValue() ? aRet
: OPropertySetHelper::queryInterface(rType
);
175 Sequence
< Type
> Statement::getTypes()
177 static Sequence
< Type
> collection(
178 ::comphelper::concatSequences(
179 OPropertySetHelper::getTypes(),
180 Statement_BASE::getTypes()));
185 Sequence
< sal_Int8
> Statement::getImplementationId()
187 return css::uno::Sequence
<sal_Int8
>();
190 void Statement::close( )
192 // let the connection die without acquired mutex !
193 Reference
< XConnection
> r
;
194 Reference
< XCloseable
> resultSet
;
196 MutexGuard
guard( m_xMutex
->GetMutex() );
197 m_pSettings
= nullptr;
199 m_connection
.clear();
201 resultSet
= m_lastResultset
;
202 m_lastResultset
.clear();
211 void Statement::raiseSQLException(
212 const OUString
& sql
, const char * errorMsg
)
214 OUString error
= "pq_driver: "
215 + OUString( errorMsg
, strlen(errorMsg
), ConnectionSettings::encoding
)
216 + " (caused by statement '" + sql
+ "')";
217 SAL_WARN("connectivity.postgresql", error
);
218 throw SQLException( error
, *this, OUString(), 1, Any() );
221 Reference
< XResultSet
> Statement::executeQuery(const OUString
& sql
)
223 if( ! execute( sql
) )
225 raiseSQLException( sql
, "not a query" );
227 return Reference
< XResultSet
> ( m_lastResultset
, css::uno::UNO_QUERY
);
230 sal_Int32
Statement::executeUpdate( const OUString
& sql
)
234 raiseSQLException( sql
, "not a command" );
236 return m_multipleResultUpdateCount
;
239 /// @throws SQLException
240 static void raiseSQLException(
241 const Reference
< XInterface
> & owner
,
243 const char * errorMsg
,
244 const char *errorType
= nullptr )
246 OUStringBuffer
buf(128);
247 buf
.append( "pq_driver: ");
251 buf
.appendAscii( errorType
);
255 OUString( errorMsg
, strlen(errorMsg
) , ConnectionSettings::encoding
) );
256 buf
.append( " (caused by statement '" );
257 buf
.append( OStringToOUString( sql
, ConnectionSettings::encoding
) );
259 OUString error
= buf
.makeStringAndClear();
260 SAL_WARN("connectivity.postgresql", error
);
261 throw SQLException( error
, owner
, OUString(), 1, Any() );
265 // returns the elements of the primary key of the given table
266 // static Sequence< Reference< css::beans::XPropertySet > > lookupKeys(
267 static std::vector
< OUString
> lookupKeys(
268 const Reference
< css::container::XNameAccess
> &tables
,
269 const OUString
& table
,
273 std::vector
< OUString
> ret
;
274 Reference
< XKeysSupplier
> keySupplier
;
275 Statics
& st
= getStatics();
277 if( tables
->hasByName( table
) )
278 tables
->getByName( table
) >>= keySupplier
;
279 else if( -1 == table
.indexOf( '.' ) )
281 // it wasn't a fully qualified name. Now need to skip through all tables.
282 Reference
< XEnumerationAccess
> enumerationAccess( tables
, UNO_QUERY
);
284 Reference
< css::container::XEnumeration
> enumeration
=
285 enumerationAccess
->createEnumeration();
286 while( enumeration
->hasMoreElements() )
288 Reference
< XPropertySet
> set
;
289 enumeration
->nextElement() >>= set
;
293 if( set
->getPropertyValue( st
.NAME
) >>= name
)
295 // printf( "searching %s %s\n",
296 // OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
297 // OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
301 if( keySupplier
.is() )
303 // is ambiguous, as I don't know postgresql searchpath,
304 // I can't continue here, as I may write to a different table
306 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name
<< " is duplicated, add schema to resolve ambiguity");
309 keySupplier
.set( set
, UNO_QUERY
);
316 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table
<< " is unknown)");
319 if( keySupplier
.is() )
321 Reference
< XPropertySet
> set( keySupplier
, UNO_QUERY
);
322 set
->getPropertyValue( getStatics().NAME
) >>= *pTable
;
323 set
->getPropertyValue( getStatics().SCHEMA_NAME
) >>= *pSchema
;
326 Reference
< XEnumerationAccess
> keys ( keySupplier
->getKeys(), UNO_QUERY
);
327 Reference
< XEnumeration
> enumeration
= keys
->createEnumeration();
328 while( enumeration
->hasMoreElements() )
330 enumeration
->nextElement() >>= set
;
331 sal_Int32 keyType
= 0;
332 if( (set
->getPropertyValue( st
.TYPE
) >>= keyType
) &&
333 keyType
== css::sdbcx::KeyType::PRIMARY
)
335 Reference
< XColumnsSupplier
> columns( set
, UNO_QUERY
);
336 Reference
< XIndexAccess
> indexAccess( columns
->getColumns(), UNO_QUERY
);
338 int length
= indexAccess
->getCount();
339 ret
.resize( length
);
340 // printf( "primary key for Table %s is ",
341 // OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
342 for( int i
= 0 ; i
< length
; i
++ )
344 indexAccess
->getByIndex( i
) >>= set
;
346 set
->getPropertyValue( st
.NAME
) >>= name
;
348 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
355 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table
<< " does not have a primary key)");
361 bool executePostgresCommand( const OString
& cmd
, struct CommandData
*data
)
363 ConnectionSettings
*pSettings
= *(data
->ppSettings
);
365 sal_Int32 duration
= osl_getGlobalTimer();
366 PGresult
*result
= PQexec( pSettings
->pConnection
, cmd
.getStr() );
367 duration
= osl_getGlobalTimer() - duration
;
370 data
->owner
, cmd
, PQerrorMessage( pSettings
->pConnection
) );
372 ExecStatusType state
= PQresultStatus( result
);
373 *(data
->pLastOidInserted
) = 0;
374 data
->pLastTableInserted
->clear();
375 *(data
->pLastQuery
) = cmd
;
380 case PGRES_COMMAND_OK
:
382 *(data
->pMultipleResultUpdateCount
) = atoi( PQcmdTuples( result
) );
383 *(data
->pMultipleResultAvailable
) = false;
385 // in case an oid value is available, we retrieve it
386 *(data
->pLastOidInserted
) = PQoidValue( result
);
388 // in case it was a single insert, extract the name of the table,
389 // otherwise the table name is empty
390 *(data
->pLastTableInserted
) =
391 extractTableFromInsert( OStringToOUString( cmd
, ConnectionSettings::encoding
) );
393 OString strMain
= "executed command '" + cmd
+ "' successfully ('" + OString::number(*( data
->pMultipleResultUpdateCount
))
394 + "), duration=" + OString::number(duration
) + "ms";
397 if( *(data
->pLastOidInserted
) )
399 strOption
+= ", usedOid=" + OString::number( *(data
->pLastOidInserted
) ) + ", diagnosedTable="
400 + OUStringToOString(*data
->pLastTableInserted
, ConnectionSettings::encoding
);
402 SAL_INFO("connectivity.postgresql", strMain
+ strOption
);
406 case PGRES_TUPLES_OK
: // success
408 // In case it is a single table, it has a primary key and all columns
409 // belonging to the primary key are in the result set, allow updateable result sets
411 OUString table
, schema
;
412 std::vector
< OString
> vec
;
413 tokenizeSQL( cmd
, vec
);
414 OUString sourceTable
=
416 extractSingleTableFromSelect( vec
), ConnectionSettings::encoding
);
418 if( data
->concurrency
==
419 css::sdbc::ResultSetConcurrency::UPDATABLE
)
422 if( sourceTable
.getLength() )
424 std::vector
< OUString
> sourceTableKeys
= lookupKeys(
425 pSettings
->tables
.is() ?
426 pSettings
->tables
: data
->tableSupplier
->getTables() ,
431 // check, whether the columns are in the result set (required !)
433 for( i
= 0 ; i
< static_cast<int>(sourceTableKeys
.size()) ; i
++ )
437 OUStringToOString( sourceTableKeys
[i
] ,
438 ConnectionSettings::encoding
).getStr()) )
444 if( !sourceTableKeys
.empty() && i
== static_cast<int>(sourceTableKeys
.size()) )
446 *(data
->pLastResultset
) =
447 UpdateableResultSet::createFromPGResultSet(
448 data
->refMutex
, data
->owner
, data
->ppSettings
, result
,
449 schema
, table
,sourceTableKeys
);
451 else if( ! table
.getLength() )
453 aReason
= "can't support updateable resultset, because a single table in the "
454 "WHERE part of the statement could not be identified (" + cmd
+ ".";
456 else if( !sourceTableKeys
.empty() )
458 OStringBuffer
buf( 128 );
459 buf
.append( "can't support updateable resultset for table " );
460 buf
.append( OUStringToOString( schema
, ConnectionSettings::encoding
) );
462 buf
.append( OUStringToOString( table
, ConnectionSettings::encoding
) );
463 buf
.append( ", because resultset does not contain a part of the primary key ( column " );
464 buf
.append( OUStringToOString( sourceTableKeys
[i
], ConnectionSettings::encoding
) );
465 buf
.append( " is missing )" );
466 aReason
= buf
.makeStringAndClear();
471 aReason
= "can't support updateable resultset for table "
472 + OUStringToOString( schema
, ConnectionSettings::encoding
) + "."
473 + OUStringToOString( table
, ConnectionSettings::encoding
)
474 + ", because resultset table does not have a primary key ";
479 SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd
<< ")");
481 if( ! (*(data
->pLastResultset
)).is() )
483 SAL_WARN("connectivity.postgresql", aReason
);
485 // TODO: How to react here correctly ?
486 // remove this piece of code
487 *(data
->pLastResultset
) =
488 new FakedUpdateableResultSet(
489 data
->refMutex
, data
->owner
,
490 data
->ppSettings
,result
, schema
, table
,
491 OStringToOUString( aReason
, ConnectionSettings::encoding
) );
495 else if( sourceTable
.getLength() > 0)
497 splitConcatenatedIdentifier( sourceTable
, &schema
, &table
);
500 sal_Int32 returnedRows
= PQntuples( result
);
501 if( ! data
->pLastResultset
->is() )
502 *(data
->pLastResultset
) =
503 Reference
< XCloseable
> (
505 data
->refMutex
, data
->owner
,
506 data
->ppSettings
,result
, schema
, table
) );
507 *(data
->pMultipleResultAvailable
) = true;
509 SAL_INFO("connectivity.postgresql", "executed query '" << cmd
<< "' successfully, duration=" << duration
<< "ms, returnedRows=" << returnedRows
<< ".");
512 case PGRES_EMPTY_QUERY
:
515 case PGRES_BAD_RESPONSE
:
516 case PGRES_NONFATAL_ERROR
:
517 case PGRES_FATAL_ERROR
:
520 data
->owner
, cmd
, PQresultErrorMessage( result
) , PQresStatus( state
) );
526 static Sequence
< OUString
> getPrimaryKeyColumnNames(
527 const Reference
< XConnection
> & connection
, const OUString
&schemaName
, const OUString
&tableName
)
529 Sequence
< OUString
> ret
;
531 Int2StringMap mapIndex2Name
;
532 fillAttnum2attnameMap( mapIndex2Name
, connection
, schemaName
, tableName
);
534 // retrieve the primary key ...
535 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
536 "SELECT conkey " // 7
537 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
538 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
539 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
540 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
541 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" );
542 DisposeGuard
guard( stmt
);
543 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
544 paras
->setString( 1 , tableName
);
545 paras
->setString( 2 , schemaName
);
546 Reference
< XResultSet
> rs
= stmt
->executeQuery();
547 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
551 ret
= convertMappedIntArray2StringArray( mapIndex2Name
, string2intarray(xRow
->getString( 1 ) ) );
556 static void getAutoValues(
557 String2StringMap
& result
,
558 const Reference
< XConnection
> & connection
,
559 const OUString
&schemaName
,
560 const OUString
& tableName
,
561 ConnectionSettings
*pConnectionSettings
)
563 OUString strDefaultValue
= getColExprForDefaultSettingVal(pConnectionSettings
);
564 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
565 "SELECT pg_attribute.attname, " + strDefaultValue
+
566 "FROM pg_class, pg_namespace, pg_attribute "
567 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
568 "pg_attribute.attnum = pg_attrdef.adnum "
569 "WHERE pg_attribute.attrelid = pg_class.oid AND "
570 "pg_class.relnamespace = pg_namespace.oid AND "
571 "pg_namespace.nspname = ? AND "
572 // LEM TODO: this is weird; why "LIKE" and not "="?
573 // Most probably gives problems if tableName contains '%'
574 "pg_class.relname LIKE ? AND "
575 + strDefaultValue
+ " != ''"
577 DisposeGuard
guard( stmt
);
578 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
579 paras
->setString( 1 , schemaName
);
580 paras
->setString( 2 , tableName
);
581 Reference
< XResultSet
> rs
= stmt
->executeQuery();
582 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
586 result
[ OUStringToOString( xRow
->getString( 1 ), RTL_TEXTENCODING_ASCII_US
) ] =
587 OUStringToOString( xRow
->getString(2), RTL_TEXTENCODING_ASCII_US
);
591 Reference
< XResultSet
> getGeneratedValuesFromLastInsert(
592 ConnectionSettings
*pConnectionSettings
,
593 const Reference
< XConnection
> &connection
,
595 const OUString
& lastTableInserted
,
596 const OString
& lastQuery
)
598 Reference
< XResultSet
> ret
;
600 OUString schemaName
, tableName
;
601 splitConcatenatedIdentifier(
602 lastTableInserted
, &schemaName
, &tableName
);
604 if( nLastOid
&& lastTableInserted
.getLength() )
606 OUStringBuffer
buf( 128 );
607 buf
.append( "SELECT * FROM " );
608 if( schemaName
.getLength() )
609 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
611 bufferQuoteIdentifier( buf
, lastTableInserted
, pConnectionSettings
);
612 buf
.append( " WHERE oid = " );
613 buf
.append( nLastOid
);
614 query
= buf
.makeStringAndClear();
616 else if ( lastTableInserted
.getLength() && lastQuery
.getLength() )
618 // extract nameValue Pairs
619 String2StringMap namedValues
;
620 extractNameValuePairsFromInsert( namedValues
, lastQuery
);
623 // OStringBuffer buf( 128);
624 // buf.append( "extracting name/value from '" );
625 // buf.append( lastQuery.getStr() );
626 // buf.append( "' to [" );
627 // for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
629 // buf.append( ii->first.getStr() );
630 // buf.append( "=" );
631 // buf.append( ii->second.getStr() );
632 // buf.append( "," );
634 // buf.append( "]\n" );
635 // printf( "%s", buf.makeStringAndClear() );
637 // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
640 const Sequence
< OUString
> keyColumnNames
= getPrimaryKeyColumnNames( connection
, schemaName
, tableName
);
641 if( keyColumnNames
.hasElements() )
643 OUStringBuffer
buf( 128 );
644 buf
.append( "SELECT * FROM " );
645 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
646 buf
.append( " WHERE " );
647 bool bAdditionalCondition
= false;
648 String2StringMap autoValues
;
649 for( OUString
const & columnNameUnicode
: keyColumnNames
)
652 OString columnName
= OUStringToOString( columnNameUnicode
, ConnectionSettings::encoding
);
653 bool bColumnMatchNamedValue
= false;
654 for (auto const& namedValue
: namedValues
)
656 if( columnName
.equalsIgnoreAsciiCase( namedValue
.first
) )
658 value
= OStringToOUString( namedValue
.second
, ConnectionSettings::encoding
);
659 bColumnMatchNamedValue
= true;
664 // check, if a column of the primary key was not inserted explicitly,
665 if( !bColumnMatchNamedValue
)
667 if( autoValues
.empty() )
669 getAutoValues( autoValues
, connection
, schemaName
, tableName
, pConnectionSettings
);
671 // this could mean, that the column is a default or auto value, check this ...
672 bool bColumnMatchAutoValue
= false;
673 for (auto const& autoValue
: autoValues
)
675 if( columnName
.equalsIgnoreAsciiCase( autoValue
.first
) )
677 // it is indeed an auto value.
678 value
= OStringToOUString(autoValue
.second
, RTL_TEXTENCODING_ASCII_US
);
679 // check, whether it is a sequence
681 if( autoValue
.second
.startsWith("nextval(") )
683 // retrieve current sequence value:
684 OUStringBuffer
myBuf(128 );
685 myBuf
.append( "SELECT currval(" );
686 myBuf
.appendAscii( &(autoValue
.second
.getStr()[8]));
687 value
= querySingleValue( connection
, myBuf
.makeStringAndClear() );
689 bColumnMatchAutoValue
= true;
693 if( !bColumnMatchAutoValue
)
695 // it even was no autovalue, no sense to continue as we can't query the
702 if( bAdditionalCondition
)
703 buf
.append( " AND " );
704 bufferQuoteIdentifier( buf
, columnNameUnicode
, pConnectionSettings
);
707 bAdditionalCondition
= true;
709 query
= buf
.makeStringAndClear();
713 if( query
.getLength() )
715 Reference
< css::sdbc::XStatement
> stmt
= connection
->createStatement();
716 ret
= stmt
->executeQuery( query
);
723 sal_Bool
Statement::execute( const OUString
& sql
)
725 osl::MutexGuard
guard( m_xMutex
->GetMutex() );
727 OString cmd
= OUStringToOString( sql
, m_pSettings
);
729 Reference
< XCloseable
> lastResultSetHolder
= m_lastResultset
;
730 if( lastResultSetHolder
.is() )
731 lastResultSetHolder
->close();
733 m_lastResultset
.clear();
734 m_lastTableInserted
.clear();
736 struct CommandData data
;
737 data
.refMutex
= m_xMutex
;
738 data
.ppSettings
= &m_pSettings
;
739 data
.pLastOidInserted
= &m_lastOidInserted
;
740 data
.pLastQuery
= &m_lastQuery
;
741 data
.pMultipleResultUpdateCount
= &m_multipleResultUpdateCount
;
742 data
.pMultipleResultAvailable
= &m_multipleResultAvailable
;
743 data
.pLastTableInserted
= &m_lastTableInserted
;
744 data
.pLastResultset
= &m_lastResultset
;
746 data
.tableSupplier
.set( m_connection
, UNO_QUERY
);
748 extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY
);
749 return executePostgresCommand( cmd
, &data
);
752 Reference
< XConnection
> Statement::getConnection( )
754 Reference
< XConnection
> ret
;
756 MutexGuard
guard( m_xMutex
->GetMutex() );
764 Any
Statement::getWarnings( )
769 void Statement::clearWarnings( )
773 Reference
< css::sdbc::XResultSetMetaData
> Statement::getMetaData()
775 Reference
< css::sdbc::XResultSetMetaData
> ret
;
776 Reference
< css::sdbc::XResultSetMetaDataSupplier
> supplier( m_lastResultset
, UNO_QUERY
);
778 ret
= supplier
->getMetaData();
783 ::cppu::IPropertyArrayHelper
& Statement::getInfoHelper()
785 return getStatementPropertyArrayHelper();
789 sal_Bool
Statement::convertFastPropertyValue(
790 Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
792 rOldValue
= m_props
[nHandle
];
796 case STATEMENT_CURSOR_NAME
:
799 bRet
= ( rValue
>>= val
);
800 rConvertedValue
<<= val
;
803 case STATEMENT_ESCAPE_PROCESSING
:
806 bRet
= ( rValue
>>= val
);
807 rConvertedValue
<<= val
;
810 case STATEMENT_FETCH_DIRECTION
:
811 case STATEMENT_FETCH_SIZE
:
812 case STATEMENT_MAX_FIELD_SIZE
:
813 case STATEMENT_MAX_ROWS
:
814 case STATEMENT_QUERY_TIME_OUT
:
815 case STATEMENT_RESULT_SET_CONCURRENCY
:
816 case STATEMENT_RESULT_SET_TYPE
:
819 bRet
= ( rValue
>>= val
);
820 rConvertedValue
<<= val
;
825 throw IllegalArgumentException(
826 "pq_statement: Invalid property handle ("
827 + OUString::number( nHandle
) + ")",
835 void Statement::setFastPropertyValue_NoBroadcast(
836 sal_Int32 nHandle
,const Any
& rValue
)
838 m_props
[nHandle
] = rValue
;
841 void Statement::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
843 rValue
= m_props
[nHandle
];
846 Reference
< XPropertySetInfo
> Statement::getPropertySetInfo()
848 return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
852 Reference
< XResultSet
> Statement::getResultSet( )
854 return Reference
< XResultSet
> ( m_lastResultset
, css::uno::UNO_QUERY
);
857 sal_Int32
Statement::getUpdateCount( )
859 return m_multipleResultUpdateCount
;
862 sal_Bool
Statement::getMoreResults( )
864 // The PostgreSQL C interface always returns a single result,
865 // so we will never have multiple ones.
866 // Implicitly close the open resultset (if any) as per spec,
867 // and setup to signal "no more result, neither as resultset,
868 // nor as update count".
869 Reference
< XCloseable
> lastResultSetHolder
= m_lastResultset
;
870 if( lastResultSetHolder
.is() )
871 lastResultSetHolder
->close();
872 m_multipleResultUpdateCount
= -1;
877 void Statement::disposing()
882 Reference
< XResultSet
> Statement::getGeneratedValues( )
884 osl::MutexGuard
guard( m_xMutex
->GetMutex() );
885 return getGeneratedValuesFromLastInsert(
886 m_pSettings
, m_connection
, m_lastOidInserted
, m_lastTableInserted
, m_lastQuery
);
891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */