1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * Effective License of whole file:
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
25 * Copyright: 2000 by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 ************************************************************************/
37 #include "pq_statement.hxx"
38 #include "pq_fakedupdateableresultset.hxx"
39 #include "pq_updateableresultset.hxx"
40 #include "pq_tools.hxx"
41 #include "pq_statics.hxx"
43 #include <osl/thread.h>
46 #include <rtl/ustrbuf.hxx>
47 #include <rtl/strbuf.hxx>
49 #include <cppuhelper/typeprovider.hxx>
50 #include <cppuhelper/queryinterface.hxx>
52 #include <com/sun/star/beans/PropertyAttribute.hpp>
54 #include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
55 #include <com/sun/star/sdbc/ResultSetType.hpp>
56 #include <com/sun/star/sdbc/XParameters.hpp>
58 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
59 #include <com/sun/star/sdbcx/KeyType.hpp>
60 #include <com/sun/star/sdbcx/XKeysSupplier.hpp>
62 #include <com/sun/star/container/XIndexAccess.hpp>
63 #include <com/sun/star/container/XEnumerationAccess.hpp>
68 using osl::MutexGuard
;
71 using com::sun::star::uno::Any
;
72 using com::sun::star::uno::makeAny
;
73 using com::sun::star::uno::Type
;
74 using com::sun::star::uno::RuntimeException
;
75 using com::sun::star::uno::Exception
;
76 using com::sun::star::uno::Sequence
;
77 using com::sun::star::uno::Reference
;
78 using com::sun::star::uno::XInterface
;
79 using com::sun::star::uno::UNO_QUERY
;
81 using com::sun::star::lang::IllegalArgumentException
;
83 using com::sun::star::sdbc::XWarningsSupplier
;
84 using com::sun::star::sdbc::XCloseable
;
85 using com::sun::star::sdbc::XStatement
;
86 using com::sun::star::sdbc::XPreparedStatement
;
87 using com::sun::star::sdbc::XParameters
;
88 using com::sun::star::sdbc::XRow
;
89 using com::sun::star::sdbc::XResultSet
;
90 using com::sun::star::sdbc::XGeneratedResultSet
;
91 using com::sun::star::sdbc::XConnection
;
92 using com::sun::star::sdbc::SQLException
;
94 using com::sun::star::sdbcx::XColumnsSupplier
;
95 using com::sun::star::sdbcx::XTablesSupplier
;
96 using com::sun::star::sdbcx::XKeysSupplier
;
98 using com::sun::star::beans::Property
;
99 using com::sun::star::beans::XPropertySetInfo
;
100 using com::sun::star::beans::XPropertySet
;
101 using com::sun::star::beans::XFastPropertySet
;
102 using com::sun::star::beans::XMultiPropertySet
;
104 using com::sun::star::container::XNameAccess
;
105 using com::sun::star::container::XEnumerationAccess
;
106 using com::sun::star::container::XEnumeration
;
107 using com::sun::star::container::XIndexAccess
;
109 namespace pq_sdbc_driver
111 static ::cppu::IPropertyArrayHelper
& getStatementPropertyArrayHelper()
113 static ::cppu::IPropertyArrayHelper
*pArrayHelper
;
116 MutexGuard
guard( Mutex::getGlobalMutex() );
119 static Property aTable
[] =
122 OUString("CursorName"), 0,
123 ::cppu::UnoType
<OUString
>::get() , 0 ),
125 OUString("EscapeProcessing"), 1,
126 ::getBooleanCppuType() , 0 ),
128 OUString("FetchDirection"), 2,
129 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
131 OUString("FetchSize"), 3,
132 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
134 OUString("MaxFieldSize"), 4,
135 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
137 OUString("MaxRows"), 5,
138 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
140 OUString("QueryTimeOut"), 6,
141 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
143 OUString("ResultSetConcurrency"), 7,
144 ::cppu::UnoType
<sal_Int32
>::get() , 0 ),
146 OUString("ResultSetType"), 8,
147 ::cppu::UnoType
<sal_Int32
>::get() , 0 )
149 OSL_ASSERT( sizeof(aTable
)/ sizeof(Property
) == STATEMENT_SIZE
);
150 static ::cppu::OPropertyArrayHelper
arrayHelper( aTable
, STATEMENT_SIZE
, sal_True
);
151 pArrayHelper
= &arrayHelper
;
154 return *pArrayHelper
;
157 Statement::Statement( const ::rtl::Reference
< RefCountedMutex
> & refMutex
,
158 const Reference
< XConnection
> & conn
,
159 struct ConnectionSettings
*pSettings
)
160 : OComponentHelper( refMutex
->mutex
)
161 , OPropertySetHelper( OComponentHelper::rBHelper
)
162 , m_connection( conn
)
163 , m_pSettings( pSettings
)
164 , m_refMutex( refMutex
)
165 , m_multipleResultAvailable(false)
166 , m_multipleResultUpdateCount(0)
167 , m_lastOidInserted(InvalidOid
)
169 m_props
[STATEMENT_QUERY_TIME_OUT
] = makeAny( (sal_Int32
)0 );
170 m_props
[STATEMENT_MAX_ROWS
] = makeAny( (sal_Int32
)0 );
171 m_props
[STATEMENT_RESULT_SET_CONCURRENCY
] = makeAny(
172 com::sun::star::sdbc::ResultSetConcurrency::READ_ONLY
);
173 m_props
[STATEMENT_RESULT_SET_TYPE
] = makeAny(
174 com::sun::star::sdbc::ResultSetType::SCROLL_INSENSITIVE
);
177 Statement::~Statement()
179 POSTGRE_TRACE( "dtor Statement" );
182 void Statement::checkClosed() throw (SQLException
, RuntimeException
)
184 if( ! m_pSettings
|| ! m_pSettings
->pConnection
)
186 "pq_driver: Statement or connection has already been closed !",
187 *this, OUString(),1,Any());
190 Any
Statement::queryInterface( const Type
& reqType
) throw (RuntimeException
, std::exception
)
194 ret
= OComponentHelper::queryInterface( reqType
);
195 if( ! ret
.hasValue() )
196 ret
= ::cppu::queryInterface( reqType
,
197 static_cast< XWarningsSupplier
* > ( this ),
198 static_cast< XStatement
* > ( this ),
199 static_cast< com::sun::star::sdbc::XResultSetMetaDataSupplier
* > ( this ),
200 static_cast< XCloseable
* > ( this ),
201 static_cast< XPropertySet
* > ( this ),
202 static_cast< XMultiPropertySet
* > ( this ),
203 static_cast< XGeneratedResultSet
* > ( this ),
204 static_cast< XFastPropertySet
* > ( this ) );
209 Sequence
< Type
> Statement::getTypes() throw ( RuntimeException
, std::exception
)
211 static cppu::OTypeCollection
*pCollection
;
214 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
217 static cppu::OTypeCollection
collection(
218 getCppuType( (Reference
< XWarningsSupplier
> *) 0 ),
219 getCppuType( (Reference
< XStatement
> *) 0 ),
220 getCppuType( (Reference
< com::sun::star::sdbc::XResultSetMetaDataSupplier
> *) 0 ),
221 getCppuType( (Reference
< XCloseable
> *) 0 ),
222 getCppuType( (Reference
< XPropertySet
>*) 0 ),
223 getCppuType( (Reference
< XFastPropertySet
> *) 0 ),
224 getCppuType( (Reference
< XMultiPropertySet
> *) 0 ),
225 getCppuType( (Reference
< XGeneratedResultSet
> *) 0 ),
226 OComponentHelper::getTypes());
227 pCollection
= &collection
;
230 return pCollection
->getTypes();
233 Sequence
< sal_Int8
> Statement::getImplementationId() throw ( RuntimeException
, std::exception
)
235 return css::uno::Sequence
<sal_Int8
>();
238 void Statement::close( ) throw (SQLException
, RuntimeException
, std::exception
)
240 // let the connection die without acquired mutex !
241 Reference
< XConnection
> r
;
242 Reference
< XCloseable
> resultSet
;
244 MutexGuard
guard( m_refMutex
->mutex
);
247 m_connection
.clear();
249 resultSet
= m_lastResultset
;
250 m_lastResultset
.clear();
255 POSTGRE_TRACE( "statement closed" );
260 void Statement::raiseSQLException(
261 const OUString
& sql
, const char * errorMsg
, const char *errorType
)
262 throw( SQLException
)
264 OUStringBuffer
buf(128);
265 buf
.appendAscii( "pq_driver: ");
268 buf
.appendAscii( "[" );
269 buf
.appendAscii( errorType
);
270 buf
.appendAscii( "]" );
273 OUString( errorMsg
, strlen(errorMsg
) , m_pSettings
->encoding
) );
274 buf
.appendAscii( " (caused by statement '" );
276 buf
.appendAscii( "')" );
277 OUString error
= buf
.makeStringAndClear();
278 log( m_pSettings
, LogLevel::ERROR
, error
);
279 throw SQLException( error
, *this, OUString(), 1, Any() );
282 Reference
< XResultSet
> Statement::executeQuery(const OUString
& sql
)
283 throw (SQLException
, RuntimeException
, std::exception
)
285 Reference
< XCloseable
> lastResultSetHolder
= m_lastResultset
;
286 if( lastResultSetHolder
.is() )
287 lastResultSetHolder
->close();
289 if( ! execute( sql
) )
291 raiseSQLException( sql
, "not a query" );
293 return Reference
< XResultSet
> ( m_lastResultset
, com::sun::star::uno::UNO_QUERY
);
296 sal_Int32
Statement::executeUpdate( const OUString
& sql
)
297 throw (SQLException
, RuntimeException
, std::exception
)
301 raiseSQLException( sql
, "not a command" );
303 return m_multipleResultUpdateCount
;
307 static void raiseSQLException(
308 ConnectionSettings
*pSettings
,
309 const Reference
< XInterface
> & owner
,
311 const char * errorMsg
,
312 const char *errorType
= 0 )
313 throw( SQLException
)
315 OUStringBuffer
buf(128);
316 buf
.appendAscii( "pq_driver: ");
319 buf
.appendAscii( "[" );
320 buf
.appendAscii( errorType
);
321 buf
.appendAscii( "]" );
324 OUString( errorMsg
, strlen(errorMsg
) , pSettings
->encoding
) );
325 buf
.appendAscii( " (caused by statement '" );
326 buf
.append( OStringToOUString( sql
, pSettings
->encoding
) );
327 buf
.appendAscii( "')" );
328 OUString error
= buf
.makeStringAndClear();
329 log( pSettings
, LogLevel::ERROR
, error
);
330 throw SQLException( error
, owner
, OUString(), 1, Any() );
334 // returns the elements of the primary key of the given table
335 // static Sequence< Reference< com::sun::star::beans::XPropertySet > > lookupKeys(
336 static Sequence
< OUString
> lookupKeys(
337 const Reference
< com::sun::star::container::XNameAccess
> &tables
,
338 const OUString
& table
,
341 ConnectionSettings
*pSettings
)
343 Sequence
< OUString
> ret
;
344 Reference
< XKeysSupplier
> keySupplier
;
345 Statics
& st
= getStatics();
347 if( tables
->hasByName( table
) )
348 tables
->getByName( table
) >>= keySupplier
;
349 else if( -1 == table
.indexOf( '.' ) )
351 // it wasn't a fully qualified name. Now need to skip through all tables.
352 Reference
< XEnumerationAccess
> enumerationAccess
=
353 Reference
< XEnumerationAccess
> ( tables
, UNO_QUERY
);
355 Reference
< com::sun::star::container::XEnumeration
> enumeration
=
356 enumerationAccess
->createEnumeration();
357 while( enumeration
->hasMoreElements() )
359 Reference
< XPropertySet
> set
;
360 enumeration
->nextElement() >>= set
;
364 if( set
->getPropertyValue( st
.NAME
) >>= name
)
366 // printf( "searching %s %s\n",
367 // OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
368 // OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
372 if( keySupplier
.is() )
374 // is ambigous, as I don't know postgresql searchpath,
375 // I can't continue here, as I may write to a different table
377 if( isLog( pSettings
, LogLevel::INFO
) )
379 OStringBuffer
buf( 128 );
380 buf
.append( "Can't offer updateable result set because table " );
381 buf
.append( OUStringToOString(name
, pSettings
->encoding
) );
382 buf
.append( " is duplicated, add schema to resolve ambiguity" );
383 log( pSettings
, LogLevel::INFO
, buf
.makeStringAndClear().getStr() );
387 keySupplier
= Reference
< XKeysSupplier
> ( set
, UNO_QUERY
);
394 if( isLog( pSettings
, LogLevel::INFO
) )
396 OStringBuffer
buf( 128 );
397 buf
.append( "Can't offer updateable result set ( table " );
398 buf
.append( OUStringToOString(table
, pSettings
->encoding
) );
399 buf
.append( " is unknown)" );
400 log( pSettings
, LogLevel::INFO
, buf
.makeStringAndClear().getStr() );
404 if( keySupplier
.is() )
406 Reference
< XPropertySet
> set( keySupplier
, UNO_QUERY
);
407 set
->getPropertyValue( getStatics().NAME
) >>= (*pTable
);
408 set
->getPropertyValue( getStatics().SCHEMA_NAME
) >>= (*pSchema
);
411 Reference
< XEnumerationAccess
> keys ( keySupplier
->getKeys(), UNO_QUERY
);
412 Reference
< XEnumeration
> enumeration
= keys
->createEnumeration();
413 while( enumeration
->hasMoreElements() )
415 enumeration
->nextElement() >>= set
;
416 sal_Int32 keyType
= 0;
417 if( (set
->getPropertyValue( st
.TYPE
) >>= keyType
) &&
418 keyType
== com::sun::star::sdbcx::KeyType::PRIMARY
)
420 Reference
< XColumnsSupplier
> columns( set
, UNO_QUERY
);
421 Reference
< XIndexAccess
> indexAccess
=
422 Reference
< XIndexAccess
> ( columns
->getColumns(), UNO_QUERY
);
424 int length
= indexAccess
->getCount();
425 ret
.realloc( length
);
426 // printf( "primary key for Table %s is ",
427 // OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
428 for( int i
= 0 ; i
< length
; i
++ )
430 indexAccess
->getByIndex( i
) >>= set
;
432 set
->getPropertyValue( st
.NAME
) >>= name
;
434 // printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
439 if( ! ret
.getLength() )
441 if( isLog( pSettings
, LogLevel::INFO
) )
443 OStringBuffer
buf( 128 );
444 buf
.append( "Can't offer updateable result set ( table " );
445 buf
.append( OUStringToOString(table
, pSettings
->encoding
) );
446 buf
.append( " does not have a primary key)" );
447 log( pSettings
, LogLevel::INFO
, buf
.makeStringAndClear().getStr() );
454 bool executePostgresCommand( const OString
& cmd
, struct CommandData
*data
)
456 ConnectionSettings
*pSettings
= *(data
->ppSettings
);
458 sal_Int32 duration
= osl_getGlobalTimer();
459 PGresult
*result
= PQexec( pSettings
->pConnection
, cmd
.getStr() );
460 duration
= osl_getGlobalTimer() - duration
;
463 pSettings
, data
->owner
, cmd
, PQerrorMessage( pSettings
->pConnection
) );
465 ExecStatusType state
= PQresultStatus( result
);
466 *(data
->pLastOidInserted
) = 0;
467 *(data
->pLastTableInserted
) = OUString();
468 *(data
->pLastQuery
) = cmd
;
473 case PGRES_COMMAND_OK
:
475 *(data
->pMultipleResultUpdateCount
) = atoi( PQcmdTuples( result
) );
476 *(data
->pMultipleResultAvailable
) = false;
478 // in case an oid value is available, we retrieve it
479 *(data
->pLastOidInserted
) = PQoidValue( result
);
481 // in case it was a single insert, extract the name of the table,
482 // otherwise the table name is empty
483 *(data
->pLastTableInserted
) =
484 extractTableFromInsert( OStringToOUString( cmd
, pSettings
->encoding
) );
485 if( isLog( pSettings
, LogLevel::SQL
) )
487 OStringBuffer
buf( 128 );
488 buf
.append( "executed command '" );
489 buf
.append( cmd
.getStr() );
490 buf
.append( "' successfully (" );
491 buf
.append( *( data
->pMultipleResultUpdateCount
) );
493 buf
.append( ", duration=" );
494 buf
.append( duration
);
496 if( *(data
->pLastOidInserted
) )
498 buf
.append( ", usedOid=" );
499 buf
.append( *(data
->pLastOidInserted
) , 10 );
500 buf
.append( ", diagnosedTable=" );
502 OUStringToOString( *data
->pLastTableInserted
, pSettings
->encoding
) );
504 log( pSettings
, LogLevel::SQL
, buf
.makeStringAndClear().getStr() );
509 case PGRES_TUPLES_OK
: // success
511 // In case it is a single table, it has a primary key and all columns
512 // belonging to the primary key are in the result set, allow updateable result sets
514 OUString table
, schema
;
515 Sequence
< OUString
> sourceTableKeys
;
517 tokenizeSQL( cmd
, vec
);
518 OUString sourceTable
=
520 extractSingleTableFromSelect( vec
), pSettings
->encoding
);
522 if( data
->concurrency
==
523 com::sun::star::sdbc::ResultSetConcurrency::UPDATABLE
)
526 if( sourceTable
.getLength() )
528 sourceTableKeys
= lookupKeys(
529 pSettings
->tables
.is() ?
530 pSettings
->tables
: data
->tableSupplier
->getTables() ,
536 // check, whether the columns are in the result set (required !)
538 for( i
= 0 ; i
< sourceTableKeys
.getLength() ; i
++ )
542 OUStringToOString( sourceTableKeys
[i
] ,
543 pSettings
->encoding
).getStr()) )
549 if( sourceTableKeys
.getLength() && i
== sourceTableKeys
.getLength() )
551 *(data
->pLastResultset
) =
552 UpdateableResultSet::createFromPGResultSet(
553 data
->refMutex
, data
->owner
, data
->ppSettings
, result
,
554 schema
, table
,sourceTableKeys
);
556 else if( ! table
.getLength() )
558 OStringBuffer
buf( 128 );
559 buf
.append( "can't support updateable resultset, because a single table in the "
560 "WHERE part of the statement could not be identified (" );
563 aReason
= buf
.makeStringAndClear();
565 else if( sourceTableKeys
.getLength() )
567 OStringBuffer
buf( 128 );
568 buf
.append( "can't support updateable resultset for table " );
569 buf
.append( OUStringToOString( schema
, pSettings
->encoding
) );
571 buf
.append( OUStringToOString( table
, pSettings
->encoding
) );
572 buf
.append( ", because resultset does not contain a part of the primary key ( column " );
573 buf
.append( OUStringToOString( sourceTableKeys
[i
], pSettings
->encoding
) );
574 buf
.append( " is missing )" );
575 aReason
= buf
.makeStringAndClear();
580 OStringBuffer
buf( 128 );
581 buf
.append( "can't support updateable resultset for table " );
582 buf
.append( OUStringToOString( schema
, pSettings
->encoding
) );
584 buf
.append( OUStringToOString( table
, pSettings
->encoding
) );
585 buf
.append( ", because resultset table does not have a primary key " );
586 aReason
= buf
.makeStringAndClear();
591 OStringBuffer
buf( 128 );
592 buf
.append( "can't support updateable result for selects with multiple tables (" );
595 log( pSettings
, LogLevel::SQL
, buf
.makeStringAndClear().getStr() );
597 if( ! (*(data
->pLastResultset
)).is() )
599 if( isLog( pSettings
, LogLevel::ERROR
) )
601 log( pSettings
, LogLevel::ERROR
, aReason
.getStr());
604 // TODO: How to react here correctly ?
605 // remove this piece of code
606 *(data
->pLastResultset
) =
607 new FakedUpdateableResultSet(
608 data
->refMutex
, data
->owner
,
609 data
->ppSettings
,result
, schema
, table
,
610 OStringToOUString( aReason
, pSettings
->encoding
) );
614 else if( sourceTable
.getLength() > 0)
616 splitConcatenatedIdentifier( sourceTable
, &schema
, &table
);
619 sal_Int32 returnedRows
= PQntuples( result
);
620 if( ! data
->pLastResultset
->is() )
621 *(data
->pLastResultset
) =
622 Reference
< XCloseable
> (
624 data
->refMutex
, data
->owner
,
625 data
->ppSettings
,result
, schema
, table
) );
626 *(data
->pMultipleResultAvailable
) = true;
628 if( isLog( pSettings
, LogLevel::SQL
) )
630 OStringBuffer
buf( 128 );
631 buf
.append( "executed query '" );
633 buf
.append( "' successfully" );
634 buf
.append( ", duration=" );
635 buf
.append( duration
);
636 buf
.append( "ms, returnedRows=" );
637 buf
.append( returnedRows
);
639 log( pSettings
, LogLevel::SQL
, buf
.makeStringAndClear().getStr() );
643 case PGRES_EMPTY_QUERY
:
646 case PGRES_BAD_RESPONSE
:
647 case PGRES_NONFATAL_ERROR
:
648 case PGRES_FATAL_ERROR
:
651 pSettings
, data
->owner
, cmd
, PQresultErrorMessage( result
) , PQresStatus( state
) );
657 static Sequence
< OUString
> getPrimaryKeyColumnNames(
658 const Reference
< XConnection
> & connection
, const OUString
&schemaName
, const OUString
&tableName
)
660 Sequence
< OUString
> ret
;
662 Int2StringMap mapIndex2Name
;
663 fillAttnum2attnameMap( mapIndex2Name
, connection
, schemaName
, tableName
);
665 // retrieve the primary key ...
666 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
667 "SELECT conkey " // 7
668 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
669 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
670 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
671 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
672 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" );
673 DisposeGuard
guard( stmt
);
674 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
675 paras
->setString( 1 , tableName
);
676 paras
->setString( 2 , schemaName
);
677 Reference
< XResultSet
> rs
= stmt
->executeQuery();
678 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
682 ret
= convertMappedIntArray2StringArray( mapIndex2Name
, string2intarray(xRow
->getString( 1 ) ) );
687 static void getAutoValues(
688 String2StringMap
& result
,
689 const Reference
< XConnection
> & connection
,
690 const OUString
&schemaName
,
691 const OUString
& tableName
)
693 Reference
< XPreparedStatement
> stmt
= connection
->prepareStatement(
694 "SELECT pg_attribute.attname, pg_attrdef.adsrc "
695 "FROM pg_class, pg_namespace, pg_attribute "
696 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
697 "pg_attribute.attnum = pg_attrdef.adnum "
698 "WHERE pg_attribute.attrelid = pg_class.oid AND "
699 "pg_class.relnamespace = pg_namespace.oid AND "
700 "pg_namespace.nspname = ? AND "
701 // LEM TODO: this is weird; why "LIKE" and not "="?
702 // Most probably gives problems if tableName contains '%'
703 "pg_class.relname LIKE ? AND "
704 "pg_attrdef.adsrc != ''"
706 DisposeGuard
guard( stmt
);
707 Reference
< XParameters
> paras( stmt
, UNO_QUERY
);
708 paras
->setString( 1 , schemaName
);
709 paras
->setString( 2 , tableName
);
710 Reference
< XResultSet
> rs
= stmt
->executeQuery();
711 Reference
< XRow
> xRow( rs
, UNO_QUERY
);
715 result
[ OUStringToOString( xRow
->getString( 1 ), RTL_TEXTENCODING_ASCII_US
) ] =
716 OUStringToOString( xRow
->getString(2), RTL_TEXTENCODING_ASCII_US
);
720 Reference
< XResultSet
> getGeneratedValuesFromLastInsert(
721 ConnectionSettings
*pConnectionSettings
,
722 const Reference
< XConnection
> &connection
,
724 const OUString
& lastTableInserted
,
725 const OString
& lastQuery
)
727 Reference
< XResultSet
> ret
;
729 OUString schemaName
, tableName
;
730 splitConcatenatedIdentifier(
731 lastTableInserted
, &schemaName
, &tableName
);
733 if( nLastOid
&& lastTableInserted
.getLength() )
735 OUStringBuffer
buf( 128 );
736 buf
.append( "SELECT * FROM " );
737 if( schemaName
.getLength() )
738 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
740 bufferQuoteIdentifier( buf
, lastTableInserted
, pConnectionSettings
);
741 buf
.append( " WHERE oid = " );
742 buf
.append( nLastOid
, 10 );
743 query
= buf
.makeStringAndClear();
745 else if ( lastTableInserted
.getLength() && lastQuery
.getLength() )
747 // extract nameValue Pairs
748 String2StringMap namedValues
;
749 extractNameValuePairsFromInsert( namedValues
, lastQuery
);
752 // OStringBuffer buf( 128);
753 // buf.append( "extracting name/value from '" );
754 // buf.append( lastQuery.getStr() );
755 // buf.append( "' to [" );
756 // for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
758 // buf.append( ii->first.getStr() );
759 // buf.append( "=" );
760 // buf.append( ii->second.getStr() );
761 // buf.append( "," );
763 // buf.append( "]\n" );
764 // printf( "%s", buf.makeStringAndClear() );
766 // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
769 Sequence
< OUString
> keyColumnNames
= getPrimaryKeyColumnNames( connection
, schemaName
, tableName
);
770 if( keyColumnNames
.getLength() )
772 OUStringBuffer
buf( 128 );
773 buf
.append( "SELECT * FROM " );
774 bufferQuoteQualifiedIdentifier(buf
, schemaName
, tableName
, pConnectionSettings
);
775 buf
.append( " WHERE " );
776 bool additionalCondition
= false;
777 String2StringMap autoValues
;
778 for( int i
= 0 ; i
< keyColumnNames
.getLength() ; i
++ )
781 OString columnName
= OUStringToOString( keyColumnNames
[i
], pConnectionSettings
->encoding
);
782 String2StringMap::iterator ii
= namedValues
.begin();
783 for( ; ii
!= namedValues
.end() ; ++ii
)
785 if( columnName
.equalsIgnoreAsciiCase( ii
->first
) )
787 value
= OStringToOUString( ii
->second
, pConnectionSettings
->encoding
);
792 // check, if a column of the primary key was not inserted explicitly,
793 if( ii
== namedValues
.end() )
796 if( autoValues
.begin() == autoValues
.end() )
798 getAutoValues( autoValues
, connection
, schemaName
, tableName
);
800 // this could mean, that the column is a default or auto value, check this ...
801 String2StringMap::iterator j
= autoValues
.begin();
802 for( ; j
!= autoValues
.end() ; ++j
)
804 if( columnName
.equalsIgnoreAsciiCase( j
->first
) )
806 // it is indeed an auto value.
807 value
= OStringToOUString(j
->second
, RTL_TEXTENCODING_ASCII_US
);
808 // check, whether it is a sequence
810 if( rtl_str_shortenedCompare_WithLength(
811 j
->second
.getStr(), j
->second
.getLength(),
812 RTL_CONSTASCII_STRINGPARAM( "nextval(" ), 8 ) == 0 )
814 // retrieve current sequence value:
815 OUStringBuffer
myBuf(128 );
816 myBuf
.append( "SELECT currval(" );
817 myBuf
.appendAscii( &(j
->second
.getStr()[8]));
818 value
= querySingleValue( connection
, myBuf
.makeStringAndClear() );
823 if( j
== autoValues
.end() )
825 // it even was no autovalue, no sense to continue as we can't query the
827 buf
= OUStringBuffer();
832 if( additionalCondition
)
833 buf
.append( " AND " );
834 bufferQuoteIdentifier( buf
, keyColumnNames
[i
], pConnectionSettings
);
837 additionalCondition
= true;
839 query
= buf
.makeStringAndClear();
843 if( query
.getLength() )
845 Reference
< com::sun::star::sdbc::XStatement
> stmt
= connection
->createStatement();
846 ret
= stmt
->executeQuery( query
);
853 sal_Bool
Statement::execute( const OUString
& sql
)
854 throw (SQLException
, RuntimeException
, std::exception
)
856 osl::MutexGuard
guard( m_refMutex
->mutex
);
858 OString cmd
= OUStringToOString( sql
, m_pSettings
);
860 m_lastResultset
.clear();
861 m_lastTableInserted
= OUString();
863 struct CommandData data
;
864 data
.refMutex
= m_refMutex
;
865 data
.ppSettings
= &m_pSettings
;
866 data
.pLastOidInserted
= &m_lastOidInserted
;
867 data
.pLastQuery
= &m_lastQuery
;
868 data
.pMultipleResultUpdateCount
= &m_multipleResultUpdateCount
;
869 data
.pMultipleResultAvailable
= &m_multipleResultAvailable
;
870 data
.pLastTableInserted
= &m_lastTableInserted
;
871 data
.pLastResultset
= &m_lastResultset
;
873 data
.tableSupplier
= Reference
< com::sun::star::sdbcx::XTablesSupplier
>( m_connection
, UNO_QUERY
);
875 extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY
);
876 return executePostgresCommand( cmd
, &data
);
879 Reference
< XConnection
> Statement::getConnection( )
880 throw (SQLException
, RuntimeException
, std::exception
)
882 Reference
< XConnection
> ret
;
884 MutexGuard
guard( m_refMutex
->mutex
);
892 Any
Statement::getWarnings( )
893 throw (SQLException
,RuntimeException
, std::exception
)
898 void Statement::clearWarnings( )
899 throw (SQLException
, RuntimeException
, std::exception
)
903 Reference
< ::com::sun::star::sdbc::XResultSetMetaData
> Statement::getMetaData()
904 throw (SQLException
,RuntimeException
, std::exception
)
906 Reference
< com::sun::star::sdbc::XResultSetMetaData
> ret
;
907 Reference
< com::sun::star::sdbc::XResultSetMetaDataSupplier
> supplier( m_lastResultset
, UNO_QUERY
);
909 ret
= supplier
->getMetaData();
914 ::cppu::IPropertyArrayHelper
& Statement::getInfoHelper()
916 return getStatementPropertyArrayHelper();
920 sal_Bool
Statement::convertFastPropertyValue(
921 Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
922 throw (IllegalArgumentException
)
924 rOldValue
= m_props
[nHandle
];
928 case STATEMENT_CURSOR_NAME
:
931 bRet
= ( rValue
>>= val
);
932 rConvertedValue
= makeAny( val
);
935 case STATEMENT_ESCAPE_PROCESSING
:
938 bRet
= ( rValue
>>= val
);
939 rConvertedValue
= makeAny( val
);
942 case STATEMENT_FETCH_DIRECTION
:
943 case STATEMENT_FETCH_SIZE
:
944 case STATEMENT_MAX_FIELD_SIZE
:
945 case STATEMENT_MAX_ROWS
:
946 case STATEMENT_QUERY_TIME_OUT
:
947 case STATEMENT_RESULT_SET_CONCURRENCY
:
948 case STATEMENT_RESULT_SET_TYPE
:
951 bRet
= ( rValue
>>= val
);
952 rConvertedValue
= makeAny( val
);
957 OUStringBuffer
buf(128);
958 buf
.appendAscii( "pq_statement: Invalid property handle (" );
959 buf
.append( nHandle
);
960 buf
.appendAscii( ")" );
961 throw IllegalArgumentException( buf
.makeStringAndClear(), *this, 2 );
968 void Statement::setFastPropertyValue_NoBroadcast(
969 sal_Int32 nHandle
,const Any
& rValue
) throw (Exception
, std::exception
)
971 m_props
[nHandle
] = rValue
;
974 void Statement::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
976 rValue
= m_props
[nHandle
];
979 Reference
< XPropertySetInfo
> Statement::getPropertySetInfo()
980 throw(RuntimeException
, std::exception
)
982 return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
986 Reference
< XResultSet
> Statement::getResultSet( )
987 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
989 return Reference
< XResultSet
> ( m_lastResultset
, com::sun::star::uno::UNO_QUERY
);
992 sal_Int32
Statement::getUpdateCount( )
993 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
995 return m_multipleResultUpdateCount
;
998 sal_Bool
Statement::getMoreResults( )
999 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
1006 void Statement::disposing()
1011 Reference
< XResultSet
> Statement::getGeneratedValues( )
1012 throw (SQLException
, RuntimeException
, std::exception
)
1014 osl::MutexGuard
guard( m_refMutex
->mutex
);
1015 return getGeneratedValuesFromLastInsert(
1016 m_pSettings
, m_connection
, m_lastOidInserted
, m_lastTableInserted
, m_lastQuery
);
1021 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */