nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / drivers / postgresql / pq_updateableresultset.cxx
blobd8780e76c56385a30f56582052b50c50cefca5ad
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/ustrbuf.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 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called");
189 if( ! m_insertRow )
190 throw SQLException(
191 "pq_resultset.insertRow: moveToInsertRow has not been called !",
192 *this, OUString(), 1, Any() );
194 OUStringBuffer buf( 128 );
195 buf.append( "INSERT INTO " );
196 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
197 buf.append( " ( " );
199 int columns = 0;
200 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
202 if( m_updateableField[i].isTouched )
204 if( columns > 0 )
205 buf.append( ", " );
206 columns ++;
207 bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings);
210 buf.append( " ) VALUES ( " );
212 columns = 0;
213 for(const UpdateableField & i : m_updateableField)
215 if( i.isTouched )
217 if( columns > 0 )
218 buf.append( " , " );
219 columns ++;
220 bufferQuoteAnyConstant( buf, i.value, *m_ppSettings );
222 // OUString val;
223 // m_updateableField[i].value >>= val;
224 // buf.append( val );
225 // OStringToOUString(val, (*m_ppSettings)->encoding ) );
229 buf.append( " )" );
231 Reference< XStatement > stmt =
232 extractConnectionFromStatement(m_owner)->createStatement();
233 DisposeGuard dispGuard( stmt );
234 stmt->executeUpdate( buf.makeStringAndClear() );
236 // reflect the changes !
237 m_rowCount ++;
238 m_data.resize( m_rowCount );
239 m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount );
240 Reference< XGeneratedResultSet > result( stmt, UNO_QUERY );
241 if( result.is() )
243 Reference< XResultSet > rs = result->getGeneratedValues();
244 if( rs.is() && rs->next() )
246 Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
247 Reference< XRow> xRow ( rs, UNO_QUERY );
248 for( int i = 0 ; i < m_fieldCount ; i++ )
250 int field = columnLocate->findColumn( m_columnNames[i] );
251 if( field >= 1 )
253 m_data[m_rowCount-1][i] <<= xRow->getString( field );
254 // printf( "adding %s %s\n" ,
255 // OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(),
256 // OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() );
261 else
263 // do the best we can ( DEFAULT and AUTO increment values fail ! )
264 for( int i = 0 ; i < m_fieldCount ; i ++ )
266 if( m_updateableField[i].isTouched )
267 m_data[m_rowCount-1][i] = m_updateableField[i].value;
272 // cleanup
273 m_updateableField = UpdateableFieldVector();
276 void UpdateableResultSet::updateRow( )
278 MutexGuard guard( m_xMutex->GetMutex() );
279 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called");
281 if( m_insertRow )
282 throw SQLException(
283 "pq_resultset.updateRow: moveToCurrentRow has not been called !",
284 *this, OUString(), 1, Any() );
286 OUStringBuffer buf( 128 );
287 buf.append( "UPDATE " );
288 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
289 buf.append( "SET " );
291 int columns = 0;
292 for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
294 if( m_updateableField[i].isTouched )
296 if( columns > 0 )
297 buf.append( ", " );
298 columns ++;
300 buf.append( m_columnNames[i] );
301 buf.append( " = " );
302 bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings );
303 // OUString val;
304 // m_updateableField[i].value >>= val;
305 // bufferQuoteConstant( buf, val ):
306 // buf.append( val );
309 buf.append( buildWhereClause() );
311 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
312 DisposeGuard dispGuard( stmt );
313 stmt->executeUpdate( buf.makeStringAndClear() );
315 // reflect the changes !
316 for( int i = 0 ; i < m_fieldCount ; i ++ )
318 if( m_updateableField[i].isTouched )
319 m_data[m_row][i] = m_updateableField[i].value;
321 m_updateableField = UpdateableFieldVector();
324 void UpdateableResultSet::deleteRow( )
326 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called");
328 if( m_insertRow )
329 throw SQLException(
330 "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
331 *this, OUString(), 1, Any() );
333 if( m_row < 0 || m_row >= m_rowCount )
335 throw SQLException(
336 "deleteRow cannot be called on invalid row ("
337 + OUString::number(m_row) + ")",
338 *this, OUString(), 0, Any() );
341 Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement();
342 DisposeGuard dispGuard( stmt );
343 OUStringBuffer buf( 128 );
344 buf.append( "DELETE FROM " );
345 bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings );
346 buf.append( " " );
347 buf.append( buildWhereClause() );
349 stmt->executeUpdate( buf.makeStringAndClear() );
351 // reflect the changes !
352 for( int i = m_row + 1; i < m_row ; i ++ )
354 m_data[i-1] = m_data[i];
356 m_rowCount --;
357 m_data.resize( m_rowCount );
360 void UpdateableResultSet::cancelRowUpdates( )
362 MutexGuard guard( m_xMutex->GetMutex() );
363 m_updateableField = UpdateableFieldVector();
366 void UpdateableResultSet::moveToInsertRow( )
368 m_insertRow = true;
371 void UpdateableResultSet::moveToCurrentRow( )
373 m_insertRow = false;
376 void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
378 checkColumnIndex( columnIndex );
379 if( m_updateableField.empty() )
380 m_updateableField = UpdateableFieldVector( m_fieldCount );
381 m_updateableField[columnIndex-1].isTouched = true;
384 void UpdateableResultSet::updateNull( sal_Int32 columnIndex )
386 MutexGuard guard( m_xMutex->GetMutex() );
387 checkClosed();
388 checkUpdate( columnIndex );
389 m_updateableField[columnIndex-1].value = Any();
392 void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
394 MutexGuard guard( m_xMutex->GetMutex() );
395 checkClosed();
396 checkUpdate( columnIndex );
398 Statics &st = getStatics();
399 m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
403 void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
405 updateInt(columnIndex,x);
408 void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
410 updateInt( columnIndex, x );
413 void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
415 updateLong( columnIndex, x );
416 // MutexGuard guard( m_xMutex->GetMutex() );
417 // checkClosed();
418 // checkUpdate( columnIndex );
420 // m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
424 void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
426 MutexGuard guard( m_xMutex->GetMutex() );
427 checkClosed();
428 checkUpdate( columnIndex );
430 // OStringBuffer buf( 20 );
431 // buf.append( "'" );
432 // buf.append( (sal_Int64) x );
433 // buf.append( "'" );
434 m_updateableField[columnIndex-1].value <<= OUString::number( x );
437 void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x )
440 MutexGuard guard( m_xMutex->GetMutex() );
441 checkClosed();
442 checkUpdate( columnIndex );
444 m_updateableField[columnIndex-1].value <<= OUString::number( x );
447 void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x )
449 MutexGuard guard( m_xMutex->GetMutex() );
450 checkClosed();
451 checkUpdate( columnIndex );
453 m_updateableField[columnIndex-1].value <<= OUString::number( x );
456 void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
458 MutexGuard guard( m_xMutex->GetMutex() );
459 checkClosed();
460 checkUpdate( columnIndex );
462 m_updateableField[columnIndex-1].value <<= x;
465 void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
467 MutexGuard guard( m_xMutex->GetMutex() );
468 checkClosed();
469 checkUpdate( columnIndex );
471 size_t len;
472 unsigned char * escapedString =
473 PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
474 if( ! escapedString )
476 throw SQLException(
477 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
478 *this, OUString(), 1, Any() );
480 // buf.append( (const char *)escapedString, len -1 );
482 m_updateableField[columnIndex-1].value <<=
483 OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US );
484 PQfreemem( escapedString );
487 void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
489 updateString( columnIndex, DBTypeConversion::toDateString( x ) );
492 void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
494 updateString( columnIndex, DBTypeConversion::toTimeString( x ) );
497 void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
499 updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) );
502 void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
506 void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
510 void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
514 void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
519 Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable )
521 if( updateable )
523 cppu::OTypeCollection collection(
524 cppu::UnoType<XResultSetUpdate>::get(),
525 cppu::UnoType<XRowUpdate>::get(),
526 // cppu::UnoType<css::sdbcx::XRowLocate>::get(),
527 getStaticTypes( false /* updateable */ ) );
528 return collection.getTypes();
530 else
532 cppu::OTypeCollection collection(
533 cppu::UnoType<XResultSet>::get(),
534 cppu::UnoType<XResultSetMetaDataSupplier>::get(),
535 cppu::UnoType<XRow>::get(),
536 cppu::UnoType<XColumnLocate>::get(),
537 cppu::UnoType<XCloseable>::get(),
538 cppu::UnoType<XPropertySet>::get(),
539 cppu::UnoType<XFastPropertySet>::get(),
540 cppu::UnoType<XMultiPropertySet>::get(),
541 cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper
542 cppu::UnoType<css::lang::XTypeProvider>::get(),
543 cppu::UnoType<css::uno::XAggregation>::get(),
544 cppu::UnoType<css::uno::XWeak>::get());
545 return collection.getTypes();
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */