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: 200? by Sun Microsystems, Inc.
27 * Contributor(s): Joerg Budischewski
29 * All parts contributed on or after August 2011:
31 * This Source Code Form is subject to the terms of the Mozilla Public
32 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
35 ************************************************************************/
37 #include <sal/log.hxx>
38 #include <rtl/ref.hxx>
39 #include <rtl/ustrbuf.hxx>
41 #include <cppuhelper/queryinterface.hxx>
42 #include <cppuhelper/typeprovider.hxx>
43 #include <com/sun/star/sdbc/SQLException.hpp>
44 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
46 #include "pq_updateableresultset.hxx"
47 #include "pq_resultsetmetadata.hxx"
48 #include "pq_tools.hxx"
49 #include "pq_statics.hxx"
53 #include <connectivity/dbconversion.hxx>
55 using osl::MutexGuard
;
58 using com::sun::star::uno::Reference
;
59 using com::sun::star::uno::Sequence
;
60 using com::sun::star::uno::UNO_QUERY
;
61 using com::sun::star::uno::Any
;
62 using com::sun::star::uno::Type
;
64 using com::sun::star::sdbc::XGeneratedResultSet
;
65 using com::sun::star::sdbc::XResultSetMetaDataSupplier
;
66 using com::sun::star::sdbc::SQLException
;
67 using com::sun::star::sdbc::XResultSet
;
68 using com::sun::star::sdbc::XCloseable
;
69 using com::sun::star::sdbc::XColumnLocate
;
70 using com::sun::star::sdbc::XResultSetUpdate
;
71 using com::sun::star::sdbc::XRowUpdate
;
72 using com::sun::star::sdbc::XRow
;
73 using com::sun::star::sdbc::XStatement
;
75 using com::sun::star::beans::XFastPropertySet
;
76 using com::sun::star::beans::XPropertySet
;
77 using com::sun::star::beans::XMultiPropertySet
;
79 using namespace dbtools
;
81 namespace pq_sdbc_driver
85 css::uno::Reference
< css::sdbc::XCloseable
> UpdateableResultSet::createFromPGResultSet(
86 const ::rtl::Reference
< comphelper::RefCountedMutex
> & mutex
,
87 const css::uno::Reference
< css::uno::XInterface
> &owner
,
88 ConnectionSettings
**ppSettings
,
90 const OUString
&schema
,
91 const OUString
&table
,
92 std::vector
< OUString
> && primaryKey
)
94 sal_Int32 columnCount
= PQnfields( result
);
95 sal_Int32 rowCount
= PQntuples( result
);
96 std::vector
< OUString
> columnNames( columnCount
);
97 for( int i
= 0 ; i
< columnCount
; i
++ )
99 char * name
= PQfname( result
, i
);
100 columnNames
[i
] = OUString( name
, strlen(name
), ConnectionSettings::encoding
);
102 std::vector
< std::vector
< Any
> > data( rowCount
);
104 // copy all the data into unicode strings (also binaries, as we yet
105 // don't know, what a binary is and what not!)
106 for( int row
= 0 ; row
< rowCount
; row
++ )
108 std::vector
< Any
> aRow( columnCount
);
109 for( int col
= 0 ; col
< columnCount
; col
++ )
111 if( ! PQgetisnull( result
, row
, col
) )
113 char * val
= PQgetvalue( result
, row
, col
);
116 OUString( val
, strlen( val
), ConnectionSettings::encoding
);
119 data
[row
] = std::move(aRow
);
122 rtl::Reference
<UpdateableResultSet
> pRS
= new UpdateableResultSet(
123 mutex
, owner
, std::move(columnNames
), std::move(data
), ppSettings
, schema
, table
, std::move(primaryKey
) );
125 pRS
->m_meta
= new ResultSetMetaData( mutex
, pRS
,nullptr, ppSettings
, result
, schema
, table
);
127 PQclear( result
); // we don't need it anymore
132 css::uno::Any
UpdateableResultSet::queryInterface(
133 const css::uno::Type
& reqType
)
135 Any ret
= SequenceResultSet::queryInterface( reqType
);
136 if( ! ret
.hasValue() )
137 ret
= ::cppu::queryInterface(
139 static_cast< XResultSetUpdate
* > ( this ),
140 static_cast< XRowUpdate
* > ( this ) );
145 css::uno::Sequence
< css::uno::Type
> UpdateableResultSet::getTypes()
147 static cppu::OTypeCollection
collection(
148 cppu::UnoType
<XResultSetUpdate
>::get(),
149 cppu::UnoType
<XRowUpdate
>::get(),
150 SequenceResultSet::getTypes());
152 return collection
.getTypes();
156 css::uno::Sequence
< sal_Int8
> UpdateableResultSet::getImplementationId()
158 return css::uno::Sequence
<sal_Int8
>();
161 OUString
UpdateableResultSet::buildWhereClause()
164 if( !m_primaryKey
.empty() )
166 OUStringBuffer
buf( 128 );
167 buf
.append( " WHERE " );
168 for( size_t i
= 0 ; i
< m_primaryKey
.size() ; i
++ )
171 buf
.append( " AND " );
172 sal_Int32 index
= findColumn( m_primaryKey
[i
] );
173 bufferQuoteIdentifier( buf
, m_primaryKey
[i
], *m_ppSettings
);
175 bufferQuoteConstant( buf
, getString( index
), *m_ppSettings
);
177 ret
= buf
.makeStringAndClear();
183 void UpdateableResultSet::insertRow( )
185 MutexGuard
guard( m_xMutex
->GetMutex() );
186 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called");
190 u
"pq_resultset.insertRow: moveToInsertRow has not been called !"_ustr
,
191 *this, OUString(), 1, Any() );
193 OUStringBuffer
buf( 128 );
194 buf
.append( "INSERT INTO " );
195 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
199 for( UpdateableFieldVector::size_type i
= 0 ; i
< m_updateableField
.size() ; i
++ )
201 if( m_updateableField
[i
].isTouched
)
206 bufferQuoteIdentifier( buf
, m_columnNames
[i
], *m_ppSettings
);
209 buf
.append( " ) VALUES ( " );
212 for(const UpdateableField
& i
: m_updateableField
)
219 bufferQuoteAnyConstant( buf
, i
.value
, *m_ppSettings
);
222 // m_updateableField[i].value >>= val;
223 // buf.append( val );
224 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
230 Reference
< XStatement
> stmt
=
231 extractConnectionFromStatement(m_owner
)->createStatement();
232 DisposeGuard
dispGuard( stmt
);
233 stmt
->executeUpdate( buf
.makeStringAndClear() );
235 // reflect the changes !
237 m_data
.resize( m_rowCount
);
238 m_data
[m_rowCount
-1] = std::vector
< Any
> ( m_fieldCount
);
239 Reference
< XGeneratedResultSet
> result( stmt
, UNO_QUERY
);
242 Reference
< XResultSet
> rs
= result
->getGeneratedValues();
243 if( rs
.is() && rs
->next() )
245 Reference
< XColumnLocate
> columnLocate( rs
, UNO_QUERY
);
246 Reference
< XRow
> xRow ( rs
, UNO_QUERY
);
247 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
249 int field
= columnLocate
->findColumn( m_columnNames
[i
] );
252 m_data
[m_rowCount
-1][i
] <<= xRow
->getString( field
);
253 // printf( "adding %s %s\n" ,
254 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
255 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
262 // do the best we can ( DEFAULT and AUTO increment values fail ! )
263 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
265 if( m_updateableField
[i
].isTouched
)
266 m_data
[m_rowCount
-1][i
] = m_updateableField
[i
].value
;
272 m_updateableField
= UpdateableFieldVector();
275 void UpdateableResultSet::updateRow( )
277 MutexGuard
guard( m_xMutex
->GetMutex() );
278 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called");
282 u
"pq_resultset.updateRow: moveToCurrentRow has not been called !"_ustr
,
283 *this, OUString(), 1, Any() );
285 OUStringBuffer
buf( 128 );
286 buf
.append( "UPDATE " );
287 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
288 buf
.append( "SET " );
291 for( UpdateableFieldVector::size_type i
= 0; i
< m_updateableField
.size() ; i
++ )
293 if( m_updateableField
[i
].isTouched
)
299 buf
.append( m_columnNames
[i
]
301 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
, *m_ppSettings
);
303 // m_updateableField[i].value >>= val;
304 // bufferQuoteConstant( buf, val ):
305 // buf.append( val );
308 buf
.append( buildWhereClause() );
310 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
311 DisposeGuard
dispGuard( stmt
);
312 stmt
->executeUpdate( buf
.makeStringAndClear() );
314 // reflect the changes !
315 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
317 if( m_updateableField
[i
].isTouched
)
318 m_data
[m_row
][i
] = m_updateableField
[i
].value
;
320 m_updateableField
= UpdateableFieldVector();
323 void UpdateableResultSet::deleteRow( )
325 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called");
329 u
"pq_resultset.deleteRow: deleteRow cannot be called when on insert row !"_ustr
,
330 *this, OUString(), 1, Any() );
332 if( m_row
< 0 || m_row
>= m_rowCount
)
335 "deleteRow cannot be called on invalid row ("
336 + OUString::number(m_row
) + ")",
337 *this, OUString(), 0, Any() );
340 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
341 DisposeGuard
dispGuard( stmt
);
342 OUStringBuffer
buf( 128 );
343 buf
.append( "DELETE FROM " );
344 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
346 + buildWhereClause() );
348 stmt
->executeUpdate( buf
.makeStringAndClear() );
350 // reflect the changes !
351 for( int i
= m_row
+ 1; i
< m_row
; i
++ )
353 m_data
[i
-1] = m_data
[i
];
356 m_data
.resize( m_rowCount
);
359 void UpdateableResultSet::cancelRowUpdates( )
361 MutexGuard
guard( m_xMutex
->GetMutex() );
362 m_updateableField
= UpdateableFieldVector();
365 void UpdateableResultSet::moveToInsertRow( )
370 void UpdateableResultSet::moveToCurrentRow( )
375 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex
)
377 checkColumnIndex( columnIndex
);
378 if( m_updateableField
.empty() )
379 m_updateableField
= UpdateableFieldVector( m_fieldCount
);
380 m_updateableField
[columnIndex
-1].isTouched
= true;
383 void UpdateableResultSet::updateNull( sal_Int32 columnIndex
)
385 MutexGuard
guard( m_xMutex
->GetMutex() );
387 checkUpdate( columnIndex
);
388 m_updateableField
[columnIndex
-1].value
= Any();
391 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex
, sal_Bool x
)
393 MutexGuard
guard( m_xMutex
->GetMutex() );
395 checkUpdate( columnIndex
);
397 Statics
&st
= getStatics();
398 m_updateableField
[columnIndex
-1].value
<<= ( x
? st
.TRUE
: st
.FALSE
);
402 void UpdateableResultSet::updateByte( sal_Int32 columnIndex
, sal_Int8 x
)
404 updateInt(columnIndex
,x
);
407 void UpdateableResultSet::updateShort( sal_Int32 columnIndex
, sal_Int16 x
)
409 updateInt( columnIndex
, x
);
412 void UpdateableResultSet::updateInt( sal_Int32 columnIndex
, sal_Int32 x
)
414 updateLong( columnIndex
, x
);
415 // MutexGuard guard( m_xMutex->GetMutex() );
417 // checkUpdate( columnIndex );
419 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
423 void UpdateableResultSet::updateLong( sal_Int32 columnIndex
, sal_Int64 x
)
425 MutexGuard
guard( m_xMutex
->GetMutex() );
427 checkUpdate( columnIndex
);
429 // OStringBuffer buf( 20 );
430 // buf.append( "'" );
431 // buf.append( (sal_Int64) x );
432 // buf.append( "'" );
433 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
436 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex
, float x
)
439 MutexGuard
guard( m_xMutex
->GetMutex() );
441 checkUpdate( columnIndex
);
443 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
446 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex
, double x
)
448 MutexGuard
guard( m_xMutex
->GetMutex() );
450 checkUpdate( columnIndex
);
452 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
455 void UpdateableResultSet::updateString( sal_Int32 columnIndex
, const OUString
& x
)
457 MutexGuard
guard( m_xMutex
->GetMutex() );
459 checkUpdate( columnIndex
);
461 m_updateableField
[columnIndex
-1].value
<<= x
;
464 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex
, const css::uno::Sequence
< sal_Int8
>& x
)
466 MutexGuard
guard( m_xMutex
->GetMutex() );
468 checkUpdate( columnIndex
);
471 unsigned char * escapedString
=
472 PQescapeBytea( reinterpret_cast<unsigned char const *>(x
.getConstArray()), x
.getLength(), &len
);
473 if( ! escapedString
)
476 u
"pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string"_ustr
,
477 *this, OUString(), 1, Any() );
479 // buf.append( (const char *)escapedString, len -1 );
481 m_updateableField
[columnIndex
-1].value
<<=
482 OUString( reinterpret_cast<char*>(escapedString
), len
, RTL_TEXTENCODING_ASCII_US
);
483 PQfreemem( escapedString
);
486 void UpdateableResultSet::updateDate( sal_Int32 columnIndex
, const css::util::Date
& x
)
488 updateString( columnIndex
, DBTypeConversion::toDateString( x
) );
491 void UpdateableResultSet::updateTime( sal_Int32 columnIndex
, const css::util::Time
& x
)
493 updateString( columnIndex
, DBTypeConversion::toTimeString( x
) );
496 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex
, const css::util::DateTime
& x
)
498 updateString( columnIndex
, DBTypeConversion::toDateTimeString( x
) );
501 void UpdateableResultSet::updateBinaryStream( sal_Int32
/* columnIndex */, const css::uno::Reference
< css::io::XInputStream
>& /* x */, sal_Int32
/* length */ )
505 void UpdateableResultSet::updateCharacterStream( sal_Int32
/* columnIndex */, const css::uno::Reference
< css::io::XInputStream
>& /* x */, sal_Int32
/* length */ )
509 void UpdateableResultSet::updateObject( sal_Int32
/* columnIndex */, const css::uno::Any
& /* x */ )
513 void UpdateableResultSet::updateNumericObject( sal_Int32
/* columnIndex */, const css::uno::Any
& /* x */, sal_Int32
/* scale */ )
518 Sequence
< Type
> UpdateableResultSet::getStaticTypes( bool updateable
)
522 cppu::OTypeCollection
collection(
523 cppu::UnoType
<XResultSetUpdate
>::get(),
524 cppu::UnoType
<XRowUpdate
>::get(),
525 // cppu::UnoType<css::sdbcx::XRowLocate>::get(),
526 getStaticTypes( false /* updateable */ ) );
527 return collection
.getTypes();
531 cppu::OTypeCollection
collection(
532 cppu::UnoType
<XResultSet
>::get(),
533 cppu::UnoType
<XResultSetMetaDataSupplier
>::get(),
534 cppu::UnoType
<XRow
>::get(),
535 cppu::UnoType
<XColumnLocate
>::get(),
536 cppu::UnoType
<XCloseable
>::get(),
537 cppu::UnoType
<XPropertySet
>::get(),
538 cppu::UnoType
<XFastPropertySet
>::get(),
539 cppu::UnoType
<XMultiPropertySet
>::get(),
540 cppu::UnoType
<css::lang::XComponent
>::get(), // OComponentHelper
541 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
542 cppu::UnoType
<css::uno::XAggregation
>::get(),
543 cppu::UnoType
<css::uno::XWeak
>::get());
544 return collection
.getTypes();
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */