merge the formfield patch from ooo-build
[ooovba.git] / connectivity / source / drivers / postgresql / pq_statement.cxx
blobf578ac7179e5838f76ebb5a71deab5f31248e58d
1 /*************************************************************************
3 * $RCSfile: pq_statement.cxx,v $
5 * $Revision: 1.1.2.7 $
7 * last change: $Author: jbu $ $Date: 2007/08/26 20:40:40 $
9 * The Contents of this file are made available subject to the terms of
10 * either of the following licenses
12 * - GNU Lesser General Public License Version 2.1
13 * - Sun Industry Standards Source License Version 1.1
15 * Sun Microsystems Inc., October, 2000
17 * GNU Lesser General Public License Version 2.1
18 * =============================================
19 * Copyright 2000 by Sun Microsystems, Inc.
20 * 901 San Antonio Road, Palo Alto, CA 94303, USA
22 * This library is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License version 2.1, as published by the Free Software Foundation.
26 * This library is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * Lesser General Public License for more details.
31 * You should have received a copy of the GNU Lesser General Public
32 * License along with this library; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 * MA 02111-1307 USA
37 * Sun Industry Standards Source License Version 1.1
38 * =================================================
39 * The contents of this file are subject to the Sun Industry Standards
40 * Source License Version 1.1 (the "License"); You may not use this file
41 * except in compliance with the License. You may obtain a copy of the
42 * License at http://www.openoffice.org/license.html.
44 * Software provided under this License is provided on an "AS IS" basis,
45 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
46 * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
47 * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
48 * See the License for the specific provisions governing your rights and
49 * obligations concerning the Software.
51 * The Initial Developer of the Original Code is: Joerg Budischewski
53 * Copyright: 2000 by Sun Microsystems, Inc.
55 * All Rights Reserved.
57 * Contributor(s): Joerg Budischewski
60 ************************************************************************/
61 #include "pq_statement.hxx"
62 #include "pq_fakedupdateableresultset.hxx"
63 #include "pq_updateableresultset.hxx"
64 #include "pq_tools.hxx"
65 #include "pq_statics.hxx"
67 #include <osl/thread.h>
68 #include <osl/time.h>
70 #include <rtl/ustrbuf.hxx>
71 #include <rtl/strbuf.hxx>
73 #include <cppuhelper/typeprovider.hxx>
74 #include <cppuhelper/queryinterface.hxx>
76 #include <com/sun/star/beans/PropertyAttribute.hpp>
78 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
79 #include <com/sun/star/sdbc/ResultSetType.hpp>
80 #include <com/sun/star/sdbc/XParameters.hpp>
82 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
83 #include <com/sun/star/sdbcx/KeyType.hpp>
84 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
86 #include <com/sun/star/container/XIndexAccess.hpp>
87 #include <com/sun/star/container/XEnumerationAccess.hpp>
89 #include <string.h>
91 using osl::Mutex;
92 using osl::MutexGuard;
94 using rtl::OUString;
95 using rtl::OUStringBuffer;
96 using rtl::OUStringToOString;
97 using rtl::OStringToOUString;
98 using rtl::OString;
100 using com::sun::star::uno::Any;
101 using com::sun::star::uno::makeAny;
102 using com::sun::star::uno::Type;
103 using com::sun::star::uno::RuntimeException;
104 using com::sun::star::uno::Exception;
105 using com::sun::star::uno::Sequence;
106 using com::sun::star::uno::Reference;
107 using com::sun::star::uno::XInterface;
108 using com::sun::star::uno::UNO_QUERY;
110 using com::sun::star::lang::IllegalArgumentException;
112 using com::sun::star::sdbc::XWarningsSupplier;
113 using com::sun::star::sdbc::XCloseable;
114 using com::sun::star::sdbc::XStatement;
115 using com::sun::star::sdbc::XPreparedStatement;
116 using com::sun::star::sdbc::XParameters;
117 using com::sun::star::sdbc::XRow;
118 using com::sun::star::sdbc::XResultSet;
119 using com::sun::star::sdbc::XGeneratedResultSet;
120 using com::sun::star::sdbc::XConnection;
121 using com::sun::star::sdbc::SQLException;
123 using com::sun::star::sdbcx::XColumnsSupplier;
124 using com::sun::star::sdbcx::XTablesSupplier;
125 using com::sun::star::sdbcx::XKeysSupplier;
127 using com::sun::star::beans::Property;
128 using com::sun::star::beans::XPropertySetInfo;
129 using com::sun::star::beans::XPropertySet;
130 using com::sun::star::beans::XFastPropertySet;
131 using com::sun::star::beans::XMultiPropertySet;
133 using com::sun::star::container::XNameAccess;
134 using com::sun::star::container::XEnumerationAccess;
135 using com::sun::star::container::XEnumeration;
136 using com::sun::star::container::XIndexAccess;
138 #define ASCII_STR(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
139 namespace pq_sdbc_driver
141 static ::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper()
143 static ::cppu::IPropertyArrayHelper *pArrayHelper;
144 if( ! pArrayHelper )
146 MutexGuard guard( Mutex::getGlobalMutex() );
147 if( ! pArrayHelper )
149 static Property aTable[] =
151 Property(
152 OUString( RTL_CONSTASCII_USTRINGPARAM("CursorName") ), 0,
153 ::getCppuType( (OUString *)0) , 0 ),
154 Property(
155 OUString( RTL_CONSTASCII_USTRINGPARAM("EscapeProcessing") ), 1,
156 ::getBooleanCppuType() , 0 ),
157 Property(
158 OUString( RTL_CONSTASCII_USTRINGPARAM("FetchDirection") ), 2,
159 ::getCppuType( (sal_Int32 *)0) , 0 ),
160 Property(
161 OUString( RTL_CONSTASCII_USTRINGPARAM("FetchSize") ), 3,
162 ::getCppuType( (sal_Int32 *)0) , 0 ),
163 Property(
164 OUString( RTL_CONSTASCII_USTRINGPARAM("MaxFieldSize") ), 4,
165 ::getCppuType( (sal_Int32 *)0) , 0 ),
166 Property(
167 OUString( RTL_CONSTASCII_USTRINGPARAM("MaxRows") ), 5,
168 ::getCppuType( (sal_Int32 *)0) , 0 ),
169 Property(
170 OUString( RTL_CONSTASCII_USTRINGPARAM("QueryTimeOut") ), 6,
171 ::getCppuType( (sal_Int32 *)0) , 0 ),
172 Property(
173 OUString( RTL_CONSTASCII_USTRINGPARAM("ResultSetConcurrency") ), 7,
174 ::getCppuType( (sal_Int32 *)0) , 0 ),
175 Property(
176 OUString( RTL_CONSTASCII_USTRINGPARAM("ResultSetType") ), 8,
177 ::getCppuType( (sal_Int32 *)0) , 0 )
179 OSL_ASSERT( sizeof(aTable)/ sizeof(Property) == STATEMENT_SIZE );
180 static ::cppu::OPropertyArrayHelper arrayHelper( aTable, STATEMENT_SIZE, sal_True );
181 pArrayHelper = &arrayHelper;
184 return *pArrayHelper;
187 Statement::Statement( const ::rtl::Reference< RefCountedMutex > & refMutex,
188 const Reference< XConnection > & conn,
189 struct ConnectionSettings *pSettings )
190 : OComponentHelper( refMutex->mutex ),
191 OPropertySetHelper( OComponentHelper::rBHelper ),
192 m_refMutex( refMutex ),
193 m_connection( conn ),
194 m_pSettings( pSettings ),
195 m_lastOidInserted( InvalidOid )
197 m_props[STATEMENT_QUERY_TIME_OUT] = makeAny( (sal_Int32)0 );
198 m_props[STATEMENT_MAX_ROWS] = makeAny( (sal_Int32)0 );
199 m_props[STATEMENT_RESULT_SET_CONCURRENCY] = makeAny(
200 com::sun::star::sdbc::ResultSetConcurrency::READ_ONLY );
201 m_props[STATEMENT_RESULT_SET_TYPE] = makeAny(
202 com::sun::star::sdbc::ResultSetType::SCROLL_INSENSITIVE );
205 Statement::~Statement()
207 POSTGRE_TRACE( "dtor Statement" );
210 void Statement::checkClosed() throw (SQLException, RuntimeException )
212 if( ! m_pSettings || ! m_pSettings->pConnection )
213 throw SQLException(
214 ASCII_STR("pq_driver: Statement or connection has already been closed !" ),
215 *this, OUString(),1,Any());
218 Any Statement::queryInterface( const Type & reqType ) throw (RuntimeException)
220 Any ret;
222 ret = OComponentHelper::queryInterface( reqType );
223 if( ! ret.hasValue() )
224 ret = ::cppu::queryInterface( reqType,
225 static_cast< XWarningsSupplier * > ( this ),
226 static_cast< XStatement * > ( this ),
227 static_cast< com::sun::star::sdbc::XResultSetMetaDataSupplier * > ( this ),
228 static_cast< XCloseable * > ( this ),
229 static_cast< XPropertySet * > ( this ),
230 static_cast< XMultiPropertySet * > ( this ),
231 static_cast< XGeneratedResultSet * > ( this ),
232 static_cast< XFastPropertySet * > ( this ) );
233 return ret;
237 Sequence< Type > Statement::getTypes() throw ( RuntimeException )
239 static cppu::OTypeCollection *pCollection;
240 if( ! pCollection )
242 MutexGuard guard( osl::Mutex::getGlobalMutex() );
243 if( !pCollection )
245 static cppu::OTypeCollection collection(
246 getCppuType( (Reference< XWarningsSupplier> *) 0 ),
247 getCppuType( (Reference< XStatement> *) 0 ),
248 getCppuType( (Reference< com::sun::star::sdbc::XResultSetMetaDataSupplier> *) 0 ),
249 getCppuType( (Reference< XCloseable> *) 0 ),
250 getCppuType( (Reference< XPropertySet >*) 0 ),
251 getCppuType( (Reference< XFastPropertySet > *) 0 ),
252 getCppuType( (Reference< XMultiPropertySet > *) 0 ),
253 getCppuType( (Reference< XGeneratedResultSet > *) 0 ),
254 OComponentHelper::getTypes());
255 pCollection = &collection;
258 return pCollection->getTypes();
261 Sequence< sal_Int8> Statement::getImplementationId() throw ( RuntimeException )
263 static cppu::OImplementationId *pId;
264 if( ! pId )
266 MutexGuard guard( osl::Mutex::getGlobalMutex() );
267 if( ! pId )
269 static cppu::OImplementationId id(sal_False);
270 pId = &id;
273 return pId->getImplementationId();
276 void Statement::close( ) throw (SQLException, RuntimeException)
278 // let the connection die without acquired mutex !
279 Reference< XConnection > r;
280 Reference< XCloseable > resultSet;
282 MutexGuard guard( m_refMutex->mutex );
283 m_pSettings = 0;
284 r = m_connection;
285 m_connection.clear();
287 resultSet = m_lastResultset;
288 m_lastResultset.clear();
290 if( resultSet.is() )
292 resultSet->close();
293 POSTGRE_TRACE( "statement closed" );
298 void Statement::raiseSQLException(
299 const OUString & sql, const char * errorMsg, const char *errorType )
300 throw( SQLException )
302 OUStringBuffer buf(128);
303 buf.appendAscii( "pq_driver: ");
304 if( errorType )
306 buf.appendAscii( "[" );
307 buf.appendAscii( errorType );
308 buf.appendAscii( "]" );
310 buf.append(
311 rtl::OUString( errorMsg, strlen(errorMsg) , m_pSettings->encoding ) );
312 buf.appendAscii( " (caused by statement '" );
313 buf.append( sql );
314 buf.appendAscii( "')" );
315 OUString error = buf.makeStringAndClear();
316 log( m_pSettings, LogLevel::ERROR, error );
317 throw SQLException( error, *this, OUString(), 1, Any() );
320 Reference< XResultSet > Statement::executeQuery(const OUString& sql )
321 throw (SQLException, RuntimeException)
323 Reference< XCloseable > lastResultSetHolder = m_lastResultset;
324 if( lastResultSetHolder.is() )
325 lastResultSetHolder->close();
327 if( ! execute( sql ) )
329 raiseSQLException( sql, "not a query" );
331 return Reference< XResultSet > ( m_lastResultset, com::sun::star::uno::UNO_QUERY );
334 sal_Int32 Statement::executeUpdate( const OUString& sql )
335 throw (SQLException, RuntimeException)
337 if( execute( sql ) )
339 raiseSQLException( sql, "not a command" );
341 return m_multipleResultUpdateCount;
345 static void raiseSQLException(
346 ConnectionSettings *pSettings,
347 const Reference< XInterface> & owner,
348 const OString & sql,
349 const char * errorMsg,
350 const char *errorType = 0 )
351 throw( SQLException )
353 OUStringBuffer buf(128);
354 buf.appendAscii( "pq_driver: ");
355 if( errorType )
357 buf.appendAscii( "[" );
358 buf.appendAscii( errorType );
359 buf.appendAscii( "]" );
361 buf.append(
362 rtl::OUString( errorMsg, strlen(errorMsg) , pSettings->encoding ) );
363 buf.appendAscii( " (caused by statement '" );
364 buf.append( rtl::OStringToOUString( sql, pSettings->encoding ) );
365 buf.appendAscii( "')" );
366 OUString error = buf.makeStringAndClear();
367 log( pSettings, LogLevel::ERROR, error );
368 throw SQLException( error, owner, OUString(), 1, Any() );
372 // returns the elements of the primary key of the given table
373 // static Sequence< Reference< com::sun::star::beans::XPropertySet > > lookupKeys(
374 static Sequence< ::rtl::OUString > lookupKeys(
375 const Reference< com::sun::star::container::XNameAccess > &tables,
376 const OUString & table,
377 OUString *pSchema,
378 OUString *pTable,
379 ConnectionSettings *pSettings)
381 Sequence< ::rtl::OUString > ret;
382 Reference< XKeysSupplier > keySupplier;
383 Statics & st = getStatics();
385 if( tables->hasByName( table ) )
386 tables->getByName( table ) >>= keySupplier;
387 else if( -1 == table.indexOf( '.' ) )
389 // it wasn't a fully qualified name. Now need to skip through all tables.
390 Reference< XEnumerationAccess > enumerationAccess =
391 Reference< XEnumerationAccess > ( tables, UNO_QUERY );
393 Reference< com::sun::star::container::XEnumeration > enumeration =
394 enumerationAccess->createEnumeration();
395 while( enumeration->hasMoreElements() )
397 Reference< XPropertySet > set;
398 enumeration->nextElement() >>= set;
399 OUString name;
400 // ::rtl::OUString schema;
402 if( set->getPropertyValue( st.NAME ) >>= name )
404 // printf( "searching %s %s\n",
405 // OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
406 // OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
407 if( name == table )
410 if( keySupplier.is() )
412 // is ambigous, as I don't know postgresql searchpath,
413 // I can't continue here, as I may write to a different table
414 keySupplier.clear();
415 if( isLog( pSettings, LogLevel::INFO ) )
417 rtl::OStringBuffer buf( 128 );
418 buf.append( "Can't offer updateable result set because table " );
419 buf.append( OUStringToOString(name, pSettings->encoding) );
420 buf.append( " is duplicated, add schema to resolve ambiguity" );
421 log( pSettings, LogLevel::INFO, buf.makeStringAndClear().getStr() );
423 break;
425 keySupplier = Reference< XKeysSupplier > ( set, UNO_QUERY );
430 else
432 if( isLog( pSettings, LogLevel::INFO ) )
434 rtl::OStringBuffer buf( 128 );
435 buf.append( "Can't offer updateable result set ( table " );
436 buf.append( OUStringToOString(table, pSettings->encoding) );
437 buf.append( " is unknown)" );
438 log( pSettings, LogLevel::INFO, buf.makeStringAndClear().getStr() );
442 if( keySupplier.is() )
444 Reference< XPropertySet > set( keySupplier, UNO_QUERY );
445 set->getPropertyValue( getStatics().NAME ) >>= (*pTable);
446 set->getPropertyValue( getStatics().SCHEMA_NAME ) >>= (*pSchema );
447 set.clear();
449 Reference< XEnumerationAccess > keys ( keySupplier->getKeys(), UNO_QUERY );
450 Reference< XEnumeration > enumeration = keys->createEnumeration();
451 while( enumeration->hasMoreElements() )
453 enumeration->nextElement() >>= set;
454 sal_Int32 keyType;
455 if( (set->getPropertyValue( st.TYPE ) >>= keyType ) &&
456 keyType == com::sun::star::sdbcx::KeyType::PRIMARY )
458 Reference< XColumnsSupplier > columns( set, UNO_QUERY );
459 Reference< XIndexAccess > indexAccess =
460 Reference< XIndexAccess > ( columns->getColumns(), UNO_QUERY );
462 int length = indexAccess->getCount();
463 ret.realloc( length );
464 // printf( "primary key for Table %s is ",
465 // OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
466 for( int i = 0 ; i < length ; i ++ )
468 indexAccess->getByIndex( i ) >>= set;
469 OUString name;
470 set->getPropertyValue( st.NAME ) >>= name;
471 ret[i] = name;
472 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
474 // printf( "\n" );
477 if( ! ret.getLength() )
479 if( isLog( pSettings, LogLevel::INFO ) )
481 rtl::OStringBuffer buf( 128 );
482 buf.append( "Can't offer updateable result set ( table " );
483 buf.append( OUStringToOString(table, pSettings->encoding) );
484 buf.append( " does not have a primary key)" );
485 log( pSettings, LogLevel::INFO, buf.makeStringAndClear().getStr() );
489 return ret;
492 bool executePostgresCommand( const rtl::OString & cmd, struct CommandData *data )
494 ConnectionSettings *pSettings = *(data->ppSettings);
496 sal_Int32 duration = osl_getGlobalTimer();
497 PGresult *result = PQexec( pSettings->pConnection, cmd.getStr() );
498 duration = osl_getGlobalTimer() - duration;
499 if( ! result )
500 raiseSQLException(
501 pSettings, data->owner, cmd, PQerrorMessage( pSettings->pConnection ) );
503 ExecStatusType state = PQresultStatus( result );
504 *(data->pLastOidInserted) = 0;
505 *(data->pLastTableInserted) = rtl::OUString();
506 *(data->pLastQuery) = cmd;
508 sal_Bool ret = sal_False;
509 switch( state )
511 case PGRES_COMMAND_OK:
513 *(data->pMultipleResultUpdateCount) = atoi( PQcmdTuples( result ) );
514 *(data->pMultipleResultAvailable) = sal_False;
516 // in case an oid value is available, we retrieve it
517 *(data->pLastOidInserted) = PQoidValue( result );
519 // in case it was a single insert, extract the name of the table,
520 // otherwise the table name is empty
521 *(data->pLastTableInserted) =
522 extractTableFromInsert( OStringToOUString( cmd, pSettings->encoding ) );
523 if( isLog( pSettings, LogLevel::SQL ) )
525 rtl::OStringBuffer buf( 128 );
526 buf.append( "executed command '" );
527 buf.append( cmd.getStr() );
528 buf.append( "' sucessfully (" );
529 buf.append( *( data->pMultipleResultUpdateCount ) );
530 buf.append( ")" );
531 buf.append( ", duration=" );
532 buf.append( duration );
533 buf.append( "ms" );
534 if( *(data->pLastOidInserted) )
536 buf.append( ", usedOid=" );
537 buf.append( *(data->pLastOidInserted) , 10 );
538 buf.append( ", diagnosedTable=" );
539 buf.append(
540 OUStringToOString( *data->pLastTableInserted, pSettings->encoding ) );
542 log( pSettings, LogLevel::SQL, buf.makeStringAndClear().getStr() );
544 PQclear( result );
545 break;
547 case PGRES_TUPLES_OK: // success
549 // In case it is a single table, it has a primary key and all columns
550 // belonging to the primary key are in the result set, allow updateable result sets
551 // otherwise, don't
552 rtl::OUString table, schema;
553 Sequence< OUString > sourceTableKeys;
554 OStringVector vec;
555 tokenizeSQL( cmd, vec );
556 OUString sourceTable =
557 OStringToOUString(
558 extractSingleTableFromSelect( vec ), pSettings->encoding );
560 if( data->concurrency ==
561 com::sun::star::sdbc::ResultSetConcurrency::UPDATABLE )
563 OString aReason;
564 if( sourceTable.getLength() )
566 sourceTableKeys = lookupKeys(
567 pSettings->tables.is() ?
568 pSettings->tables : data->tableSupplier->getTables() ,
569 sourceTable,
570 &schema,
571 &table,
572 pSettings);
574 // check, whether the columns are in the result set (required !)
575 int i;
576 for( i = 0 ; i < sourceTableKeys.getLength() ; i ++ )
578 if( -1 == PQfnumber(
579 result,
580 OUStringToOString( sourceTableKeys[i] ,
581 pSettings->encoding ).getStr()) )
583 break;
587 if( sourceTableKeys.getLength() && i == sourceTableKeys.getLength() )
589 *(data->pLastResultset) =
590 UpdateableResultSet::createFromPGResultSet(
591 data->refMutex, data->owner, data->ppSettings, result,
592 schema, table,sourceTableKeys );
594 else if( ! table.getLength() )
596 rtl::OStringBuffer buf( 128 );
597 buf.append(
598 RTL_CONSTASCII_STRINGPARAM(
599 "can't support updateable resultset, because a single table in the "
600 "WHERE part of the statement could not be identified (" ) );
601 buf.append( cmd );
602 buf.append( RTL_CONSTASCII_STRINGPARAM( "." ) );
603 aReason = buf.makeStringAndClear();
605 else if( sourceTableKeys.getLength() )
607 ::rtl::OStringBuffer buf( 128 );
608 buf.append(
609 RTL_CONSTASCII_STRINGPARAM(
610 "can't support updateable resultset for table " ) );
611 buf.append( rtl::OUStringToOString( schema, pSettings->encoding ) );
612 buf.append( RTL_CONSTASCII_STRINGPARAM( "." ) );
613 buf.append( rtl::OUStringToOString( table, pSettings->encoding ) );
614 buf.append( RTL_CONSTASCII_STRINGPARAM( ", because resultset does not contain a part of the primary key ( column " ) );
615 buf.append( rtl::OUStringToOString( sourceTableKeys[i], pSettings->encoding ) );
616 buf.append( RTL_CONSTASCII_STRINGPARAM( " is missing )") );
617 aReason = buf.makeStringAndClear();
619 else
622 ::rtl::OStringBuffer buf( 128 );
623 buf.append(
624 RTL_CONSTASCII_STRINGPARAM(
625 "can't support updateable resultset for table " ) );
626 buf.append( rtl::OUStringToOString( schema, pSettings->encoding ) );
627 buf.append( RTL_CONSTASCII_STRINGPARAM( "." ) );
628 buf.append( rtl::OUStringToOString( table, pSettings->encoding ) );
629 buf.append( RTL_CONSTASCII_STRINGPARAM( ", because resultset table does not have a primary key " ) );
630 aReason = buf.makeStringAndClear();
633 else
635 ::rtl::OStringBuffer buf( 128 );
636 buf.append(
637 RTL_CONSTASCII_STRINGPARAM(
638 "can't support updateable result for selects with multiple tables (" ) );
639 buf.append( cmd );
640 buf.append( RTL_CONSTASCII_STRINGPARAM( ")" ) );
641 log( pSettings, LogLevel::SQL, buf.makeStringAndClear().getStr() );
643 if( ! (*(data->pLastResultset)).is() )
645 if( isLog( pSettings, LogLevel::ERROR ) )
647 log( pSettings, LogLevel::ERROR, aReason.getStr());
650 // TODO: How to react here correctly ?
651 // remove this piece of code
652 *(data->pLastResultset) =
653 new FakedUpdateableResultSet(
654 data->refMutex, data->owner,
655 data->ppSettings,result, schema, table,
656 OStringToOUString( aReason, pSettings->encoding) );
660 else if( sourceTable.getLength() && -1 != sourceTable.indexOf( '.' ) )
662 splitConcatenatedIdentifier( sourceTable, &schema, &table );
665 sal_Int32 returnedRows = PQntuples( result );
666 if( ! data->pLastResultset->is() )
667 *(data->pLastResultset) =
668 Reference< XCloseable > (
669 new ResultSet(
670 data->refMutex, data->owner,
671 data->ppSettings,result, schema, table ) );
672 *(data->pMultipleResultAvailable) = sal_True;
673 ret = sal_True;
674 if( isLog( pSettings, LogLevel::SQL ) )
676 rtl::OStringBuffer buf( 128 );
677 buf.append( RTL_CONSTASCII_STRINGPARAM("executed query '") );
678 buf.append( cmd );
679 buf.append( RTL_CONSTASCII_STRINGPARAM("' sucessfully") );
680 buf.append( RTL_CONSTASCII_STRINGPARAM(", duration=") );
681 buf.append( duration );
682 buf.append( RTL_CONSTASCII_STRINGPARAM("ms, returnedRows=") );
683 buf.append( returnedRows );
684 buf.append( RTL_CONSTASCII_STRINGPARAM("." ) );
685 log( pSettings, LogLevel::SQL, buf.makeStringAndClear().getStr() );
687 break;
689 case PGRES_EMPTY_QUERY:
690 case PGRES_COPY_OUT:
691 case PGRES_COPY_IN:
692 case PGRES_BAD_RESPONSE:
693 case PGRES_NONFATAL_ERROR:
694 case PGRES_FATAL_ERROR:
695 default:
696 raiseSQLException(
697 pSettings, data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) );
699 return ret;
703 static Sequence< OUString > getPrimaryKeyColumnNames(
704 const Reference< XConnection > & connection, const OUString &schemaName, const OUString &tableName )
706 Sequence< OUString > ret;
708 Int2StringMap mapIndex2Name;
709 fillAttnum2attnameMap( mapIndex2Name, connection, schemaName, tableName );
711 // retrieve the primary key ...
712 Reference< XPreparedStatement > stmt = connection->prepareStatement(
713 ASCII_STR(
714 "SELECT conkey " // 7
715 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
716 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
717 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
718 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
719 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" ) );
720 DisposeGuard guard( stmt );
721 Reference< XParameters > paras( stmt, UNO_QUERY );
722 paras->setString( 1 , tableName );
723 paras->setString( 2 , schemaName );
724 Reference< XResultSet > rs = stmt->executeQuery();
725 Reference< XRow > xRow( rs , UNO_QUERY );
727 if( rs->next() )
729 ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) );
731 return ret;
734 static void getAutoValues(
735 String2StringMap & result,
736 const Reference< XConnection > & connection,
737 const OUString &schemaName,
738 const OUString & tableName )
740 Reference< XPreparedStatement > stmt = connection->prepareStatement(
741 ASCII_STR("SELECT pg_attribute.attname, pg_attrdef.adsrc "
742 "FROM pg_class, pg_namespace, pg_attribute "
743 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
744 "pg_attribute.attnum = pg_attrdef.adnum "
745 "WHERE pg_attribute.attrelid = pg_class.oid AND "
746 "pg_class.relnamespace = pg_namespace.oid AND "
747 "pg_namespace.nspname = ? AND "
748 "pg_class.relname LIKE ? AND "
749 "pg_attrdef.adsrc != ''"
750 ) );
751 DisposeGuard guard( stmt );
752 Reference< XParameters > paras( stmt, UNO_QUERY );
753 paras->setString( 1 , schemaName );
754 paras->setString( 2 , tableName );
755 Reference< XResultSet > rs = stmt->executeQuery();
756 Reference< XRow > xRow( rs , UNO_QUERY );
758 while( rs->next() )
760 result[ OUStringToOString( xRow->getString( 1 ), RTL_TEXTENCODING_ASCII_US) ] =
761 OUStringToOString( xRow->getString(2), RTL_TEXTENCODING_ASCII_US );
765 Reference< XResultSet > getGeneratedValuesFromLastInsert(
766 ConnectionSettings *pConnectionSettings,
767 const Reference< XConnection > &connection,
768 sal_Int32 nLastOid,
769 const rtl::OUString & lastTableInserted,
770 const rtl::OString & lastQuery )
772 Reference< XResultSet > ret;
773 OUString query;
774 OUString schemaName, tableName;
775 splitConcatenatedIdentifier(
776 lastTableInserted, &schemaName, &tableName );
778 if( nLastOid && lastTableInserted.getLength() )
780 OUStringBuffer buf( 128 );
781 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SELECT * FROM " ) );
782 if( schemaName.getLength() )
783 bufferQuoteQualifiedIdentifier(buf, schemaName,tableName );
784 else
785 bufferQuoteIdentifier( buf, lastTableInserted );
786 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " WHERE oid = " ) );
787 buf.append( nLastOid , 10 );
788 query = buf.makeStringAndClear();
790 else if ( lastTableInserted.getLength() && lastQuery.getLength() )
792 // extract nameValue Pairs
793 String2StringMap namedValues;
794 extractNameValuePairsFromInsert( namedValues, lastQuery );
796 // debug ...
797 // rtl::OStringBuffer buf( 128);
798 // buf.append( "extracting name/value from '" );
799 // buf.append( lastQuery.getStr() );
800 // buf.append( "' to [" );
801 // for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
802 // {
803 // buf.append( ii->first.getStr() );
804 // buf.append( "=" );
805 // buf.append( ii->second.getStr() );
806 // buf.append( "," );
807 // }
808 // buf.append( "]\n" );
809 // printf( buf.makeStringAndClear() );
811 // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
812 // in postgresql doc
814 Sequence< OUString > keyColumnNames = getPrimaryKeyColumnNames( connection, schemaName, tableName );
815 if( keyColumnNames.getLength() )
817 OUStringBuffer buf( 128 );
818 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SELECT * FROM " ) );
819 bufferQuoteQualifiedIdentifier(buf, schemaName,tableName );
820 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " WHERE " ) );
821 bool additionalCondition = false;
822 String2StringMap autoValues;
823 for( int i = 0 ; i < keyColumnNames.getLength() ; i ++ )
825 OUString value;
826 OString columnName = OUStringToOString( keyColumnNames[i], pConnectionSettings->encoding );
827 String2StringMap::iterator ii = namedValues.begin();
828 for( ; ii != namedValues.end() ; ++ii )
830 if( columnName.equalsIgnoreAsciiCase( ii->first ) )
832 value = OStringToOUString( ii->second , pConnectionSettings->encoding );
833 break;
837 // check, if a column of the primary key was not inserted explicitly,
838 if( ii == namedValues.end() )
841 if( autoValues.begin() == autoValues.end() )
843 getAutoValues( autoValues, connection, schemaName, tableName );
845 // this could mean, that the column is a default or auto value, check this ...
846 String2StringMap::iterator ii = autoValues.begin();
847 for( ; ii != autoValues.end() ; ++ii )
849 if( columnName.equalsIgnoreAsciiCase( ii->first ) )
851 // it is indeed an auto value.
852 value = OStringToOUString(ii->second, RTL_TEXTENCODING_ASCII_US );
853 // check, whether it is a sequence
855 if( rtl_str_shortenedCompare_WithLength(
856 ii->second.getStr(), ii->second.getLength(),
857 RTL_CONSTASCII_STRINGPARAM( "nextval(" ), 8 ) == 0 )
859 // retrieve current sequence value:
860 OUStringBuffer myBuf(128 );
861 myBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SELECT currval(" ) );
862 myBuf.appendAscii( &(ii->second.getStr()[8]));
863 value = querySingleValue( connection, myBuf.makeStringAndClear() );
865 break;
868 if( ii == autoValues.end() )
870 // it even was no autovalue, no sense to continue as we can't query the
871 // inserted row
872 buf = OUStringBuffer();
873 break;
877 if( additionalCondition )
878 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " AND " ) );
879 bufferQuoteIdentifier( buf, keyColumnNames[i] );
880 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " = " ) );
881 buf.append( value );
882 additionalCondition = true;
884 query = buf.makeStringAndClear();
888 if( query.getLength() )
890 Reference< com::sun::star::sdbc::XStatement > stmt = connection->createStatement();
891 ret = stmt->executeQuery( query );
894 return ret;
898 sal_Bool Statement::execute( const OUString& sql )
899 throw (SQLException, RuntimeException)
901 osl::MutexGuard guard( m_refMutex->mutex );
902 checkClosed();
903 OString cmd = rtl::OUStringToOString( sql, m_pSettings->encoding );
905 m_lastResultset.clear();
906 m_lastTableInserted = rtl::OUString();
908 struct CommandData data;
909 data.refMutex = m_refMutex;
910 data.ppSettings = &m_pSettings;
911 data.pLastOidInserted = &m_lastOidInserted;
912 data.pLastQuery = &m_lastQuery;
913 data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount;
914 data.pMultipleResultAvailable = &m_multipleResultAvailable;
915 data.pLastTableInserted = &m_lastTableInserted;
916 data.pLastResultset = &m_lastResultset;
917 data.owner = *this;
918 data.tableSupplier = Reference< com::sun::star::sdbcx::XTablesSupplier >( m_connection, UNO_QUERY );
919 data.concurrency =
920 extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY );
921 return executePostgresCommand( cmd , &data );
924 Reference< XConnection > Statement::getConnection( )
925 throw (SQLException, RuntimeException)
927 Reference< XConnection > ret;
929 MutexGuard guard( m_refMutex->mutex );
930 checkClosed();
931 ret = m_connection;
933 return ret;
937 Any Statement::getWarnings( )
938 throw (SQLException,RuntimeException)
940 return Any();
943 void Statement::clearWarnings( )
944 throw (SQLException, RuntimeException)
948 Reference< ::com::sun::star::sdbc::XResultSetMetaData > Statement::getMetaData()
949 throw (SQLException,RuntimeException)
951 Reference< com::sun::star::sdbc::XResultSetMetaData > ret;
952 Reference< com::sun::star::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY );
953 if( supplier.is() )
954 ret = supplier->getMetaData();
955 return ret;
959 ::cppu::IPropertyArrayHelper & Statement::getInfoHelper()
961 return getStatementPropertyArrayHelper();
965 sal_Bool Statement::convertFastPropertyValue(
966 Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
967 throw (IllegalArgumentException)
969 rOldValue = m_props[nHandle];
970 sal_Bool bRet;
971 switch( nHandle )
973 case STATEMENT_CURSOR_NAME:
975 OUString val;
976 bRet = ( rValue >>= val );
977 rConvertedValue = makeAny( val );
978 break;
980 case STATEMENT_ESCAPE_PROCESSING:
982 sal_Bool val;
983 bRet = ( rValue >>= val );
984 rConvertedValue = makeAny( val );
985 break;
987 case STATEMENT_FETCH_DIRECTION:
988 case STATEMENT_FETCH_SIZE:
989 case STATEMENT_MAX_FIELD_SIZE:
990 case STATEMENT_MAX_ROWS:
991 case STATEMENT_QUERY_TIME_OUT:
992 case STATEMENT_RESULT_SET_CONCURRENCY:
993 case STATEMENT_RESULT_SET_TYPE:
995 sal_Int32 val;
996 bRet = ( rValue >>= val );
997 rConvertedValue = makeAny( val );
998 break;
1000 default:
1002 OUStringBuffer buf(128);
1003 buf.appendAscii( "pq_statement: Invalid property handle (" );
1004 buf.append( nHandle );
1005 buf.appendAscii( ")" );
1006 throw IllegalArgumentException( buf.makeStringAndClear(), *this, 2 );
1009 return bRet;
1013 void Statement::setFastPropertyValue_NoBroadcast(
1014 sal_Int32 nHandle,const Any& rValue ) throw (Exception)
1016 m_props[nHandle] = rValue;
1019 void Statement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1021 rValue = m_props[nHandle];
1024 Reference < XPropertySetInfo > Statement::getPropertySetInfo()
1025 throw(RuntimeException)
1027 return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
1031 Reference< XResultSet > Statement::getResultSet( )
1032 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
1034 return Reference< XResultSet > ( m_lastResultset, com::sun::star::uno::UNO_QUERY );
1037 sal_Int32 Statement::getUpdateCount( )
1038 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
1040 return m_multipleResultUpdateCount;
1043 sal_Bool Statement::getMoreResults( )
1044 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
1046 return sal_False;
1051 void Statement::disposing()
1053 close();
1056 Reference< XResultSet > Statement::getGeneratedValues( )
1057 throw (SQLException, RuntimeException)
1059 osl::MutexGuard guard( m_refMutex->mutex );
1060 return getGeneratedValuesFromLastInsert(
1061 m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery );