1 /*************************************************************************
3 * $RCSfile: pq_statement.cxx,v $
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,
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>
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>
92 using osl::MutexGuard
;
95 using rtl::OUStringBuffer
;
96 using rtl::OUStringToOString
;
97 using rtl::OStringToOUString
;
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
;
146 MutexGuard
guard( Mutex::getGlobalMutex() );
149 static Property aTable
[] =
152 OUString( RTL_CONSTASCII_USTRINGPARAM("CursorName") ), 0,
153 ::getCppuType( (OUString
*)0) , 0 ),
155 OUString( RTL_CONSTASCII_USTRINGPARAM("EscapeProcessing") ), 1,
156 ::getBooleanCppuType() , 0 ),
158 OUString( RTL_CONSTASCII_USTRINGPARAM("FetchDirection") ), 2,
159 ::getCppuType( (sal_Int32
*)0) , 0 ),
161 OUString( RTL_CONSTASCII_USTRINGPARAM("FetchSize") ), 3,
162 ::getCppuType( (sal_Int32
*)0) , 0 ),
164 OUString( RTL_CONSTASCII_USTRINGPARAM("MaxFieldSize") ), 4,
165 ::getCppuType( (sal_Int32
*)0) , 0 ),
167 OUString( RTL_CONSTASCII_USTRINGPARAM("MaxRows") ), 5,
168 ::getCppuType( (sal_Int32
*)0) , 0 ),
170 OUString( RTL_CONSTASCII_USTRINGPARAM("QueryTimeOut") ), 6,
171 ::getCppuType( (sal_Int32
*)0) , 0 ),
173 OUString( RTL_CONSTASCII_USTRINGPARAM("ResultSetConcurrency") ), 7,
174 ::getCppuType( (sal_Int32
*)0) , 0 ),
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
)
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
)
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 ) );
237 Sequence
< Type
> Statement::getTypes() throw ( RuntimeException
)
239 static cppu::OTypeCollection
*pCollection
;
242 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
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
;
266 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
269 static cppu::OImplementationId
id(sal_False
);
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
);
285 m_connection
.clear();
287 resultSet
= m_lastResultset
;
288 m_lastResultset
.clear();
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: ");
306 buf
.appendAscii( "[" );
307 buf
.appendAscii( errorType
);
308 buf
.appendAscii( "]" );
311 rtl::OUString( errorMsg
, strlen(errorMsg
) , m_pSettings
->encoding
) );
312 buf
.appendAscii( " (caused by statement '" );
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
)
339 raiseSQLException( sql
, "not a command" );
341 return m_multipleResultUpdateCount
;
345 static void raiseSQLException(
346 ConnectionSettings
*pSettings
,
347 const Reference
< XInterface
> & owner
,
349 const char * errorMsg
,
350 const char *errorType
= 0 )
351 throw( SQLException
)
353 OUStringBuffer
buf(128);
354 buf
.appendAscii( "pq_driver: ");
357 buf
.appendAscii( "[" );
358 buf
.appendAscii( errorType
);
359 buf
.appendAscii( "]" );
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
,
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
;
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() );
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
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() );
425 keySupplier
= Reference
< XKeysSupplier
> ( set
, UNO_QUERY
);
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
);
449 Reference
< XEnumerationAccess
> keys ( keySupplier
->getKeys(), UNO_QUERY
);
450 Reference
< XEnumeration
> enumeration
= keys
->createEnumeration();
451 while( enumeration
->hasMoreElements() )
453 enumeration
->nextElement() >>= set
;
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
;
470 set
->getPropertyValue( st
.NAME
) >>= name
;
472 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
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() );
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
;
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
;
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
) );
531 buf
.append( ", duration=" );
532 buf
.append( duration
);
534 if( *(data
->pLastOidInserted
) )
536 buf
.append( ", usedOid=" );
537 buf
.append( *(data
->pLastOidInserted
) , 10 );
538 buf
.append( ", diagnosedTable=" );
540 OUStringToOString( *data
->pLastTableInserted
, pSettings
->encoding
) );
542 log( pSettings
, LogLevel::SQL
, buf
.makeStringAndClear().getStr() );
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
552 rtl::OUString table
, schema
;
553 Sequence
< OUString
> sourceTableKeys
;
555 tokenizeSQL( cmd
, vec
);
556 OUString sourceTable
=
558 extractSingleTableFromSelect( vec
), pSettings
->encoding
);
560 if( data
->concurrency
==
561 com::sun::star::sdbc::ResultSetConcurrency::UPDATABLE
)
564 if( sourceTable
.getLength() )
566 sourceTableKeys
= lookupKeys(
567 pSettings
->tables
.is() ?
568 pSettings
->tables
: data
->tableSupplier
->getTables() ,
574 // check, whether the columns are in the result set (required !)
576 for( i
= 0 ; i
< sourceTableKeys
.getLength() ; i
++ )
580 OUStringToOString( sourceTableKeys
[i
] ,
581 pSettings
->encoding
).getStr()) )
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 );
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 (" ) );
602 buf
.append( RTL_CONSTASCII_STRINGPARAM( "." ) );
603 aReason
= buf
.makeStringAndClear();
605 else if( sourceTableKeys
.getLength() )
607 ::rtl::OStringBuffer
buf( 128 );
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();
622 ::rtl::OStringBuffer
buf( 128 );
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();
635 ::rtl::OStringBuffer
buf( 128 );
637 RTL_CONSTASCII_STRINGPARAM(
638 "can't support updateable result for selects with multiple tables (" ) );
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
> (
670 data
->refMutex
, data
->owner
,
671 data
->ppSettings
,result
, schema
, table
) );
672 *(data
->pMultipleResultAvailable
) = sal_True
;
674 if( isLog( pSettings
, LogLevel::SQL
) )
676 rtl::OStringBuffer
buf( 128 );
677 buf
.append( RTL_CONSTASCII_STRINGPARAM("executed query '") );
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() );
689 case PGRES_EMPTY_QUERY
:
692 case PGRES_BAD_RESPONSE
:
693 case PGRES_NONFATAL_ERROR
:
694 case PGRES_FATAL_ERROR
:
697 pSettings
, data
->owner
, cmd
, PQresultErrorMessage( result
) , PQresStatus( state
) );
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(
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
);
729 ret
= convertMappedIntArray2StringArray( mapIndex2Name
, string2intarray(xRow
->getString( 1 ) ) );
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 != ''"
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
);
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
,
769 const rtl::OUString
& lastTableInserted
,
770 const rtl::OString
& lastQuery
)
772 Reference
< XResultSet
> ret
;
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
);
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
);
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 )
803 // buf.append( ii->first.getStr() );
804 // buf.append( "=" );
805 // buf.append( ii->second.getStr() );
806 // buf.append( "," );
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
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
++ )
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
);
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() );
868 if( ii
== autoValues
.end() )
870 // it even was no autovalue, no sense to continue as we can't query the
872 buf
= OUStringBuffer();
877 if( additionalCondition
)
878 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( " AND " ) );
879 bufferQuoteIdentifier( buf
, keyColumnNames
[i
] );
880 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( " = " ) );
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
);
898 sal_Bool
Statement::execute( const OUString
& sql
)
899 throw (SQLException
, RuntimeException
)
901 osl::MutexGuard
guard( m_refMutex
->mutex
);
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
;
918 data
.tableSupplier
= Reference
< com::sun::star::sdbcx::XTablesSupplier
>( m_connection
, UNO_QUERY
);
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
);
937 Any
Statement::getWarnings( )
938 throw (SQLException
,RuntimeException
)
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
);
954 ret
= supplier
->getMetaData();
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
];
973 case STATEMENT_CURSOR_NAME
:
976 bRet
= ( rValue
>>= val
);
977 rConvertedValue
= makeAny( val
);
980 case STATEMENT_ESCAPE_PROCESSING
:
983 bRet
= ( rValue
>>= val
);
984 rConvertedValue
= makeAny( val
);
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
:
996 bRet
= ( rValue
>>= val
);
997 rConvertedValue
= makeAny( val
);
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 );
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
)
1051 void Statement::disposing()
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
);