bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_updateableresultset.cxx
bloba7fb2f79126044b383de731db71efc0493cccc60
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>
42 #include <com/sun/star/sdbc/SQLException.hpp>
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::Sequence;
59 using com::sun::star::uno::UNO_QUERY;
60 using com::sun::star::uno::Any;
61 using com::sun::star::uno::Type;
63 using com::sun::star::sdbc::XGeneratedResultSet;
64 using com::sun::star::sdbc::XResultSetMetaDataSupplier;
65 using com::sun::star::sdbc::SQLException;
66 using com::sun::star::sdbc::XResultSet;
67 using com::sun::star::sdbc::XCloseable;
68 using com::sun::star::sdbc::XColumnLocate;
69 using com::sun::star::sdbc::XResultSetUpdate;
70 using com::sun::star::sdbc::XRowUpdate;
71 using com::sun::star::sdbc::XRow;
72 using com::sun::star::sdbc::XStatement;
74 using com::sun::star::beans::XFastPropertySet;
75 using com::sun::star::beans::XPropertySet;
76 using com::sun::star::beans::XMultiPropertySet;
78 using namespace dbtools;
80 namespace pq_sdbc_driver
84 css::uno::Reference< css::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet(
85 const ::rtl::Reference< comphelper::RefCountedMutex > & mutex,
86 const css::uno::Reference< css::uno::XInterface > &owner,
87 ConnectionSettings **ppSettings,
88 PGresult *result,
89 const OUString &schema,
90 const OUString &table,
91 const std::vector< OUString > &primaryKey )
93 sal_Int32 columnCount = PQnfields( result );
94 sal_Int32 rowCount = PQntuples( result );
95 std::vector< OUString > columnNames( columnCount );
96 for( int i = 0 ; i < columnCount ; i ++ )
98 char * name = PQfname( result, i );
99 columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding );
101 std::vector< std::vector< Any > > data( rowCount );
103 // copy all the data into unicode strings (also binaries, as we yet
104 // don't know, what a binary is and what not!)
105 for( int row = 0 ; row < rowCount ; row ++ )
107 std::vector< Any > aRow( columnCount );
108 for( int col = 0 ; col < columnCount ; col ++ )
110 if( ! PQgetisnull( result, row, col ) )
112 char * val = PQgetvalue( result, row, col );
114 aRow[col] <<=
115 OUString( val, strlen( val ), ConnectionSettings::encoding );
118 data[row] = aRow;
121 UpdateableResultSet *pRS = new UpdateableResultSet(
122 mutex, owner, columnNames, data, ppSettings, schema, table, primaryKey );
124 Reference <XCloseable > ret = pRS; // give it a refcount
126 pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table );
128 PQclear( result ); // we don't need it anymore
130 return ret;
133 css::uno::Any UpdateableResultSet::queryInterface(
134 const css::uno::Type & reqType )
136 Any ret = SequenceResultSet::queryInterface( reqType );
137 if( ! ret.hasValue() )
138 ret = ::cppu::queryInterface(
139 reqType,
140 static_cast< XResultSetUpdate * > ( this ),
141 static_cast< XRowUpdate * > ( this ) );
142 return ret;
146 css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes()
148 static cppu::OTypeCollection collection(
149 cppu::UnoType<XResultSetUpdate>::get(),
150 cppu::UnoType<XRowUpdate>::get(),
151 SequenceResultSet::getTypes());
153 return collection.getTypes();
157 css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId()
159 return css::uno::Sequence<sal_Int8>();
162 OUString UpdateableResultSet::buildWhereClause()
164 OUString ret;
165 if( !m_primaryKey.empty() )
167 OUStringBuffer buf( 128 );
168 buf.append( " WHERE " );
169 for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ )
171 if( i > 0 )
172 buf.append( " AND " );
173 sal_Int32 index = findColumn( m_primaryKey[i] );
174 bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings );
175 buf.append( " = " );
176 bufferQuoteConstant( buf, getString( index ), *m_ppSettings );
178 ret = buf.makeStringAndClear();
180 return ret;
184 void UpdateableResultSet::insertRow( )
186 MutexGuard guard( m_xMutex->GetMutex() );
187 if (isLog(*m_ppSettings, LogLevel::Info))
189 log(*m_ppSettings, LogLevel::Info, "UpdateableResultSet::insertRow got called");
191 if( ! m_insertRow )
192 throw SQLException(
193 "pq_resultset.insertRow: moveToInsertRow has not been called !",
194 *this, OUString(), 1, Any() );
196 OUStringBuffer buf( 128 );
197 buf.append( "INSERT INTO " );
198 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
199 buf.append( " ( " );
201 int columns = 0;
202 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
204 if( m_updateableField[i].isTouched )
206 if( columns > 0 )
207 buf.append( ", " );
208 columns ++;
209 bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings);
212 buf.append( " ) VALUES ( " );
214 columns = 0;
215 for(UpdateableField & i : m_updateableField)
217 if( i.isTouched )
219 if( columns > 0 )
220 buf.append( " , " );
221 columns ++;
222 bufferQuoteAnyConstant( buf, i.value, *m_ppSettings );
224 // OUString val;
225 // m_updateableField[i].value >>= val;
226 // buf.append( val );
227 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
231 buf.append( " )" );
233 Reference< XStatement > stmt =
234 extractConnectionFromStatement(m_owner)->createStatement();
235 DisposeGuard dispGuard( stmt );
236 stmt->executeUpdate( buf.makeStringAndClear() );
238 // reflect the changes !
239 m_rowCount ++;
240 m_data.resize( m_rowCount );
241 m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount );
242 Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
243 if( result.is() )
245 Reference< XResultSet > rs = result->getGeneratedValues();
246 if( rs.is() && rs->next() )
248 Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
249 Reference< XRow> xRow ( rs, UNO_QUERY );
250 for( int i = 0 ; i < m_fieldCount ; i++ )
252 int field = columnLocate->findColumn( m_columnNames[i] );
253 if( field >= 1 )
255 m_data[m_rowCount-1][i] <<= xRow->getString( field );
256 // printf( "adding %s %s\n" ,
257 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
258 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
263 else
265 // do the best we can ( DEFAULT and AUTO increment values fail ! )
266 for( int i = 0 ; i < m_fieldCount ; i ++ )
268 if( m_updateableField[i].isTouched )
269 m_data[m_rowCount-1][i] = m_updateableField[i].value;
274 // cleanup
275 m_updateableField = UpdateableFieldVector();
278 void UpdateableResultSet::updateRow( )
280 MutexGuard guard( m_xMutex->GetMutex() );
281 if (isLog(*m_ppSettings, LogLevel::Info))
283 log(*m_ppSettings, LogLevel::Info, "UpdateableResultSet::updateRow got called");
285 if( m_insertRow )
286 throw SQLException(
287 "pq_resultset.updateRow: moveToCurrentRow has not been called !",
288 *this, OUString(), 1, Any() );
290 OUStringBuffer buf( 128 );
291 buf.append( "UPDATE " );
292 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
293 buf.append( "SET " );
295 int columns = 0;
296 for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
298 if( m_updateableField[i].isTouched )
300 if( columns > 0 )
301 buf.append( ", " );
302 columns ++;
304 buf.append( m_columnNames[i] );
305 buf.append( " = " );
306 bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
307 // OUString val;
308 // m_updateableField[i].value >>= val;
309 // bufferQuoteConstant( buf, val ):
310 // buf.append( val );
313 buf.append( buildWhereClause() );
315 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
316 DisposeGuard dispGuard( stmt );
317 stmt->executeUpdate( buf.makeStringAndClear() );
319 // reflect the changes !
320 for( int i = 0 ; i < m_fieldCount ; i ++ )
322 if( m_updateableField[i].isTouched )
323 m_data[m_row][i] = m_updateableField[i].value;
325 m_updateableField = UpdateableFieldVector();
328 void UpdateableResultSet::deleteRow( )
330 if (isLog(*m_ppSettings, LogLevel::Info))
332 log(*m_ppSettings, LogLevel::Info, "UpdateableResultSet::deleteRow got called");
334 if( m_insertRow )
335 throw SQLException(
336 "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
337 *this, OUString(), 1, Any() );
339 if( m_row < 0 || m_row >= m_rowCount )
341 throw SQLException(
342 "deleteRow cannot be called on invalid row ("
343 + OUString::number(m_row) + ")",
344 *this, OUString(), 0, Any() );
347 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
348 DisposeGuard dispGuard( stmt );
349 OUStringBuffer buf( 128 );
350 buf.append( "DELETE FROM " );
351 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
352 buf.append( " " );
353 buf.append( buildWhereClause() );
355 stmt->executeUpdate( buf.makeStringAndClear() );
357 // reflect the changes !
358 for( int i = m_row + 1; i < m_row ; i ++ )
360 m_data[i-1] = m_data[i];
362 m_rowCount --;
363 m_data.resize( m_rowCount );
366 void UpdateableResultSet::cancelRowUpdates( )
368 MutexGuard guard( m_xMutex->GetMutex() );
369 m_updateableField = UpdateableFieldVector();
372 void UpdateableResultSet::moveToInsertRow( )
374 m_insertRow = true;
377 void UpdateableResultSet::moveToCurrentRow( )
379 m_insertRow = false;
382 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
384 checkColumnIndex( columnIndex );
385 if( m_updateableField.empty() )
386 m_updateableField = UpdateableFieldVector( m_fieldCount );
387 m_updateableField[columnIndex-1].isTouched = true;
390 void UpdateableResultSet::updateNull( sal_Int32 columnIndex )
392 MutexGuard guard( m_xMutex->GetMutex() );
393 checkClosed();
394 checkUpdate( columnIndex );
395 m_updateableField[columnIndex-1].value = Any();
398 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
400 MutexGuard guard( m_xMutex->GetMutex() );
401 checkClosed();
402 checkUpdate( columnIndex );
404 Statics &st = getStatics();
405 m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
409 void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
411 updateInt(columnIndex,x);
414 void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
416 updateInt( columnIndex, x );
419 void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
421 updateLong( columnIndex, x );
422 // MutexGuard guard( m_xMutex->GetMutex() );
423 // checkClosed();
424 // checkUpdate( columnIndex );
426 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
430 void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
432 MutexGuard guard( m_xMutex->GetMutex() );
433 checkClosed();
434 checkUpdate( columnIndex );
436 // OStringBuffer buf( 20 );
437 // buf.append( "'" );
438 // buf.append( (sal_Int64) x );
439 // buf.append( "'" );
440 m_updateableField[columnIndex-1].value <<= OUString::number( x );
443 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x )
446 MutexGuard guard( m_xMutex->GetMutex() );
447 checkClosed();
448 checkUpdate( columnIndex );
450 m_updateableField[columnIndex-1].value <<= OUString::number( x );
453 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x )
455 MutexGuard guard( m_xMutex->GetMutex() );
456 checkClosed();
457 checkUpdate( columnIndex );
459 m_updateableField[columnIndex-1].value <<= OUString::number( x );
462 void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
464 MutexGuard guard( m_xMutex->GetMutex() );
465 checkClosed();
466 checkUpdate( columnIndex );
468 m_updateableField[columnIndex-1].value <<= x;
471 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
473 MutexGuard guard( m_xMutex->GetMutex() );
474 checkClosed();
475 checkUpdate( columnIndex );
477 size_t len;
478 unsigned char * escapedString =
479 PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
480 if( ! escapedString )
482 throw SQLException(
483 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
484 *this, OUString(), 1, Any() );
486 // buf.append( (const sal_Char *)escapedString, len -1 );
488 m_updateableField[columnIndex-1].value <<=
489 OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US );
490 free( escapedString );
493 void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
495 updateString( columnIndex, DBTypeConversion::toDateString( x ) );
498 void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
500 updateString( columnIndex, DBTypeConversion::toTimeString( x ) );
503 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
505 updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) );
508 void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
512 void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
516 void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
520 void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
525 Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
527 if( updateable )
529 cppu::OTypeCollection collection(
530 cppu::UnoType<XResultSetUpdate>::get(),
531 cppu::UnoType<XRowUpdate>::get(),
532 // cppu::UnoType<css::sdbcx::XRowLocate>::get(),
533 getStaticTypes( false /* updateable */ ) );
534 return collection.getTypes();
536 else
538 cppu::OTypeCollection collection(
539 cppu::UnoType<XResultSet>::get(),
540 cppu::UnoType<XResultSetMetaDataSupplier>::get(),
541 cppu::UnoType<XRow>::get(),
542 cppu::UnoType<XColumnLocate>::get(),
543 cppu::UnoType<XCloseable>::get(),
544 cppu::UnoType<XPropertySet>::get(),
545 cppu::UnoType<XFastPropertySet>::get(),
546 cppu::UnoType<XMultiPropertySet>::get(),
547 cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper
548 cppu::UnoType<css::lang::XTypeProvider>::get(),
549 cppu::UnoType<css::uno::XAggregation>::get(),
550 cppu::UnoType<css::uno::XWeak>::get());
551 return collection.getTypes();
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */