Use correct object
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_updateableresultset.cxx
blobd8d2edfc6c04de9aac623a4d96d98ebdd8e2b913
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 <sal/log.hxx>
38 #include <rtl/ref.hxx>
39 #include <rtl/ustrbuf.hxx>
41 #include <cppuhelper/queryinterface.hxx>
42 #include <cppuhelper/typeprovider.hxx>
43 #include <com/sun/star/sdbc/SQLException.hpp>
44 #include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
46 #include "pq_updateableresultset.hxx"
47 #include "pq_resultsetmetadata.hxx"
48 #include "pq_tools.hxx"
49 #include "pq_statics.hxx"
51 #include <string.h>
53 #include <connectivity/dbconversion.hxx>
55 using osl::MutexGuard;
58 using com::sun::star::uno::Reference;
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;
64 using com::sun::star::sdbc::XGeneratedResultSet;
65 using com::sun::star::sdbc::XResultSetMetaDataSupplier;
66 using com::sun::star::sdbc::SQLException;
67 using com::sun::star::sdbc::XResultSet;
68 using com::sun::star::sdbc::XCloseable;
69 using com::sun::star::sdbc::XColumnLocate;
70 using com::sun::star::sdbc::XResultSetUpdate;
71 using com::sun::star::sdbc::XRowUpdate;
72 using com::sun::star::sdbc::XRow;
73 using com::sun::star::sdbc::XStatement;
75 using com::sun::star::beans::XFastPropertySet;
76 using com::sun::star::beans::XPropertySet;
77 using com::sun::star::beans::XMultiPropertySet;
79 using namespace dbtools;
81 namespace pq_sdbc_driver
85 css::uno::Reference< css::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet(
86 const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
87 const css::uno::Reference< css::uno::XInterface > &owner,
88 ConnectionSettings **ppSettings,
89 PGresult *result,
90 const OUString &schema,
91 const OUString &table,
92 std::vector< OUString > && primaryKey )
94 sal_Int32 columnCount = PQnfields( result );
95 sal_Int32 rowCount = PQntuples( result );
96 std::vector< OUString > columnNames( columnCount );
97 for( int i = 0 ; i < columnCount ; i ++ )
99 char * name = PQfname( result, i );
100 columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding );
102 std::vector< std::vector< Any > > data( rowCount );
104 // copy all the data into unicode strings (also binaries, as we yet
105 // don't know, what a binary is and what not!)
106 for( int row = 0 ; row < rowCount ; row ++ )
108 std::vector< Any > aRow( columnCount );
109 for( int col = 0 ; col < columnCount ; col ++ )
111 if( ! PQgetisnull( result, row, col ) )
113 char * val = PQgetvalue( result, row, col );
115 aRow[col] <<=
116 OUString( val, strlen( val ), ConnectionSettings::encoding );
119 data[row] = std::move(aRow);
122 rtl::Reference<UpdateableResultSet> pRS = new UpdateableResultSet(
123 mutex, owner, std::move(columnNames), std::move(data), ppSettings, schema, table, std::move(primaryKey) );
125 pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table );
127 PQclear( result ); // we don't need it anymore
129 return pRS;
132 css::uno::Any UpdateableResultSet::queryInterface(
133 const css::uno::Type & reqType )
135 Any ret = SequenceResultSet::queryInterface( reqType );
136 if( ! ret.hasValue() )
137 ret = ::cppu::queryInterface(
138 reqType,
139 static_cast< XResultSetUpdate * > ( this ),
140 static_cast< XRowUpdate * > ( this ) );
141 return ret;
145 css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes()
147 static cppu::OTypeCollection collection(
148 cppu::UnoType<XResultSetUpdate>::get(),
149 cppu::UnoType<XRowUpdate>::get(),
150 SequenceResultSet::getTypes());
152 return collection.getTypes();
156 css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId()
158 return css::uno::Sequence<sal_Int8>();
161 OUString UpdateableResultSet::buildWhereClause()
163 OUString ret;
164 if( !m_primaryKey.empty() )
166 OUStringBuffer buf( 128 );
167 buf.append( " WHERE " );
168 for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ )
170 if( i > 0 )
171 buf.append( " AND " );
172 sal_Int32 index = findColumn( m_primaryKey[i] );
173 bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings );
174 buf.append( " = " );
175 bufferQuoteConstant( buf, getString( index ), *m_ppSettings );
177 ret = buf.makeStringAndClear();
179 return ret;
183 void UpdateableResultSet::insertRow( )
185 MutexGuard guard( m_xMutex->GetMutex() );
186 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called");
188 if( ! m_insertRow )
189 throw SQLException(
190 u"pq_resultset.insertRow: moveToInsertRow has not been called !"_ustr,
191 *this, OUString(), 1, Any() );
193 OUStringBuffer buf( 128 );
194 buf.append( "INSERT INTO " );
195 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
196 buf.append( " ( " );
198 int columns = 0;
199 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
201 if( m_updateableField[i].isTouched )
203 if( columns > 0 )
204 buf.append( ", " );
205 columns ++;
206 bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings);
209 buf.append( " ) VALUES ( " );
211 columns = 0;
212 for(const UpdateableField & i : m_updateableField)
214 if( i.isTouched )
216 if( columns > 0 )
217 buf.append( " , " );
218 columns ++;
219 bufferQuoteAnyConstant( buf, i.value, *m_ppSettings );
221 // OUString val;
222 // m_updateableField[i].value >>= val;
223 // buf.append( val );
224 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
228 buf.append( " )" );
230 Reference< XStatement > stmt =
231 extractConnectionFromStatement(m_owner)->createStatement();
232 DisposeGuard dispGuard( stmt );
233 stmt->executeUpdate( buf.makeStringAndClear() );
235 // reflect the changes !
236 m_rowCount ++;
237 m_data.resize( m_rowCount );
238 m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount );
239 Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
240 if( result.is() )
242 Reference< XResultSet > rs = result->getGeneratedValues();
243 if( rs.is() && rs->next() )
245 Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
246 Reference< XRow> xRow ( rs, UNO_QUERY );
247 for( int i = 0 ; i < m_fieldCount ; i++ )
249 int field = columnLocate->findColumn( m_columnNames[i] );
250 if( field >= 1 )
252 m_data[m_rowCount-1][i] <<= xRow->getString( field );
253 // printf( "adding %s %s\n" ,
254 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
255 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
260 else
262 // do the best we can ( DEFAULT and AUTO increment values fail ! )
263 for( int i = 0 ; i < m_fieldCount ; i ++ )
265 if( m_updateableField[i].isTouched )
266 m_data[m_rowCount-1][i] = m_updateableField[i].value;
271 // cleanup
272 m_updateableField = UpdateableFieldVector();
275 void UpdateableResultSet::updateRow( )
277 MutexGuard guard( m_xMutex->GetMutex() );
278 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called");
280 if( m_insertRow )
281 throw SQLException(
282 u"pq_resultset.updateRow: moveToCurrentRow has not been called !"_ustr,
283 *this, OUString(), 1, Any() );
285 OUStringBuffer buf( 128 );
286 buf.append( "UPDATE " );
287 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
288 buf.append( "SET " );
290 int columns = 0;
291 for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
293 if( m_updateableField[i].isTouched )
295 if( columns > 0 )
296 buf.append( ", " );
297 columns ++;
299 buf.append( m_columnNames[i]
300 + " = " );
301 bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
302 // OUString val;
303 // m_updateableField[i].value >>= val;
304 // bufferQuoteConstant( buf, val ):
305 // buf.append( val );
308 buf.append( buildWhereClause() );
310 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
311 DisposeGuard dispGuard( stmt );
312 stmt->executeUpdate( buf.makeStringAndClear() );
314 // reflect the changes !
315 for( int i = 0 ; i < m_fieldCount ; i ++ )
317 if( m_updateableField[i].isTouched )
318 m_data[m_row][i] = m_updateableField[i].value;
320 m_updateableField = UpdateableFieldVector();
323 void UpdateableResultSet::deleteRow( )
325 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called");
327 if( m_insertRow )
328 throw SQLException(
329 u"pq_resultset.deleteRow: deleteRow cannot be called when on insert row !"_ustr,
330 *this, OUString(), 1, Any() );
332 if( m_row < 0 || m_row >= m_rowCount )
334 throw SQLException(
335 "deleteRow cannot be called on invalid row ("
336 + OUString::number(m_row) + ")",
337 *this, OUString(), 0, Any() );
340 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
341 DisposeGuard dispGuard( stmt );
342 OUStringBuffer buf( 128 );
343 buf.append( "DELETE FROM " );
344 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
345 buf.append( " "
346 + buildWhereClause() );
348 stmt->executeUpdate( buf.makeStringAndClear() );
350 // reflect the changes !
351 for( int i = m_row + 1; i < m_row ; i ++ )
353 m_data[i-1] = m_data[i];
355 m_rowCount --;
356 m_data.resize( m_rowCount );
359 void UpdateableResultSet::cancelRowUpdates( )
361 MutexGuard guard( m_xMutex->GetMutex() );
362 m_updateableField = UpdateableFieldVector();
365 void UpdateableResultSet::moveToInsertRow( )
367 m_insertRow = true;
370 void UpdateableResultSet::moveToCurrentRow( )
372 m_insertRow = false;
375 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
377 checkColumnIndex( columnIndex );
378 if( m_updateableField.empty() )
379 m_updateableField = UpdateableFieldVector( m_fieldCount );
380 m_updateableField[columnIndex-1].isTouched = true;
383 void UpdateableResultSet::updateNull( sal_Int32 columnIndex )
385 MutexGuard guard( m_xMutex->GetMutex() );
386 checkClosed();
387 checkUpdate( columnIndex );
388 m_updateableField[columnIndex-1].value = Any();
391 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
393 MutexGuard guard( m_xMutex->GetMutex() );
394 checkClosed();
395 checkUpdate( columnIndex );
397 Statics &st = getStatics();
398 m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
402 void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
404 updateInt(columnIndex,x);
407 void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
409 updateInt( columnIndex, x );
412 void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
414 updateLong( columnIndex, x );
415 // MutexGuard guard( m_xMutex->GetMutex() );
416 // checkClosed();
417 // checkUpdate( columnIndex );
419 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
423 void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
425 MutexGuard guard( m_xMutex->GetMutex() );
426 checkClosed();
427 checkUpdate( columnIndex );
429 // OStringBuffer buf( 20 );
430 // buf.append( "'" );
431 // buf.append( (sal_Int64) x );
432 // buf.append( "'" );
433 m_updateableField[columnIndex-1].value <<= OUString::number( x );
436 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x )
439 MutexGuard guard( m_xMutex->GetMutex() );
440 checkClosed();
441 checkUpdate( columnIndex );
443 m_updateableField[columnIndex-1].value <<= OUString::number( x );
446 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x )
448 MutexGuard guard( m_xMutex->GetMutex() );
449 checkClosed();
450 checkUpdate( columnIndex );
452 m_updateableField[columnIndex-1].value <<= OUString::number( x );
455 void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
457 MutexGuard guard( m_xMutex->GetMutex() );
458 checkClosed();
459 checkUpdate( columnIndex );
461 m_updateableField[columnIndex-1].value <<= x;
464 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
466 MutexGuard guard( m_xMutex->GetMutex() );
467 checkClosed();
468 checkUpdate( columnIndex );
470 size_t len;
471 unsigned char * escapedString =
472 PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
473 if( ! escapedString )
475 throw SQLException(
476 u"pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string"_ustr,
477 *this, OUString(), 1, Any() );
479 // buf.append( (const char *)escapedString, len -1 );
481 m_updateableField[columnIndex-1].value <<=
482 OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US );
483 PQfreemem( escapedString );
486 void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
488 updateString( columnIndex, DBTypeConversion::toDateString( x ) );
491 void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
493 updateString( columnIndex, DBTypeConversion::toTimeString( x ) );
496 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
498 updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) );
501 void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
505 void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
509 void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
513 void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
518 Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
520 if( updateable )
522 cppu::OTypeCollection collection(
523 cppu::UnoType<XResultSetUpdate>::get(),
524 cppu::UnoType<XRowUpdate>::get(),
525 // cppu::UnoType<css::sdbcx::XRowLocate>::get(),
526 getStaticTypes( false /* updateable */ ) );
527 return collection.getTypes();
529 else
531 cppu::OTypeCollection collection(
532 cppu::UnoType<XResultSet>::get(),
533 cppu::UnoType<XResultSetMetaDataSupplier>::get(),
534 cppu::UnoType<XRow>::get(),
535 cppu::UnoType<XColumnLocate>::get(),
536 cppu::UnoType<XCloseable>::get(),
537 cppu::UnoType<XPropertySet>::get(),
538 cppu::UnoType<XFastPropertySet>::get(),
539 cppu::UnoType<XMultiPropertySet>::get(),
540 cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper
541 cppu::UnoType<css::lang::XTypeProvider>::get(),
542 cppu::UnoType<css::uno::XAggregation>::get(),
543 cppu::UnoType<css::uno::XWeak>::get());
544 return collection.getTypes();
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */