merge the formfield patch from ooo-build
[ooovba.git] / connectivity / source / drivers / postgresql / pq_updateableresultset.cxx
blob0e416937319fcb8d1352eccf55cbd403f1690d78
1 #include <rtl/ustrbuf.hxx>
2 #include <rtl/strbuf.hxx>
4 #include <cppuhelper/queryinterface.hxx>
5 #include <cppuhelper/typeprovider.hxx>
7 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
8 // #include <com/sun/star/sdbcx/XRowLocate.hpp>
10 #include "pq_updateableresultset.hxx"
11 #include "pq_resultsetmetadata.hxx"
12 #include "pq_tools.hxx"
13 #include "pq_statics.hxx"
15 #include <string.h>
17 using osl::MutexGuard;
19 using rtl::OUString;
20 using rtl::OUStringBuffer;
21 using rtl::OStringBuffer;
22 using rtl::OString;
24 using com::sun::star::uno::Reference;
25 using com::sun::star::uno::makeAny;
26 using com::sun::star::uno::Sequence;
27 using com::sun::star::uno::UNO_QUERY;
28 using com::sun::star::uno::Any;
29 using com::sun::star::uno::Type;
30 using com::sun::star::uno::RuntimeException;
32 using com::sun::star::sdbc::XGeneratedResultSet;
33 using com::sun::star::sdbc::XResultSetMetaDataSupplier;
34 using com::sun::star::sdbc::SQLException;
35 using com::sun::star::sdbc::XResultSet;
36 using com::sun::star::sdbc::XCloseable;
37 using com::sun::star::sdbc::XColumnLocate;
38 using com::sun::star::sdbc::XResultSetUpdate;
39 using com::sun::star::sdbc::XRowUpdate;
40 using com::sun::star::sdbc::XRow;
41 using com::sun::star::sdbc::XStatement;
43 using com::sun::star::beans::XFastPropertySet;
44 using com::sun::star::beans::XPropertySet;
45 using com::sun::star::beans::XMultiPropertySet;
47 #define ASCII_STR(x) OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
49 namespace pq_sdbc_driver
53 com::sun::star::uno::Reference< com::sun::star::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet(
54 const ::rtl::Reference< RefCountedMutex > & mutex,
55 const com::sun::star::uno::Reference< com::sun::star::uno::XInterface > &owner,
56 ConnectionSettings **ppSettings,
57 PGresult *result,
58 const rtl::OUString &schema,
59 const rtl::OUString &table,
60 const com::sun::star::uno::Sequence< ::rtl::OUString > &primaryKey )
62 ConnectionSettings *pSettings = *ppSettings;
63 sal_Int32 columnCount = PQnfields( result );
64 sal_Int32 rowCount = PQntuples( result );
65 Sequence< OUString > columnNames( columnCount );
66 for( int i = 0 ; i < columnCount ; i ++ )
68 char * name = PQfname( result, i );
69 columnNames[i] = rtl::OUString( name, strlen(name), pSettings->encoding );
71 Sequence< Sequence< Any > > data( rowCount );
73 // copy all the data into unicode strings (also binaries, as we yet
74 // don't know, what a binary is and what not!)
75 for( int row = 0 ; row < rowCount ; row ++ )
77 Sequence< Any > aRow( columnCount );
78 for( int col = 0 ; col < columnCount ; col ++ )
80 if( ! PQgetisnull( result, row, col ) )
82 char * val = PQgetvalue( result, row, col );
84 aRow[col] = makeAny(
85 rtl::OUString( val, strlen( val ) , (*ppSettings)->encoding ) );
88 data[row] = aRow;
91 UpdateableResultSet *pRS = new UpdateableResultSet(
92 mutex, owner, columnNames, data, ppSettings, schema, table , primaryKey );
94 Reference <XCloseable > ret = pRS; // give it an refcount
96 pRS->m_meta = new ResultSetMetaData( mutex, pRS,0, ppSettings, result, schema, table );
98 PQclear( result ); // we don't need it anymore
100 return ret;
103 static void bufferQuoteAnyConstant( rtl::OUStringBuffer & buf, const Any &val )
105 if( val.hasValue() )
107 OUString str;
108 val >>= str;
109 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "'" ) );
110 buf.append( str );
111 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "'" ) );
113 else
114 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "NULL" ) );
118 com::sun::star::uno::Any UpdateableResultSet::queryInterface(
119 const com::sun::star::uno::Type & reqType )
120 throw (com::sun::star::uno::RuntimeException)
122 Any ret = SequenceResultSet::queryInterface( reqType );
123 if( ! ret.hasValue() )
124 ret = ::cppu::queryInterface(
125 reqType,
126 static_cast< XResultSetUpdate * > ( this ),
127 static_cast< XRowUpdate * > ( this ) );
128 return ret;
132 com::sun::star::uno::Sequence< com::sun::star::uno::Type > UpdateableResultSet::getTypes()
133 throw( com::sun::star::uno::RuntimeException )
135 static cppu::OTypeCollection *pCollection;
136 if( ! pCollection )
138 MutexGuard guard( osl::Mutex::getGlobalMutex() );
139 if( !pCollection )
141 static cppu::OTypeCollection collection(
142 getCppuType( (Reference< XResultSetUpdate> *) 0 ),
143 getCppuType( (Reference< XRowUpdate> *) 0 ),
144 SequenceResultSet::getTypes());
145 pCollection = &collection;
148 return pCollection->getTypes();
152 com::sun::star::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId()
153 throw( com::sun::star::uno::RuntimeException )
155 static cppu::OImplementationId *pId;
156 if( ! pId )
158 MutexGuard guard( osl::Mutex::getGlobalMutex() );
159 if( ! pId )
161 static cppu::OImplementationId id(sal_False);
162 pId = &id;
165 return pId->getImplementationId();
168 OUString UpdateableResultSet::buildWhereClause()
170 OUString ret;
171 if( m_primaryKey.getLength() )
173 OUStringBuffer buf( 128 );
174 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " WHERE " ) );
175 for( int i = 0 ; i < m_primaryKey.getLength() ; i ++ )
177 if( i > 0 )
178 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " AND " ) );
179 sal_Int32 index = findColumn( m_primaryKey[i] );
180 bufferQuoteIdentifier( buf, m_primaryKey[i] );
181 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " = " ) );
182 bufferQuoteConstant( buf, getString( index ), (*m_ppSettings)->encoding );
184 ret = buf.makeStringAndClear();
186 return ret;
190 void UpdateableResultSet::insertRow( ) throw (SQLException, RuntimeException)
192 MutexGuard guard( m_refMutex->mutex );
193 if( isLog( *m_ppSettings, LogLevel::INFO ) )
195 log( *m_ppSettings, LogLevel::INFO,"UpdateableResultSet::insertRow got called" );
197 if( ! m_insertRow )
198 throw SQLException(
199 ASCII_STR("pq_resultset.insertRow: moveToInsertRow has not been called !" ),
200 *this, OUString(), 1, Any() );
202 OUStringBuffer buf( 128 );
203 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "INSERT INTO " ) );
204 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table );
205 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " ( " ) );
207 int i;
208 int columns = 0;
209 for( i = 0 ; i < m_updateableField.size() ; i++ )
211 if( m_updateableField[i].isTouched )
213 if( columns > 0 )
214 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
215 columns ++;
216 bufferQuoteIdentifier( buf, m_columnNames[i]);
219 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " ) VALUES ( " ) );
221 columns = 0;
222 for( i = 0 ; i < m_updateableField.size() ; i ++ )
224 if( m_updateableField[i].isTouched )
226 if( columns > 0 )
227 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " , " ) );
228 columns ++;
229 bufferQuoteAnyConstant( buf, m_updateableField[i].value );
231 // OUString val;
232 // m_updateableField[i].value >>= val;
233 // buf.append( val );
234 // rtl::OStringToOUString(val, (*m_ppSettings)->encoding ) );
238 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " )" ) );
240 Reference< XStatement > stmt =
241 extractConnectionFromStatement(m_owner)->createStatement();
242 DisposeGuard dispGuard( stmt );
243 stmt->executeUpdate( buf.makeStringAndClear() );
245 // reflect the changes !
246 m_rowCount ++;
247 m_data.realloc( m_rowCount );
248 m_data[m_rowCount-1] = Sequence< Any > ( m_fieldCount );
249 Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
250 if( result.is() )
252 Reference< XResultSet > rs = result->getGeneratedValues();
253 if( rs.is() && rs->next() )
255 Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
256 Reference< XRow> xRow ( rs, UNO_QUERY );
257 for( i = 0 ; i < m_fieldCount ; i++ )
259 int field = columnLocate->findColumn( m_columnNames[i] );
260 if( field >= 1 )
262 m_data[m_rowCount-1][i] <<= xRow->getString( field );
263 // printf( "adding %s %s\n" ,
264 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
265 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
270 else
272 // do the best we can ( DEFAULT and AUTO increment values fail ! )
273 for( int i = 0 ; i < m_fieldCount ; i ++ )
275 if( m_updateableField[i].isTouched )
276 m_data[m_rowCount-1][i] = m_updateableField[i].value;
281 // cleanup
282 m_updateableField = UpdateableFieldVector();
285 void UpdateableResultSet::updateRow( ) throw (SQLException, RuntimeException)
287 MutexGuard guard( m_refMutex->mutex );
288 if( isLog( *m_ppSettings, LogLevel::INFO ) )
290 log( *m_ppSettings, LogLevel::INFO,"UpdateableResultSet::updateRow got called" );
292 if( m_insertRow )
293 throw SQLException(
294 ASCII_STR("pq_resultset.updateRow: moveToCurrentRow has not been called !" ),
295 *this, OUString(), 1, Any() );
297 OUStringBuffer buf( 128 );
298 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "UPDATE " ) );
299 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table );
300 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "SET " ) );
302 int columns = 0,i;
303 for( i = 0; i < m_updateableField.size() ; i ++ )
305 if( m_updateableField[i].isTouched )
307 if( columns > 0 )
308 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
309 columns ++;
311 buf.append( m_columnNames[i] );
312 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = " ) );
313 bufferQuoteAnyConstant( buf, m_updateableField[i].value );
314 // OUString val;
315 // m_updateableField[i].value >>= val;
316 // bufferQuoteConstant( buf, val ):
317 // buf.append( val );
320 buf.append( buildWhereClause() );
322 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
323 DisposeGuard dispGuard( stmt );
324 stmt->executeUpdate( buf.makeStringAndClear() );
326 // reflect the changes !
327 for( i = 0 ; i < m_fieldCount ; i ++ )
329 if( m_updateableField[i].isTouched )
330 m_data[m_row][i] = m_updateableField[i].value;
332 m_updateableField = UpdateableFieldVector();
335 void UpdateableResultSet::deleteRow( ) throw (SQLException, RuntimeException)
337 if( isLog( *m_ppSettings, LogLevel::INFO ) )
339 log( *m_ppSettings, LogLevel::INFO,"UpdateableResultSet::deleteRow got called" );
341 if( m_insertRow )
342 throw SQLException(
343 ASCII_STR("pq_resultset.deleteRow: deleteRow cannot be called when on insert row !" ),
344 *this, OUString(), 1, Any() );
346 if( m_row < 0 || m_row >= m_rowCount )
348 OUStringBuffer buf( 128 );
349 buf.appendAscii( "deleteRow cannot be called on invalid row (" );
350 buf.append( m_row );
351 buf.appendAscii( ")" );
352 throw SQLException( buf.makeStringAndClear() , *this, OUString(), 0, Any() );
355 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
356 DisposeGuard dispGuard( stmt );
357 OUStringBuffer buf( 128 );
358 buf.appendAscii( "DELETE FROM " );
359 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table );
360 buf.appendAscii( " " );
361 buf.append( buildWhereClause() );
363 stmt->executeUpdate( buf.makeStringAndClear() );
365 // reflect the changes !
366 for( int i = m_row + 1; i < m_row ; i ++ )
368 m_data[i-1] = m_data[i];
370 m_rowCount --;
371 m_data.realloc( m_rowCount );
374 void UpdateableResultSet::cancelRowUpdates( ) throw (SQLException, RuntimeException)
376 MutexGuard guard( m_refMutex->mutex );
377 m_updateableField = UpdateableFieldVector();
380 void UpdateableResultSet::moveToInsertRow( ) throw (SQLException, RuntimeException)
382 m_insertRow = true;
385 void UpdateableResultSet::moveToCurrentRow( ) throw (SQLException, RuntimeException)
387 m_insertRow = false;
390 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
392 checkColumnIndex( columnIndex );
393 if( m_updateableField.empty() )
394 m_updateableField = UpdateableFieldVector( m_fieldCount );
395 m_updateableField[columnIndex-1].isTouched = true;
398 void UpdateableResultSet::updateNull( sal_Int32 columnIndex ) throw (SQLException, RuntimeException)
400 MutexGuard guard( m_refMutex->mutex );
401 checkClosed();
402 checkUpdate( columnIndex );
403 m_updateableField[columnIndex-1].value = Any();
406 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) throw (SQLException, RuntimeException)
408 MutexGuard guard( m_refMutex->mutex );
409 checkClosed();
410 checkUpdate( columnIndex );
412 Statics &st = getStatics();
413 if( x )
414 m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
418 void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) throw (SQLException, RuntimeException)
420 updateInt(columnIndex,x);
423 void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) throw (SQLException, RuntimeException)
425 updateInt( columnIndex, x );
428 void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) throw (SQLException, RuntimeException)
430 updateLong( columnIndex, x );
431 // MutexGuard guard( m_refMutex->mutex );
432 // checkClosed();
433 // checkUpdate( columnIndex );
435 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
439 void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x ) throw (SQLException, RuntimeException)
441 MutexGuard guard( m_refMutex->mutex );
442 checkClosed();
443 checkUpdate( columnIndex );
445 // OStringBuffer buf( 20 );
446 // buf.append( "'" );
447 // buf.append( (sal_Int64) x );
448 // buf.append( "'" );
449 m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
452 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x ) throw (SQLException, RuntimeException)
455 MutexGuard guard( m_refMutex->mutex );
456 checkClosed();
457 checkUpdate( columnIndex );
459 m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
462 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x ) throw (SQLException, RuntimeException)
464 MutexGuard guard( m_refMutex->mutex );
465 checkClosed();
466 checkUpdate( columnIndex );
468 m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
471 void UpdateableResultSet::updateString( sal_Int32 columnIndex, const ::rtl::OUString& x ) throw (SQLException, RuntimeException)
473 MutexGuard guard( m_refMutex->mutex );
474 checkClosed();
475 checkUpdate( columnIndex );
477 m_updateableField[columnIndex-1].value <<= x;
480 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const ::com::sun::star::uno::Sequence< sal_Int8 >& x ) throw (SQLException, RuntimeException)
482 MutexGuard guard( m_refMutex->mutex );
483 checkClosed();
484 checkUpdate( columnIndex );
486 size_t len;
487 unsigned char * escapedString =
488 PQescapeBytea( (unsigned char *)x.getConstArray(), x.getLength(), &len);
489 if( ! escapedString )
491 throw SQLException(
492 ASCII_STR("pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string" ),
493 *this, OUString(), 1, Any() );
495 // buf.append( (const sal_Char *)escapedString, len -1 );
497 m_updateableField[columnIndex-1].value <<=
498 OUString( (sal_Char*) escapedString, len, RTL_TEXTENCODING_ASCII_US );
499 free( escapedString );
502 void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const ::com::sun::star::util::Date& x ) throw (SQLException, RuntimeException)
504 updateString( columnIndex, date2String( x ) );
507 void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const ::com::sun::star::util::Time& x ) throw (SQLException, RuntimeException)
509 updateString( columnIndex, time2String( x ) );
512 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const ::com::sun::star::util::DateTime& x ) throw (SQLException, RuntimeException)
514 updateString( columnIndex, dateTime2String( x ) );
517 void UpdateableResultSet::updateBinaryStream( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw (SQLException, RuntimeException)
521 void UpdateableResultSet::updateCharacterStream( sal_Int32 columnIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw (SQLException, RuntimeException)
525 void UpdateableResultSet::updateObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x ) throw (SQLException, RuntimeException)
529 void UpdateableResultSet::updateNumericObject( sal_Int32 columnIndex, const ::com::sun::star::uno::Any& x, sal_Int32 scale ) throw (SQLException, RuntimeException)
534 ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSetMetaData > UpdateableResultSet::getMetaData( )
535 throw (::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
537 return m_meta;
540 Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
541 throw( com::sun::star::uno::RuntimeException )
543 if( updateable )
545 cppu::OTypeCollection collection(
546 getCppuType( (Reference< XResultSetUpdate> *) 0 ),
547 getCppuType( (Reference< XRowUpdate> *) 0 ),
548 // getCppuType( (Reference< com::sun::star::sdbcx::XRowLocate > *) 0 ),
549 getStaticTypes( false /* updateable */ ) );
550 return collection.getTypes();
552 else
554 cppu::OTypeCollection collection(
555 getCppuType( (Reference< XResultSet> *) 0 ),
556 getCppuType( (Reference< XResultSetMetaDataSupplier> *) 0 ),
557 getCppuType( (Reference< XRow> *) 0 ),
558 getCppuType( (Reference< XColumnLocate> *) 0 ),
559 getCppuType( (Reference< XCloseable> *) 0 ),
560 getCppuType( (Reference< XPropertySet >*) 0 ),
561 getCppuType( (Reference< XFastPropertySet > *) 0 ),
562 getCppuType( (Reference< XMultiPropertySet > *) 0 ),
563 getCppuType( (const Reference< com::sun::star::lang::XComponent > *)0 ), // OComponentHelper
564 getCppuType( (const Reference< com::sun::star::lang::XTypeProvider > *)0 ),
565 getCppuType( (const Reference< com::sun::star::uno::XAggregation > *)0 ),
566 getCppuType( (const Reference< com::sun::star::uno::XWeak > *)0 ) );
567 return collection.getTypes();