Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_updateableresultset.cxx
blobac7b755faf900bab01d645e38223c84322e99e2c
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,
18 * MA 02111-1307 USA
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"
50 #include <string.h>
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,
90 PGresult *result,
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 );
117 aRow[col] = makeAny(
118 OUString( val, strlen( val ) , (*ppSettings)->encoding ) );
121 data[row] = aRow;
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
133 return ret;
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(
143 reqType,
144 static_cast< XResultSetUpdate * > ( this ),
145 static_cast< XRowUpdate * > ( this ) );
146 return ret;
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;
154 if( ! pCollection )
156 MutexGuard guard( osl::Mutex::getGlobalMutex() );
157 if( !pCollection )
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()
178 OUString ret;
179 if( m_primaryKey.getLength() )
181 OUStringBuffer buf( 128 );
182 buf.append( " WHERE " );
183 for( int i = 0 ; i < m_primaryKey.getLength() ; i ++ )
185 if( i > 0 )
186 buf.append( " AND " );
187 sal_Int32 index = findColumn( m_primaryKey[i] );
188 bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings );
189 buf.append( " = " );
190 bufferQuoteConstant( buf, getString( index ), *m_ppSettings );
192 ret = buf.makeStringAndClear();
194 return ret;
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" );
205 if( ! m_insertRow )
206 throw SQLException(
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 );
213 buf.append( " ( " );
215 int columns = 0;
216 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
218 if( m_updateableField[i].isTouched )
220 if( columns > 0 )
221 buf.append( ", " );
222 columns ++;
223 bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings);
226 buf.append( " ) VALUES ( " );
228 columns = 0;
229 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i ++ )
231 if( m_updateableField[i].isTouched )
233 if( columns > 0 )
234 buf.append( " , " );
235 columns ++;
236 bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
238 // OUString val;
239 // m_updateableField[i].value >>= val;
240 // buf.append( val );
241 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
245 buf.append( " )" );
247 Reference< XStatement > stmt =
248 extractConnectionFromStatement(m_owner)->createStatement();
249 DisposeGuard dispGuard( stmt );
250 stmt->executeUpdate( buf.makeStringAndClear() );
252 // reflect the changes !
253 m_rowCount ++;
254 m_data.realloc( m_rowCount );
255 m_data[m_rowCount-1] = Sequence< Any > ( m_fieldCount );
256 Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
257 if( result.is() )
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] );
267 if( field >= 1 )
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() );
277 else
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;
288 // cleanup
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" );
299 if( m_insertRow )
300 throw SQLException(
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 " );
309 int columns = 0;
310 for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
312 if( m_updateableField[i].isTouched )
314 if( columns > 0 )
315 buf.append( ", " );
316 columns ++;
318 buf.append( m_columnNames[i] );
319 buf.append( " = " );
320 bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
321 // OUString val;
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" );
348 if( m_insertRow )
349 throw SQLException(
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 (" );
357 buf.append( m_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];
377 m_rowCount --;
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)
389 m_insertRow = true;
392 void UpdateableResultSet::moveToCurrentRow( ) throw (SQLException, RuntimeException, std::exception)
394 m_insertRow = false;
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 );
408 checkClosed();
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 );
416 checkClosed();
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 );
438 // checkClosed();
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 );
448 checkClosed();
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 );
462 checkClosed();
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 );
471 checkClosed();
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 );
480 checkClosed();
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 );
489 checkClosed();
490 checkUpdate( columnIndex );
492 size_t len;
493 unsigned char * escapedString =
494 PQescapeBytea( (unsigned char *)x.getConstArray(), x.getLength(), &len);
495 if( ! escapedString )
497 throw SQLException(
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)
543 return m_meta;
546 Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
547 throw( com::sun::star::uno::RuntimeException )
549 if( updateable )
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();
558 else
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: */