nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_statement.cxx
blobdd7ab576b37fdaf595bc0ab5292c90f422c99c4d
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>
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>
63 #include <string.h>
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(
103 Sequence<Property>{
104 Property(
105 "CursorName", 0,
106 ::cppu::UnoType<OUString>::get() , 0 ),
107 Property(
108 "EscapeProcessing", 1,
109 cppu::UnoType<bool>::get() , 0 ),
110 Property(
111 "FetchDirection", 2,
112 ::cppu::UnoType<sal_Int32>::get() , 0 ),
113 Property(
114 "FetchSize", 3,
115 ::cppu::UnoType<sal_Int32>::get() , 0 ),
116 Property(
117 "MaxFieldSize", 4,
118 ::cppu::UnoType<sal_Int32>::get() , 0 ),
119 Property(
120 "MaxRows", 5,
121 ::cppu::UnoType<sal_Int32>::get() , 0 ),
122 Property(
123 "QueryTimeOut", 6,
124 ::cppu::UnoType<sal_Int32>::get() , 0 ),
125 Property(
126 "ResultSetConcurrency", 7,
127 ::cppu::UnoType<sal_Int32>::get() , 0 ),
128 Property(
129 "ResultSetType", 8,
130 ::cppu::UnoType<sal_Int32>::get() , 0 )},
131 true );
133 return arrayHelper;
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 )
163 throw SQLException(
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()));
182 return collection;
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;
198 r = m_connection;
199 m_connection.clear();
201 resultSet = m_lastResultset;
202 m_lastResultset.clear();
204 if( resultSet.is() )
206 resultSet->close();
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 )
232 if( execute( sql ) )
234 raiseSQLException( sql, "not a command" );
236 return m_multipleResultUpdateCount;
239 /// @throws SQLException
240 static void raiseSQLException(
241 const Reference< XInterface> & owner,
242 const OString & sql,
243 const char * errorMsg,
244 const char *errorType = nullptr )
246 OUStringBuffer buf(128);
247 buf.append( "pq_driver: ");
248 if( errorType )
250 buf.append( "[" );
251 buf.appendAscii( errorType );
252 buf.append( "]" );
254 buf.append(
255 OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) );
256 buf.append( " (caused by statement '" );
257 buf.append( OStringToOUString( sql, ConnectionSettings::encoding ) );
258 buf.append( "')" );
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,
270 OUString *pSchema,
271 OUString *pTable)
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;
290 OUString name;
291 // OUString schema;
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() );
298 if( name == table )
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
305 keySupplier.clear();
306 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity");
307 break;
309 keySupplier.set( set, UNO_QUERY );
314 else
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;
324 set.clear();
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;
345 OUString name;
346 set->getPropertyValue( st.NAME ) >>= name;
347 ret[i] = name;
348 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
350 // printf( "\n" );
353 if( ret.empty() )
355 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)");
358 return ret;
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;
368 if( ! result )
369 raiseSQLException(
370 data->owner, cmd, PQerrorMessage( pSettings->pConnection ) );
372 ExecStatusType state = PQresultStatus( result );
373 *(data->pLastOidInserted) = 0;
374 data->pLastTableInserted->clear();
375 *(data->pLastQuery) = cmd;
377 bool ret = false;
378 switch( state )
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";
396 OString strOption;
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);
403 PQclear( result );
404 break;
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
410 // otherwise, don't
411 OUString table, schema;
412 std::vector< OString > vec;
413 tokenizeSQL( cmd, vec );
414 OUString sourceTable =
415 OStringToOUString(
416 extractSingleTableFromSelect( vec ), ConnectionSettings::encoding );
418 if( data->concurrency ==
419 css::sdbc::ResultSetConcurrency::UPDATABLE )
421 OString aReason;
422 if( sourceTable.getLength() )
424 std::vector< OUString > sourceTableKeys = lookupKeys(
425 pSettings->tables.is() ?
426 pSettings->tables : data->tableSupplier->getTables() ,
427 sourceTable,
428 &schema,
429 &table);
431 // check, whether the columns are in the result set (required !)
432 int i;
433 for( i = 0 ; i < static_cast<int>(sourceTableKeys.size()) ; i ++ )
435 if( -1 == PQfnumber(
436 result,
437 OUStringToOString( sourceTableKeys[i] ,
438 ConnectionSettings::encoding ).getStr()) )
440 break;
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 ) );
461 buf.append( "." );
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();
468 else
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 ";
477 else
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 > (
504 new ResultSet(
505 data->refMutex, data->owner,
506 data->ppSettings,result, schema, table ) );
507 *(data->pMultipleResultAvailable) = true;
508 ret = true;
509 SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << ".");
510 break;
512 case PGRES_EMPTY_QUERY:
513 case PGRES_COPY_OUT:
514 case PGRES_COPY_IN:
515 case PGRES_BAD_RESPONSE:
516 case PGRES_NONFATAL_ERROR:
517 case PGRES_FATAL_ERROR:
518 default:
519 raiseSQLException(
520 data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) );
522 return ret;
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 );
549 if( rs->next() )
551 ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) );
553 return ret;
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 );
584 while( rs->next() )
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,
594 sal_Int32 nLastOid,
595 const OUString & lastTableInserted,
596 const OString & lastQuery )
598 Reference< XResultSet > ret;
599 OUString query;
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 );
610 else
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 );
622 // debug ...
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 )
628 // {
629 // buf.append( ii->first.getStr() );
630 // buf.append( "=" );
631 // buf.append( ii->second.getStr() );
632 // buf.append( "," );
633 // }
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
638 // in postgresql doc
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 )
651 OUString value;
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;
660 break;
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;
690 break;
693 if( !bColumnMatchAutoValue )
695 // it even was no autovalue, no sense to continue as we can't query the
696 // inserted row
697 buf.truncate();
698 break;
702 if( bAdditionalCondition )
703 buf.append( " AND " );
704 bufferQuoteIdentifier( buf, columnNameUnicode, pConnectionSettings );
705 buf.append( " = " );
706 buf.append( value );
707 bAdditionalCondition = true;
709 query = buf.makeStringAndClear();
713 if( query.getLength() )
715 Reference< css::sdbc::XStatement > stmt = connection->createStatement();
716 ret = stmt->executeQuery( query );
719 return ret;
723 sal_Bool Statement::execute( const OUString& sql )
725 osl::MutexGuard guard( m_xMutex->GetMutex() );
726 checkClosed();
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;
745 data.owner = *this;
746 data.tableSupplier.set( m_connection, UNO_QUERY );
747 data.concurrency =
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() );
757 checkClosed();
758 ret = m_connection;
760 return ret;
764 Any Statement::getWarnings( )
766 return Any();
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 );
777 if( supplier.is() )
778 ret = supplier->getMetaData();
779 return ret;
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];
793 bool bRet;
794 switch( nHandle )
796 case STATEMENT_CURSOR_NAME:
798 OUString val;
799 bRet = ( rValue >>= val );
800 rConvertedValue <<= val;
801 break;
803 case STATEMENT_ESCAPE_PROCESSING:
805 bool val(false);
806 bRet = ( rValue >>= val );
807 rConvertedValue <<= val;
808 break;
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:
818 sal_Int32 val;
819 bRet = ( rValue >>= val );
820 rConvertedValue <<= val;
821 break;
823 default:
825 throw IllegalArgumentException(
826 "pq_statement: Invalid property handle ("
827 + OUString::number( nHandle ) + ")",
828 *this, 2 );
831 return bRet;
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;
873 return false;
877 void Statement::disposing()
879 close();
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: */