Use correct object
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_statement.cxx
blob5867d5cdbf333668746ee3d3e255c31fb8e9c8d9
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 <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"
44 #include <osl/time.h>
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>
62 #include <cstddef>
63 #include <string.h>
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(
104 Sequence<Property>{
105 Property(
106 u"CursorName"_ustr, 0,
107 ::cppu::UnoType<OUString>::get() , 0 ),
108 Property(
109 u"EscapeProcessing"_ustr, 1,
110 cppu::UnoType<bool>::get() , 0 ),
111 Property(
112 u"FetchDirection"_ustr, 2,
113 ::cppu::UnoType<sal_Int32>::get() , 0 ),
114 Property(
115 u"FetchSize"_ustr, 3,
116 ::cppu::UnoType<sal_Int32>::get() , 0 ),
117 Property(
118 u"MaxFieldSize"_ustr, 4,
119 ::cppu::UnoType<sal_Int32>::get() , 0 ),
120 Property(
121 u"MaxRows"_ustr, 5,
122 ::cppu::UnoType<sal_Int32>::get() , 0 ),
123 Property(
124 u"QueryTimeOut"_ustr, 6,
125 ::cppu::UnoType<sal_Int32>::get() , 0 ),
126 Property(
127 u"ResultSetConcurrency"_ustr, 7,
128 ::cppu::UnoType<sal_Int32>::get() , 0 ),
129 Property(
130 u"ResultSetType"_ustr, 8,
131 ::cppu::UnoType<sal_Int32>::get() , 0 )},
132 true );
134 return arrayHelper;
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 )
164 throw SQLException(
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()));
183 return collection;
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;
199 r = m_connection;
200 m_connection.clear();
202 resultSet = m_lastResultset;
203 m_lastResultset.clear();
205 if( resultSet.is() )
207 resultSet->close();
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 )
233 if( execute( 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: ");
249 if( errorType )
251 buf.append( "[" );
252 buf.appendAscii( errorType );
253 buf.append( "]" );
255 buf.append(
256 OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding )
257 + " (caused by statement '"
258 + OStringToOUString( sql, ConnectionSettings::encoding )
259 + "')" );
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,
271 OUString *pSchema,
272 OUString *pTable)
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;
291 OUString name;
292 // OUString schema;
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() );
299 if( name == table )
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
306 keySupplier.clear();
307 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity");
308 break;
310 keySupplier.set( set, UNO_QUERY );
315 else
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;
325 set.clear();
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;
346 OUString name;
347 set->getPropertyValue( st.NAME ) >>= name;
348 ret[i] = name;
349 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
351 // printf( "\n" );
354 if( ret.empty() )
356 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)");
359 return ret;
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;
369 if( ! result )
370 raiseSQLException(
371 data->owner, cmd, PQerrorMessage( pSettings->pConnection ) );
373 ExecStatusType state = PQresultStatus( result );
374 *(data->pLastOidInserted) = 0;
375 data->pLastTableInserted->clear();
376 *(data->pLastQuery) = cmd;
378 bool ret = false;
379 switch( state )
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";
397 OString strOption;
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);
404 PQclear( result );
405 break;
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
411 // otherwise, don't
412 OUString table, schema;
413 std::vector< OString > vec;
414 tokenizeSQL( cmd, vec );
415 OUString sourceTable =
416 OStringToOUString(
417 extractSingleTableFromSelect( vec ), ConnectionSettings::encoding );
419 if( data->concurrency ==
420 css::sdbc::ResultSetConcurrency::UPDATABLE )
422 OString aReason;
423 if( sourceTable.getLength() )
425 std::vector< OUString > sourceTableKeys = lookupKeys(
426 pSettings->tables.is() ?
427 pSettings->tables : data->tableSupplier->getTables() ,
428 sourceTable,
429 &schema,
430 &table);
432 // check, whether the columns are in the result set (required !)
433 std::size_t i;
434 for( i = 0 ; i < sourceTableKeys.size() ; i ++ )
436 if( -1 == PQfnumber(
437 result,
438 OUStringToOString( sourceTableKeys[i] ,
439 ConnectionSettings::encoding ).getStr()) )
441 break;
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 )
464 + " is missing )";
466 else
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 ";
475 else
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 > (
502 new ResultSet(
503 data->refMutex, data->owner,
504 data->ppSettings,result, schema, table ) );
505 *(data->pMultipleResultAvailable) = true;
506 ret = true;
507 SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << ".");
508 break;
510 case PGRES_EMPTY_QUERY:
511 case PGRES_COPY_OUT:
512 case PGRES_COPY_IN:
513 case PGRES_BAD_RESPONSE:
514 case PGRES_NONFATAL_ERROR:
515 case PGRES_FATAL_ERROR:
516 default:
517 raiseSQLException(
518 data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) );
520 return ret;
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 );
547 if( rs->next() )
549 ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) );
551 return ret;
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 );
582 while( rs->next() )
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,
592 sal_Int32 nLastOid,
593 std::u16string_view lastTableInserted,
594 const OString & lastQuery )
596 Reference< XResultSet > ret;
597 OUString query;
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 );
608 else
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 );
619 // debug ...
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 )
625 // {
626 // buf.append( ii->first.getStr() );
627 // buf.append( "=" );
628 // buf.append( ii->second.getStr() );
629 // buf.append( "," );
630 // }
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
635 // in postgresql doc
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 )
648 OUString value;
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;
657 break;
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;
687 break;
690 if( !bColumnMatchAutoValue )
692 // it even was no autovalue, no sense to continue as we can't query the
693 // inserted row
694 buf.truncate();
695 break;
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 );
715 return ret;
719 sal_Bool Statement::execute( const OUString& sql )
721 osl::MutexGuard guard( m_xMutex->GetMutex() );
722 checkClosed();
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;
741 data.owner = *this;
742 data.tableSupplier.set( m_connection, UNO_QUERY );
743 data.concurrency =
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() );
753 checkClosed();
754 ret = m_connection;
756 return ret;
760 Any Statement::getWarnings( )
762 return Any();
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 );
773 if( supplier.is() )
774 ret = supplier->getMetaData();
775 return ret;
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];
789 bool bRet;
790 switch( nHandle )
792 case STATEMENT_CURSOR_NAME:
794 OUString val;
795 bRet = ( rValue >>= val );
796 rConvertedValue <<= val;
797 break;
799 case STATEMENT_ESCAPE_PROCESSING:
801 bool val(false);
802 bRet = ( rValue >>= val );
803 rConvertedValue <<= val;
804 break;
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:
814 sal_Int32 val;
815 bRet = ( rValue >>= val );
816 rConvertedValue <<= val;
817 break;
819 default:
821 throw IllegalArgumentException(
822 "pq_statement: Invalid property handle ("
823 + OUString::number( nHandle ) + ")",
824 *this, 2 );
827 return bRet;
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;
869 return false;
873 void Statement::disposing()
875 close();
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: */