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"
17 using osl::MutexGuard
;
20 using rtl::OUStringBuffer
;
21 using rtl::OStringBuffer
;
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
,
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
);
85 rtl::OUString( val
, strlen( val
) , (*ppSettings
)->encoding
) );
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
103 static void bufferQuoteAnyConstant( rtl::OUStringBuffer
& buf
, const Any
&val
)
109 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "'" ) );
111 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "'" ) );
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(
126 static_cast< XResultSetUpdate
* > ( this ),
127 static_cast< XRowUpdate
* > ( this ) );
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
;
138 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
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
;
158 MutexGuard
guard( osl::Mutex::getGlobalMutex() );
161 static cppu::OImplementationId
id(sal_False
);
165 return pId
->getImplementationId();
168 OUString
UpdateableResultSet::buildWhereClause()
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
++ )
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();
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" );
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( " ( " ) );
209 for( i
= 0 ; i
< m_updateableField
.size() ; i
++ )
211 if( m_updateableField
[i
].isTouched
)
214 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
216 bufferQuoteIdentifier( buf
, m_columnNames
[i
]);
219 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( " ) VALUES ( " ) );
222 for( i
= 0 ; i
< m_updateableField
.size() ; i
++ )
224 if( m_updateableField
[i
].isTouched
)
227 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( " , " ) );
229 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
);
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 !
247 m_data
.realloc( m_rowCount
);
248 m_data
[m_rowCount
-1] = Sequence
< Any
> ( m_fieldCount
);
249 Reference
< XGeneratedResultSet
> result( stmt
, UNO_QUERY
);
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
] );
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() );
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
;
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" );
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 " ) );
303 for( i
= 0; i
< m_updateableField
.size() ; i
++ )
305 if( m_updateableField
[i
].isTouched
)
308 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( ", " ) );
311 buf
.append( m_columnNames
[i
] );
312 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(" = " ) );
313 bufferQuoteAnyConstant( buf
, m_updateableField
[i
].value
);
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" );
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 (" );
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
];
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
)
385 void UpdateableResultSet::moveToCurrentRow( ) throw (SQLException
, RuntimeException
)
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
);
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
);
410 checkUpdate( columnIndex
);
412 Statics
&st
= getStatics();
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 );
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
);
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
);
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
);
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
);
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
);
484 checkUpdate( columnIndex
);
487 unsigned char * escapedString
=
488 PQescapeBytea( (unsigned char *)x
.getConstArray(), x
.getLength(), &len
);
489 if( ! escapedString
)
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
)
540 Sequence
< Type
> UpdateableResultSet::getStaticTypes( bool updateable
)
541 throw( com::sun::star::uno::RuntimeException
)
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();
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();