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>
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::makeAny
;
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
;
63 using com::sun::star::uno::RuntimeException
;
65 using com::sun::star::sdbc::XGeneratedResultSet
;
66 using com::sun::star::sdbc::XResultSetMetaDataSupplier
;
67 using com::sun::star::sdbc::SQLException
;
68 using com::sun::star::sdbc::XResultSet
;
69 using com::sun::star::sdbc::XCloseable
;
70 using com::sun::star::sdbc::XColumnLocate
;
71 using com::sun::star::sdbc::XResultSetUpdate
;
72 using com::sun::star::sdbc::XRowUpdate
;
73 using com::sun::star::sdbc::XRow
;
74 using com::sun::star::sdbc::XStatement
;
76 using com::sun::star::beans::XFastPropertySet
;
77 using com::sun::star::beans::XPropertySet
;
78 using com::sun::star::beans::XMultiPropertySet
;
80 using namespace dbtools
;
82 namespace pq_sdbc_driver
86 com::sun::star::uno::Reference
< com::sun::star::sdbc::XCloseable
> UpdateableResultSet::createFromPGResultSet(
87 const ::rtl::Reference
< RefCountedMutex
> & mutex
,
88 const com::sun::star::uno::Reference
< com::sun::star::uno::XInterface
> &owner
,
89 ConnectionSettings
**ppSettings
,
91 const OUString
&schema
,
92 const OUString
&table
,
93 const com::sun::star::uno::Sequence
< OUString
> &primaryKey
)
95 ConnectionSettings
*pSettings
= *ppSettings
;
96 sal_Int32 columnCount
= PQnfields( result
);
97 sal_Int32 rowCount
= PQntuples( result
);
98 Sequence
< OUString
> columnNames( columnCount
);
99 for( int i
= 0 ; i
< columnCount
; i
++ )
101 char * name
= PQfname( result
, i
);
102 columnNames
[i
] = OUString( name
, strlen(name
), pSettings
->encoding
);
104 Sequence
< Sequence
< Any
> > data( rowCount
);
106 // copy all the data into unicode strings (also binaries, as we yet
107 // don't know, what a binary is and what not!)
108 for( int row
= 0 ; row
< rowCount
; row
++ )
110 Sequence
< Any
> aRow( columnCount
);
111 for( int col
= 0 ; col
< columnCount
; col
++ )
113 if( ! PQgetisnull( result
, row
, col
) )
115 char * val
= PQgetvalue( result
, row
, col
);
118 OUString( val
, strlen( val
) , (*ppSettings
)->encoding
) );
124 UpdateableResultSet
*pRS
= new UpdateableResultSet(
125 mutex
, owner
, columnNames
, data
, ppSettings
, schema
, table
, primaryKey
);
127 Reference
<XCloseable
> ret
= pRS
; // give it an refcount
129 pRS
->m_meta
= new ResultSetMetaData( mutex
, pRS
,0, ppSettings
, result
, schema
, table
);
131 PQclear( result
); // we don't need it anymore
136 com::sun::star::uno::Any
UpdateableResultSet::queryInterface(
137 const com::sun::star::uno::Type
& reqType
)
138 throw (com::sun::star::uno::RuntimeException
, std::exception
)
140 Any ret
= SequenceResultSet::queryInterface( reqType
);
141 if( ! ret
.hasValue() )
142 ret
= ::cppu::queryInterface(
144 static_cast< XResultSetUpdate
* > ( this ),
145 static_cast< XRowUpdate
* > ( this ) );
150 com::sun::star::uno::Sequence
< com::sun::star::uno::Type
> UpdateableResultSet::getTypes()
151 throw( com::sun::star::uno::RuntimeException
, std::exception
)
153 static cppu::OTypeCollection
*pCollection
;
156 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
159 static cppu::OTypeCollection
collection(
160 getCppuType( (Reference
< XResultSetUpdate
> *) 0 ),
161 getCppuType( (Reference
< XRowUpdate
> *) 0 ),
162 SequenceResultSet::getTypes());
163 pCollection
= &collection
;
166 return pCollection
->getTypes();
170 com::sun::star::uno::Sequence
< sal_Int8
> UpdateableResultSet::getImplementationId()
171 throw( com::sun::star::uno::RuntimeException
, std::exception
)
173 return css::uno::Sequence
<sal_Int8
>();
176 OUString
UpdateableResultSet::buildWhereClause()
179 if( m_primaryKey
.getLength() )
181 OUStringBuffer
buf( 128 );
182 buf
.append( " WHERE " );
183 for( int i
= 0 ; i
< m_primaryKey
.getLength() ; i
++ )
186 buf
.append( " AND " );
187 sal_Int32 index
= findColumn( m_primaryKey
[i
] );
188 bufferQuoteIdentifier( buf
, m_primaryKey
[i
], *m_ppSettings
);
190 bufferQuoteConstant( buf
, getString( index
), *m_ppSettings
);
192 ret
= buf
.makeStringAndClear();
198 void UpdateableResultSet::insertRow( ) throw (SQLException
, RuntimeException
, std::exception
)
200 MutexGuard
guard( m_refMutex
->mutex
);
201 if( isLog( *m_ppSettings
, LogLevel::INFO
) )
203 log( *m_ppSettings
, LogLevel::INFO
,"UpdateableResultSet::insertRow got called" );
207 "pq_resultset.insertRow: moveToInsertRow has not been called !",
208 *this, OUString(), 1, Any() );
210 OUStringBuffer
buf( 128 );
211 buf
.append( "INSERT INTO " );
212 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
216 for( UpdateableFieldVector::size_type i
= 0 ; i
< m_updateableField
.size() ; i
++ )
218 if( m_updateableField
[i
].isTouched
)
223 bufferQuoteIdentifier( buf
, m_columnNames
[i
], *m_ppSettings
);
226 buf
.append( " ) VALUES ( " );
229 for( UpdateableFieldVector::size_type i
= 0 ; i
< m_updateableField
.size() ; i
++ )
231 if( m_updateableField
[i
].isTouched
)
236 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
, *m_ppSettings
);
239 // m_updateableField[i].value >>= val;
240 // buf.append( val );
241 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
247 Reference
< XStatement
> stmt
=
248 extractConnectionFromStatement(m_owner
)->createStatement();
249 DisposeGuard
dispGuard( stmt
);
250 stmt
->executeUpdate( buf
.makeStringAndClear() );
252 // reflect the changes !
254 m_data
.realloc( m_rowCount
);
255 m_data
[m_rowCount
-1] = Sequence
< Any
> ( m_fieldCount
);
256 Reference
< XGeneratedResultSet
> result( stmt
, UNO_QUERY
);
259 Reference
< XResultSet
> rs
= result
->getGeneratedValues();
260 if( rs
.is() && rs
->next() )
262 Reference
< XColumnLocate
> columnLocate( rs
, UNO_QUERY
);
263 Reference
< XRow
> xRow ( rs
, UNO_QUERY
);
264 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
266 int field
= columnLocate
->findColumn( m_columnNames
[i
] );
269 m_data
[m_rowCount
-1][i
] <<= xRow
->getString( field
);
270 // printf( "adding %s %s\n" ,
271 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
272 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
279 // do the best we can ( DEFAULT and AUTO increment values fail ! )
280 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
282 if( m_updateableField
[i
].isTouched
)
283 m_data
[m_rowCount
-1][i
] = m_updateableField
[i
].value
;
289 m_updateableField
= UpdateableFieldVector();
292 void UpdateableResultSet::updateRow( ) throw (SQLException
, RuntimeException
, std::exception
)
294 MutexGuard
guard( m_refMutex
->mutex
);
295 if( isLog( *m_ppSettings
, LogLevel::INFO
) )
297 log( *m_ppSettings
, LogLevel::INFO
,"UpdateableResultSet::updateRow got called" );
301 "pq_resultset.updateRow: moveToCurrentRow has not been called !",
302 *this, OUString(), 1, Any() );
304 OUStringBuffer
buf( 128 );
305 buf
.append( "UPDATE " );
306 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
307 buf
.append( "SET " );
310 for( UpdateableFieldVector::size_type i
= 0; i
< m_updateableField
.size() ; i
++ )
312 if( m_updateableField
[i
].isTouched
)
318 buf
.append( m_columnNames
[i
] );
320 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
, *m_ppSettings
);
322 // m_updateableField[i].value >>= val;
323 // bufferQuoteConstant( buf, val ):
324 // buf.append( val );
327 buf
.append( buildWhereClause() );
329 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
330 DisposeGuard
dispGuard( stmt
);
331 stmt
->executeUpdate( buf
.makeStringAndClear() );
333 // reflect the changes !
334 for( int i
= 0 ; i
< m_fieldCount
; i
++ )
336 if( m_updateableField
[i
].isTouched
)
337 m_data
[m_row
][i
] = m_updateableField
[i
].value
;
339 m_updateableField
= UpdateableFieldVector();
342 void UpdateableResultSet::deleteRow( ) throw (SQLException
, RuntimeException
, std::exception
)
344 if( isLog( *m_ppSettings
, LogLevel::INFO
) )
346 log( *m_ppSettings
, LogLevel::INFO
,"UpdateableResultSet::deleteRow got called" );
350 "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
351 *this, OUString(), 1, Any() );
353 if( m_row
< 0 || m_row
>= m_rowCount
)
355 OUStringBuffer
buf( 128 );
356 buf
.appendAscii( "deleteRow cannot be called on invalid row (" );
358 buf
.appendAscii( ")" );
359 throw SQLException( buf
.makeStringAndClear() , *this, OUString(), 0, Any() );
362 Reference
< XStatement
> stmt
= extractConnectionFromStatement(m_owner
)->createStatement();
363 DisposeGuard
dispGuard( stmt
);
364 OUStringBuffer
buf( 128 );
365 buf
.appendAscii( "DELETE FROM " );
366 bufferQuoteQualifiedIdentifier( buf
, m_schema
, m_table
, *m_ppSettings
);
367 buf
.appendAscii( " " );
368 buf
.append( buildWhereClause() );
370 stmt
->executeUpdate( buf
.makeStringAndClear() );
372 // reflect the changes !
373 for( int i
= m_row
+ 1; i
< m_row
; i
++ )
375 m_data
[i
-1] = m_data
[i
];
378 m_data
.realloc( m_rowCount
);
381 void UpdateableResultSet::cancelRowUpdates( ) throw (SQLException
, RuntimeException
, std::exception
)
383 MutexGuard
guard( m_refMutex
->mutex
);
384 m_updateableField
= UpdateableFieldVector();
387 void UpdateableResultSet::moveToInsertRow( ) throw (SQLException
, RuntimeException
, std::exception
)
392 void UpdateableResultSet::moveToCurrentRow( ) throw (SQLException
, RuntimeException
, std::exception
)
397 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex
)
399 checkColumnIndex( columnIndex
);
400 if( m_updateableField
.empty() )
401 m_updateableField
= UpdateableFieldVector( m_fieldCount
);
402 m_updateableField
[columnIndex
-1].isTouched
= true;
405 void UpdateableResultSet::updateNull( sal_Int32 columnIndex
) throw (SQLException
, RuntimeException
, std::exception
)
407 MutexGuard
guard( m_refMutex
->mutex
);
409 checkUpdate( columnIndex
);
410 m_updateableField
[columnIndex
-1].value
= Any();
413 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex
, sal_Bool x
) throw (SQLException
, RuntimeException
, std::exception
)
415 MutexGuard
guard( m_refMutex
->mutex
);
417 checkUpdate( columnIndex
);
419 Statics
&st
= getStatics();
420 m_updateableField
[columnIndex
-1].value
<<= ( x
? st
.TRUE
: st
.FALSE
);
424 void UpdateableResultSet::updateByte( sal_Int32 columnIndex
, sal_Int8 x
) throw (SQLException
, RuntimeException
, std::exception
)
426 updateInt(columnIndex
,x
);
429 void UpdateableResultSet::updateShort( sal_Int32 columnIndex
, sal_Int16 x
) throw (SQLException
, RuntimeException
, std::exception
)
431 updateInt( columnIndex
, x
);
434 void UpdateableResultSet::updateInt( sal_Int32 columnIndex
, sal_Int32 x
) throw (SQLException
, RuntimeException
, std::exception
)
436 updateLong( columnIndex
, x
);
437 // MutexGuard guard( m_refMutex->mutex );
439 // checkUpdate( columnIndex );
441 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
445 void UpdateableResultSet::updateLong( sal_Int32 columnIndex
, sal_Int64 x
) throw (SQLException
, RuntimeException
, std::exception
)
447 MutexGuard
guard( m_refMutex
->mutex
);
449 checkUpdate( columnIndex
);
451 // OStringBuffer buf( 20 );
452 // buf.append( "'" );
453 // buf.append( (sal_Int64) x );
454 // buf.append( "'" );
455 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
458 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex
, float x
) throw (SQLException
, RuntimeException
, std::exception
)
461 MutexGuard
guard( m_refMutex
->mutex
);
463 checkUpdate( columnIndex
);
465 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
468 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex
, double x
) throw (SQLException
, RuntimeException
, std::exception
)
470 MutexGuard
guard( m_refMutex
->mutex
);
472 checkUpdate( columnIndex
);
474 m_updateableField
[columnIndex
-1].value
<<= OUString::number( x
);
477 void UpdateableResultSet::updateString( sal_Int32 columnIndex
, const OUString
& x
) throw (SQLException
, RuntimeException
, std::exception
)
479 MutexGuard
guard( m_refMutex
->mutex
);
481 checkUpdate( columnIndex
);
483 m_updateableField
[columnIndex
-1].value
<<= x
;
486 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex
, const ::com::sun::star::uno::Sequence
< sal_Int8
>& x
) throw (SQLException
, RuntimeException
, std::exception
)
488 MutexGuard
guard( m_refMutex
->mutex
);
490 checkUpdate( columnIndex
);
493 unsigned char * escapedString
=
494 PQescapeBytea( (unsigned char *)x
.getConstArray(), x
.getLength(), &len
);
495 if( ! escapedString
)
498 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
499 *this, OUString(), 1, Any() );
501 // buf.append( (const sal_Char *)escapedString, len -1 );
503 m_updateableField
[columnIndex
-1].value
<<=
504 OUString( (sal_Char
*) escapedString
, len
, RTL_TEXTENCODING_ASCII_US
);
505 free( escapedString
);
508 void UpdateableResultSet::updateDate( sal_Int32 columnIndex
, const ::com::sun::star::util::Date
& x
) throw (SQLException
, RuntimeException
, std::exception
)
510 updateString( columnIndex
, DBTypeConversion::toDateString( x
) );
513 void UpdateableResultSet::updateTime( sal_Int32 columnIndex
, const ::com::sun::star::util::Time
& x
) throw (SQLException
, RuntimeException
, std::exception
)
515 updateString( columnIndex
, DBTypeConversion::toTimeString( x
) );
518 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex
, const ::com::sun::star::util::DateTime
& x
) throw (SQLException
, RuntimeException
, std::exception
)
520 updateString( columnIndex
, DBTypeConversion::toDateTimeString( x
) );
523 void UpdateableResultSet::updateBinaryStream( sal_Int32
/* columnIndex */, const ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
>& /* x */, sal_Int32
/* length */ ) throw (SQLException
, RuntimeException
, std::exception
)
527 void UpdateableResultSet::updateCharacterStream( sal_Int32
/* columnIndex */, const ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
>& /* x */, sal_Int32
/* length */ ) throw (SQLException
, RuntimeException
, std::exception
)
531 void UpdateableResultSet::updateObject( sal_Int32
/* columnIndex */, const ::com::sun::star::uno::Any
& /* x */ ) throw (SQLException
, RuntimeException
, std::exception
)
535 void UpdateableResultSet::updateNumericObject( sal_Int32
/* columnIndex */, const ::com::sun::star::uno::Any
& /* x */, sal_Int32
/* scale */ ) throw (SQLException
, RuntimeException
, std::exception
)
540 ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XResultSetMetaData
> UpdateableResultSet::getMetaData( )
541 throw (::com::sun::star::sdbc::SQLException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
546 Sequence
< Type
> UpdateableResultSet::getStaticTypes( bool updateable
)
547 throw( com::sun::star::uno::RuntimeException
)
551 cppu::OTypeCollection
collection(
552 getCppuType( (Reference
< XResultSetUpdate
> *) 0 ),
553 getCppuType( (Reference
< XRowUpdate
> *) 0 ),
554 // getCppuType( (Reference< com::sun::star::sdbcx::XRowLocate > *) 0 ),
555 getStaticTypes( false /* updateable */ ) );
556 return collection
.getTypes();
560 cppu::OTypeCollection
collection(
561 getCppuType( (Reference
< XResultSet
> *) 0 ),
562 getCppuType( (Reference
< XResultSetMetaDataSupplier
> *) 0 ),
563 getCppuType( (Reference
< XRow
> *) 0 ),
564 getCppuType( (Reference
< XColumnLocate
> *) 0 ),
565 getCppuType( (Reference
< XCloseable
> *) 0 ),
566 getCppuType( (Reference
< XPropertySet
>*) 0 ),
567 getCppuType( (Reference
< XFastPropertySet
> *) 0 ),
568 getCppuType( (Reference
< XMultiPropertySet
> *) 0 ),
569 getCppuType( (const Reference
< com::sun::star::lang::XComponent
> *)0 ), // OComponentHelper
570 getCppuType( (const Reference
< com::sun::star::lang::XTypeProvider
> *)0 ),
571 getCppuType( (const Reference
< com::sun::star::uno::XAggregation
> *)0 ),
572 getCppuType( (const Reference
< com::sun::star::uno::XWeak
> *)0 ) );
573 return collection
.getTypes();
579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */