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 <rtl/ustrbuf.hxx>
38 #include <rtl/strbuf.hxx>
40 #include <cppuhelper/queryinterface.hxx>
41 #include <cppuhelper/typeprovider.hxx>
42 #include <com/sun/star/sdbc/SQLException.hpp>
43 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
45 #include "pq_updateableresultset.hxx"
46 #include "pq_resultsetmetadata.hxx"
47 #include "pq_tools.hxx"
48 #include "pq_statics.hxx"
52 #include <connectivity/dbconversion.hxx>
54 using osl::MutexGuard
;
57 using com::sun::star::uno::Reference
;
58 using com::sun::star::uno::Sequence
;
59 using com::sun::star::uno::UNO_QUERY
;
60 using com::sun::star::uno::Any
;
61 using com::sun::star::uno::Type
;
63 using com::sun::star::sdbc::XGeneratedResultSet
;
64 using com::sun::star::sdbc::XResultSetMetaDataSupplier
;
65 using com::sun::star::sdbc::SQLException
;
66 using com::sun::star::sdbc::XResultSet
;
67 using com::sun::star::sdbc::XCloseable
;
68 using com::sun::star::sdbc::XColumnLocate
;
69 using com::sun::star::sdbc::XResultSetUpdate
;
70 using com::sun::star::sdbc::XRowUpdate
;
71 using com::sun::star::sdbc::XRow
;
72 using com::sun::star::sdbc::XStatement
;
74 using com::sun::star::beans::XFastPropertySet
;
75 using com::sun::star::beans::XPropertySet
;
76 using com::sun::star::beans::XMultiPropertySet
;
78 using namespace dbtools
;
80 namespace pq_sdbc_driver
84 css::uno::Reference
< css::sdbc::XCloseable
> UpdateableResultSet::createFromPGResultSet(
85 const ::rtl::Reference
< comphelper::RefCountedMutex
> & mutex
,
86 const css::uno::Reference
< css::uno::XInterface
> &owner
,
87 ConnectionSettings
**ppSettings
,
89 const OUString
&schema
,
90 const OUString
&table
,
91 const std::vector
< OUString
> &primaryKey
)
93 sal_Int32 columnCount
= PQnfields( result
);
94 sal_Int32 rowCount
= PQntuples( result
);
95 std::vector
< OUString
> columnNames( columnCount
);
96 for( int i
= 0 ; i
< columnCount
; i
++ )
98 char * name
= PQfname( result
, i
);
99 columnNames
[i
] = OUString( name
, strlen(name
), ConnectionSettings::encoding
);
101 std::vector
< std::vector
< Any
> > data( rowCount
);
103 // copy all the data into unicode strings (also binaries, as we yet
104 // don't know, what a binary is and what not!)
105 for( int row
= 0 ; row
< rowCount
; row
++ )
107 std::vector
< Any
> aRow( columnCount
);
108 for( int col
= 0 ; col
< columnCount
; col
++ )
110 if( ! PQgetisnull( result
, row
, col
) )
112 char * val
= PQgetvalue( result
, row
, col
);
115 OUString( val
, strlen( val
), ConnectionSettings::encoding
);
121 UpdateableResultSet
*pRS
= new UpdateableResultSet(
122 mutex
, owner
, columnNames
, data
, ppSettings
, schema
, table
, primaryKey
);
124 Reference
<XCloseable
> ret
= pRS
; // give it a refcount
126 pRS
->m_meta
= new ResultSetMetaData( mutex
, pRS
,nullptr, ppSettings
, result
, schema
, table
);
128 PQclear( result
); // we don't need it anymore
133 css::uno::Any
UpdateableResultSet::queryInterface(
134 const css::uno::Type
& reqType
)
136 Any ret
= SequenceResultSet::queryInterface( reqType
);
137 if( ! ret
.hasValue() )
138 ret
= ::cppu::queryInterface(
140 static_cast< XResultSetUpdate
* > ( this ),
141 static_cast< XRowUpdate
* > ( this ) );
146 css::uno::Sequence
< css::uno::Type
> UpdateableResultSet::getTypes()
148 static cppu::OTypeCollection
collection(
149 cppu::UnoType
<XResultSetUpdate
>::get(),
150 cppu::UnoType
<XRowUpdate
>::get(),
151 SequenceResultSet::getTypes());
153 return collection
.getTypes();
157 css::uno::Sequence
< sal_Int8
> UpdateableResultSet::getImplementationId()
159 return css::uno::Sequence
<sal_Int8
>();
162 OUString
UpdateableResultSet::buildWhereClause()
165 if( !m_primaryKey
.empty() )
167 OUStringBuffer
buf( 128 );
168 buf
.append( " WHERE " );
169 for( size_t i
= 0 ; i
< m_primaryKey
.size() ; i
++ )
172 buf
.append( " AND " );
173 sal_Int32 index
= findColumn( m_primaryKey
[i
] );
174 bufferQuoteIdentifier( buf
, m_primaryKey
[i
], *m_ppSettings
);
176 bufferQuoteConstant( buf
, getString( index
), *m_ppSettings
);
178 ret
= buf
.makeStringAndClear();
184 void UpdateableResultSet::insertRow( )
186 MutexGuard
guard( m_xMutex
->GetMutex() );
187 if (isLog(*m_ppSettings
, LogLevel::Info
))
189 log(*m_ppSettings
, LogLevel::Info
, "UpdateableResultSet::insertRow got called");
193 "pq_resultset.insertRow: moveToInsertRow has not been called !",
194 *this, OUString(), 1, Any() );
196 OUStringBuffer
buf( 128 );
197 buf
.append( "INSERT INTO " );
198 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
202 for( UpdateableFieldVector::size_type i
= 0 ; i
< m_updateableField
.size() ; i
++ )
204 if( m_updateableField
[i
].isTouched
)
209 bufferQuoteIdentifier( buf
, m_columnNames
[i
], *m_ppSettings
);
212 buf
.append( " ) VALUES ( " );
215 for(UpdateableField
& i
: m_updateableField
)
222 bufferQuoteAnyConstant( buf
, i
.value
, *m_ppSettings
);
225 // m_updateableField[i].value >>= val;
226 // buf.append( val );
227 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
233 Reference
< XStatement
> stmt
=
234 extractConnectionFromStatement(m_owner
)->createStatement();
235 DisposeGuard
dispGuard( stmt
);
236 stmt
->executeUpdate( buf
.makeStringAndClear() );
238 // reflect the changes !
240 m_data
.resize( m_rowCount
);
241 m_data
[m_rowCount
-1] = std::vector
< Any
> ( m_fieldCount
);
242 Reference
< XGeneratedResultSet
> result( stmt
, UNO_QUERY
);
245 Reference
< XResultSet
> rs
= result
->getGeneratedValues();
246 if( rs
.is() && rs
->next() )
248 Reference
< XColumnLocate
> columnLocate( rs
, UNO_QUERY
);
249 Reference
< XRow
> xRow ( rs
, UNO_QUERY
);
250 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
252 int field
= columnLocate
->findColumn( m_columnNames
[i
] );
255 m_data
[m_rowCount
-1][i
] <<= xRow
->getString( field
);
256 // printf( "adding %s %s\n" ,
257 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
258 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
265 // do the best we can ( DEFAULT and AUTO increment values fail ! )
266 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
268 if( m_updateableField
[i
].isTouched
)
269 m_data
[m_rowCount
-1][i
] = m_updateableField
[i
].value
;
275 m_updateableField
= UpdateableFieldVector();
278 void UpdateableResultSet::updateRow( )
280 MutexGuard
guard( m_xMutex
->GetMutex() );
281 if (isLog(*m_ppSettings
, LogLevel::Info
))
283 log(*m_ppSettings
, LogLevel::Info
, "UpdateableResultSet::updateRow got called");
287 "pq_resultset.updateRow: moveToCurrentRow has not been called !",
288 *this, OUString(), 1, Any() );
290 OUStringBuffer
buf( 128 );
291 buf
.append( "UPDATE " );
292 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
293 buf
.append( "SET " );
296 for( UpdateableFieldVector::size_type i
= 0; i
< m_updateableField
.size() ; i
++ )
298 if( m_updateableField
[i
].isTouched
)
304 buf
.append( m_columnNames
[i
] );
306 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
, *m_ppSettings
);
308 // m_updateableField[i].value >>= val;
309 // bufferQuoteConstant( buf, val ):
310 // buf.append( val );
313 buf
.append( buildWhereClause() );
315 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
316 DisposeGuard
dispGuard( stmt
);
317 stmt
->executeUpdate( buf
.makeStringAndClear() );
319 // reflect the changes !
320 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
322 if( m_updateableField
[i
].isTouched
)
323 m_data
[m_row
][i
] = m_updateableField
[i
].value
;
325 m_updateableField
= UpdateableFieldVector();
328 void UpdateableResultSet::deleteRow( )
330 if (isLog(*m_ppSettings
, LogLevel::Info
))
332 log(*m_ppSettings
, LogLevel::Info
, "UpdateableResultSet::deleteRow got called");
336 "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
337 *this, OUString(), 1, Any() );
339 if( m_row
< 0 || m_row
>= m_rowCount
)
342 "deleteRow cannot be called on invalid row ("
343 + OUString::number(m_row
) + ")",
344 *this, OUString(), 0, Any() );
347 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
348 DisposeGuard
dispGuard( stmt
);
349 OUStringBuffer
buf( 128 );
350 buf
.append( "DELETE FROM " );
351 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
353 buf
.append( buildWhereClause() );
355 stmt
->executeUpdate( buf
.makeStringAndClear() );
357 // reflect the changes !
358 for( int i
= m_row
+ 1; i
< m_row
; i
++ )
360 m_data
[i
-1] = m_data
[i
];
363 m_data
.resize( m_rowCount
);
366 void UpdateableResultSet::cancelRowUpdates( )
368 MutexGuard
guard( m_xMutex
->GetMutex() );
369 m_updateableField
= UpdateableFieldVector();
372 void UpdateableResultSet::moveToInsertRow( )
377 void UpdateableResultSet::moveToCurrentRow( )
382 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex
)
384 checkColumnIndex( columnIndex
);
385 if( m_updateableField
.empty() )
386 m_updateableField
= UpdateableFieldVector( m_fieldCount
);
387 m_updateableField
[columnIndex
-1].isTouched
= true;
390 void UpdateableResultSet::updateNull( sal_Int32 columnIndex
)
392 MutexGuard
guard( m_xMutex
->GetMutex() );
394 checkUpdate( columnIndex
);
395 m_updateableField
[columnIndex
-1].value
= Any();
398 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex
, sal_Bool x
)
400 MutexGuard
guard( m_xMutex
->GetMutex() );
402 checkUpdate( columnIndex
);
404 Statics
&st
= getStatics();
405 m_updateableField
[columnIndex
-1].value
<<= ( x
? st
.TRUE
: st
.FALSE
);
409 void UpdateableResultSet::updateByte( sal_Int32 columnIndex
, sal_Int8 x
)
411 updateInt(columnIndex
,x
);
414 void UpdateableResultSet::updateShort( sal_Int32 columnIndex
, sal_Int16 x
)
416 updateInt( columnIndex
, x
);
419 void UpdateableResultSet::updateInt( sal_Int32 columnIndex
, sal_Int32 x
)
421 updateLong( columnIndex
, x
);
422 // MutexGuard guard( m_xMutex->GetMutex() );
424 // checkUpdate( columnIndex );
426 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
430 void UpdateableResultSet::updateLong( sal_Int32 columnIndex
, sal_Int64 x
)
432 MutexGuard
guard( m_xMutex
->GetMutex() );
434 checkUpdate( columnIndex
);
436 // OStringBuffer buf( 20 );
437 // buf.append( "'" );
438 // buf.append( (sal_Int64) x );
439 // buf.append( "'" );
440 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
443 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex
, float x
)
446 MutexGuard
guard( m_xMutex
->GetMutex() );
448 checkUpdate( columnIndex
);
450 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
453 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex
, double x
)
455 MutexGuard
guard( m_xMutex
->GetMutex() );
457 checkUpdate( columnIndex
);
459 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
462 void UpdateableResultSet::updateString( sal_Int32 columnIndex
, const OUString
& x
)
464 MutexGuard
guard( m_xMutex
->GetMutex() );
466 checkUpdate( columnIndex
);
468 m_updateableField
[columnIndex
-1].value
<<= x
;
471 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex
, const css::uno::Sequence
< sal_Int8
>& x
)
473 MutexGuard
guard( m_xMutex
->GetMutex() );
475 checkUpdate( columnIndex
);
478 unsigned char * escapedString
=
479 PQescapeBytea( reinterpret_cast<unsigned char const *>(x
.getConstArray()), x
.getLength(), &len
);
480 if( ! escapedString
)
483 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
484 *this, OUString(), 1, Any() );
486 // buf.append( (const sal_Char *)escapedString, len -1 );
488 m_updateableField
[columnIndex
-1].value
<<=
489 OUString( reinterpret_cast<char*>(escapedString
), len
, RTL_TEXTENCODING_ASCII_US
);
490 free( escapedString
);
493 void UpdateableResultSet::updateDate( sal_Int32 columnIndex
, const css::util::Date
& x
)
495 updateString( columnIndex
, DBTypeConversion::toDateString( x
) );
498 void UpdateableResultSet::updateTime( sal_Int32 columnIndex
, const css::util::Time
& x
)
500 updateString( columnIndex
, DBTypeConversion::toTimeString( x
) );
503 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex
, const css::util::DateTime
& x
)
505 updateString( columnIndex
, DBTypeConversion::toDateTimeString( x
) );
508 void UpdateableResultSet::updateBinaryStream( sal_Int32
/* columnIndex */, const css::uno::Reference
< css::io::XInputStream
>& /* x */, sal_Int32
/* length */ )
512 void UpdateableResultSet::updateCharacterStream( sal_Int32
/* columnIndex */, const css::uno::Reference
< css::io::XInputStream
>& /* x */, sal_Int32
/* length */ )
516 void UpdateableResultSet::updateObject( sal_Int32
/* columnIndex */, const css::uno::Any
& /* x */ )
520 void UpdateableResultSet::updateNumericObject( sal_Int32
/* columnIndex */, const css::uno::Any
& /* x */, sal_Int32
/* scale */ )
525 Sequence
< Type
> UpdateableResultSet::getStaticTypes( bool updateable
)
529 cppu::OTypeCollection
collection(
530 cppu::UnoType
<XResultSetUpdate
>::get(),
531 cppu::UnoType
<XRowUpdate
>::get(),
532 // cppu::UnoType<css::sdbcx::XRowLocate>::get(),
533 getStaticTypes( false /* updateable */ ) );
534 return collection
.getTypes();
538 cppu::OTypeCollection
collection(
539 cppu::UnoType
<XResultSet
>::get(),
540 cppu::UnoType
<XResultSetMetaDataSupplier
>::get(),
541 cppu::UnoType
<XRow
>::get(),
542 cppu::UnoType
<XColumnLocate
>::get(),
543 cppu::UnoType
<XCloseable
>::get(),
544 cppu::UnoType
<XPropertySet
>::get(),
545 cppu::UnoType
<XFastPropertySet
>::get(),
546 cppu::UnoType
<XMultiPropertySet
>::get(),
547 cppu::UnoType
<css::lang::XComponent
>::get(), // OComponentHelper
548 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
549 cppu::UnoType
<css::uno::XAggregation
>::get(),
550 cppu::UnoType
<css::uno::XWeak
>::get());
551 return collection
.getTypes();
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */