LibreOffice Module connectivity (master) 1
pq_updateableresultset.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*************************************************************************
3 *
4 * Effective License of whole file:
5 *
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.
9 *
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.
14 *
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
19 *
20 * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011:
21 *
22 * The Contents of this file are made available subject to the terms of
23 * the GNU Lesser General Public License Version 2.1
24 *
25 * Copyright: 200? by Sun Microsystems, Inc.
26 *
27 * Contributor(s): Joerg Budischewski
28 *
29 * All parts contributed on or after August 2011:
30 *
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/.
34 *
35 ************************************************************************/
36
37#include <sal/log.hxx>
38#include <rtl/ref.hxx>
39#include <rtl/ustrbuf.hxx>
40
43#include <com/sun/star/sdbc/SQLException.hpp>
44#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
45
48#include "pq_tools.hxx"
49#include "pq_statics.hxx"
50
51#include <string.h>
52
54
55using osl::MutexGuard;
56
57
60using com::sun::star::uno::UNO_QUERY;
61using com::sun::star::uno::Any;
62using com::sun::star::uno::Type;
63
64using com::sun::star::sdbc::XGeneratedResultSet;
65using com::sun::star::sdbc::XResultSetMetaDataSupplier;
66using com::sun::star::sdbc::SQLException;
67using com::sun::star::sdbc::XResultSet;
68using com::sun::star::sdbc::XCloseable;
69using com::sun::star::sdbc::XColumnLocate;
70using com::sun::star::sdbc::XResultSetUpdate;
71using com::sun::star::sdbc::XRowUpdate;
72using com::sun::star::sdbc::XRow;
73using com::sun::star::sdbc::XStatement;
74
75using com::sun::star::beans::XFastPropertySet;
77using com::sun::star::beans::XMultiPropertySet;
78
79using namespace dbtools;
80
81namespace pq_sdbc_driver
82{
83
84
85css::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 )
93{
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 ++ )
98 {
99 char * name = PQfname( result, i );
100 columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding );
101 }
102 std::vector< std::vector< Any > > data( rowCount );
103
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 ++ )
107 {
108 std::vector< Any > aRow( columnCount );
109 for( int col = 0 ; col < columnCount ; col ++ )
110 {
111 if( ! PQgetisnull( result, row, col ) )
112 {
113 char * val = PQgetvalue( result, row, col );
114
115 aRow[col] <<=
116 OUString( val, strlen( val ), ConnectionSettings::encoding );
117 }
118 }
119 data[row] = aRow;
120 }
121
123 mutex, owner, std::move(columnNames), std::move(data), ppSettings, schema, table, std::move(primaryKey) );
124
125 pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table );
126
127 PQclear( result ); // we don't need it anymore
128
129 return pRS;
130}
131
133 const css::uno::Type & reqType )
134{
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;
142}
143
144
145css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes()
146{
147 static cppu::OTypeCollection collection(
151
152 return collection.getTypes();
153
154}
155
156css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId()
157{
158 return css::uno::Sequence<sal_Int8>();
159}
160
162{
163 OUString ret;
164 if( !m_primaryKey.empty() )
165 {
166 OUStringBuffer buf( 128 );
167 buf.append( " WHERE " );
168 for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ )
169 {
170 if( i > 0 )
171 buf.append( " AND " );
172 sal_Int32 index = findColumn( m_primaryKey[i] );
174 buf.append( " = " );
176 }
177 ret = buf.makeStringAndClear();
178 }
179 return ret;
180}
181
182
184{
185 MutexGuard guard( m_xMutex->GetMutex() );
186 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called");
187
188 if( ! m_insertRow )
189 throw SQLException(
190 "pq_resultset.insertRow: moveToInsertRow has not been called !",
191 *this, OUString(), 1, Any() );
192
193 OUStringBuffer buf( 128 );
194 buf.append( "INSERT INTO " );
196 buf.append( " ( " );
197
198 int columns = 0;
199 for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ )
200 {
201 if( m_updateableField[i].isTouched )
202 {
203 if( columns > 0 )
204 buf.append( ", " );
205 columns ++;
207 }
208 }
209 buf.append( " ) VALUES ( " );
210
211 columns = 0;
212 for(const UpdateableField & i : m_updateableField)
213 {
214 if( i.isTouched )
215 {
216 if( columns > 0 )
217 buf.append( " , " );
218 columns ++;
219 bufferQuoteAnyConstant( buf, i.value, *m_ppSettings );
220
221// OUString val;
222// m_updateableField[i].value >>= val;
223// buf.append( val );
224// OStringToOUString(val, (*m_ppSettings)->encoding ) );
225 }
226 }
227
228 buf.append( " )" );
229
231 extractConnectionFromStatement(m_owner)->createStatement();
232 DisposeGuard dispGuard( stmt );
233 stmt->executeUpdate( buf.makeStringAndClear() );
234
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() )
241 {
242 Reference< XResultSet > rs = result->getGeneratedValues();
243 if( rs.is() && rs->next() )
244 {
245 Reference< XColumnLocate > columnLocate( rs, UNO_QUERY );
246 Reference< XRow> xRow ( rs, UNO_QUERY );
247 for( int i = 0 ; i < m_fieldCount ; i++ )
248 {
249 int field = columnLocate->findColumn( m_columnNames[i] );
250 if( field >= 1 )
251 {
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() );
256
257 }
258 }
259 }
260 else
261 {
262 // do the best we can ( DEFAULT and AUTO increment values fail ! )
263 for( int i = 0 ; i < m_fieldCount ; i ++ )
264 {
265 if( m_updateableField[i].isTouched )
267 }
268 }
269 }
270
271 // cleanup
273}
274
276{
277 MutexGuard guard( m_xMutex->GetMutex() );
278 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called");
279
280 if( m_insertRow )
281 throw SQLException(
282 "pq_resultset.updateRow: moveToCurrentRow has not been called !",
283 *this, OUString(), 1, Any() );
284
285 OUStringBuffer buf( 128 );
286 buf.append( "UPDATE " );
288 buf.append( "SET " );
289
290 int columns = 0;
291 for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ )
292 {
293 if( m_updateableField[i].isTouched )
294 {
295 if( columns > 0 )
296 buf.append( ", " );
297 columns ++;
298
299 buf.append( m_columnNames[i]
300 + " = " );
302// OUString val;
303// m_updateableField[i].value >>= val;
304// bufferQuoteConstant( buf, val ):
305// buf.append( val );
306 }
307 }
308 buf.append( buildWhereClause() );
309
311 DisposeGuard dispGuard( stmt );
312 stmt->executeUpdate( buf.makeStringAndClear() );
313
314 // reflect the changes !
315 for( int i = 0 ; i < m_fieldCount ; i ++ )
316 {
317 if( m_updateableField[i].isTouched )
318 m_data[m_row][i] = m_updateableField[i].value;
319 }
321}
322
324{
325 SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called");
326
327 if( m_insertRow )
328 throw SQLException(
329 "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !",
330 *this, OUString(), 1, Any() );
331
332 if( m_row < 0 || m_row >= m_rowCount )
333 {
334 throw SQLException(
335 "deleteRow cannot be called on invalid row ("
336 + OUString::number(m_row) + ")",
337 *this, OUString(), 0, Any() );
338 }
339
341 DisposeGuard dispGuard( stmt );
342 OUStringBuffer buf( 128 );
343 buf.append( "DELETE FROM " );
345 buf.append( " "
346 + buildWhereClause() );
347
348 stmt->executeUpdate( buf.makeStringAndClear() );
349
350 // reflect the changes !
351 for( int i = m_row + 1; i < m_row ; i ++ )
352 {
353 m_data[i-1] = m_data[i];
354 }
355 m_rowCount --;
356 m_data.resize( m_rowCount );
357 }
358
360{
361 MutexGuard guard( m_xMutex->GetMutex() );
363}
364
366{
367 m_insertRow = true;
368}
369
371{
372 m_insertRow = false;
373}
374
375void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex)
376{
377 checkColumnIndex( columnIndex );
378 if( m_updateableField.empty() )
380 m_updateableField[columnIndex-1].isTouched = true;
381}
382
383void UpdateableResultSet::updateNull( sal_Int32 columnIndex )
384{
385 MutexGuard guard( m_xMutex->GetMutex() );
386 checkClosed();
387 checkUpdate( columnIndex );
388 m_updateableField[columnIndex-1].value = Any();
389}
390
391void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
392{
393 MutexGuard guard( m_xMutex->GetMutex() );
394 checkClosed();
395 checkUpdate( columnIndex );
396
397 Statics &st = getStatics();
398 m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE );
399
400}
401
402void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
403{
404 updateInt(columnIndex,x);
405}
406
407void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
408{
409 updateInt( columnIndex, x );
410}
411
412void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
413{
414 updateLong( columnIndex, x );
415// MutexGuard guard( m_xMutex->GetMutex() );
416// checkClosed();
417// checkUpdate( columnIndex );
418
419// m_updateableField[columnIndex-1].value <<= OUString::valueOf( x );
420
421}
422
423void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
424{
425 MutexGuard guard( m_xMutex->GetMutex() );
426 checkClosed();
427 checkUpdate( columnIndex );
428
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 );
434}
435
436void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x )
437{
438
439 MutexGuard guard( m_xMutex->GetMutex() );
440 checkClosed();
441 checkUpdate( columnIndex );
442
443 m_updateableField[columnIndex-1].value <<= OUString::number( x );
444}
445
446void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x )
447{
448 MutexGuard guard( m_xMutex->GetMutex() );
449 checkClosed();
450 checkUpdate( columnIndex );
451
452 m_updateableField[columnIndex-1].value <<= OUString::number( x );
453}
454
455void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
456{
457 MutexGuard guard( m_xMutex->GetMutex() );
458 checkClosed();
459 checkUpdate( columnIndex );
460
461 m_updateableField[columnIndex-1].value <<= x;
462}
463
464void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x )
465{
466 MutexGuard guard( m_xMutex->GetMutex() );
467 checkClosed();
468 checkUpdate( columnIndex );
469
470 size_t len;
471 unsigned char * escapedString =
472 PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len);
473 if( ! escapedString )
474 {
475 throw SQLException(
476 "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string",
477 *this, OUString(), 1, Any() );
478 }
479// buf.append( (const char *)escapedString, len -1 );
480
481 m_updateableField[columnIndex-1].value <<=
482 OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US );
483 PQfreemem( escapedString );
484}
485
486void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
487{
489}
490
491void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
492{
494}
495
496void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
497{
499}
500
501void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
502{
503}
504
505void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ )
506{
507}
508
509void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ )
510{
511}
512
513void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ )
514{
515}
516
517
519{
520 if( updateable )
521 {
522 cppu::OTypeCollection collection(
525// cppu::UnoType<css::sdbcx::XRowLocate>::get(),
526 getStaticTypes( false /* updateable */ ) );
527 return collection.getTypes();
528 }
529 else
530 {
531 cppu::OTypeCollection collection(
540 cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper
544 return collection.getTypes();
545 }
546}
547
548}
549
550/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
css::uno::Reference< css::uno::XInterface > m_owner
::rtl::Reference< comphelper::RefCountedMutex > m_xMutex
void checkColumnIndex(sal_Int32 index)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &reqType) override
virtual OUString SAL_CALL getString(sal_Int32 columnIndex) override
std::vector< std::vector< css::uno::Any > > m_data
virtual void checkClosed() override
mutex should be locked before called
virtual sal_Int32 SAL_CALL findColumn(const OUString &columnName) override
static css::uno::Reference< css::sdbc::XCloseable > createFromPGResultSet(const ::rtl::Reference< comphelper::RefCountedMutex > &mutex, const css::uno::Reference< css::uno::XInterface > &owner, ConnectionSettings **ppSettings, PGresult *result, const OUString &schema, const OUString &table, std::vector< OUString > &&primaryKey)
virtual void SAL_CALL updateString(sal_Int32 columnIndex, const OUString &x) override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &reqType) override
virtual void SAL_CALL updateDouble(sal_Int32 columnIndex, double x) override
virtual void SAL_CALL updateRow() override
virtual void SAL_CALL updateNumericObject(sal_Int32 columnIndex, const css::uno::Any &x, sal_Int32 scale) override
virtual void SAL_CALL moveToCurrentRow() override
UpdateableResultSet(const ::rtl::Reference< comphelper::RefCountedMutex > &mutex, const css::uno::Reference< css::uno::XInterface > &owner, std::vector< OUString > &&colNames, std::vector< std::vector< css::uno::Any > > &&data, ConnectionSettings **ppSettings, OUString schema, OUString table, std::vector< OUString > &&primaryKey)
virtual void SAL_CALL updateByte(sal_Int32 columnIndex, sal_Int8 x) override
static css::uno::Sequence< css::uno::Type > getStaticTypes(bool updateable)
virtual void SAL_CALL updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime &x) override
virtual void SAL_CALL updateCharacterStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream > &x, sal_Int32 length) override
virtual void SAL_CALL updateObject(sal_Int32 columnIndex, const css::uno::Any &x) override
virtual void SAL_CALL deleteRow() override
virtual void SAL_CALL cancelRowUpdates() override
virtual void SAL_CALL updateDate(sal_Int32 columnIndex, const css::util::Date &x) override
virtual void SAL_CALL updateBoolean(sal_Int32 columnIndex, sal_Bool x) override
virtual void SAL_CALL updateInt(sal_Int32 columnIndex, sal_Int32 x) override
virtual void SAL_CALL insertRow() override
virtual void SAL_CALL updateLong(sal_Int32 columnIndex, sal_Int64 x) override
virtual void SAL_CALL updateFloat(sal_Int32 columnIndex, float x) override
virtual void SAL_CALL updateShort(sal_Int32 columnIndex, sal_Int16 x) override
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual void SAL_CALL moveToInsertRow() override
virtual void SAL_CALL updateBinaryStream(sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream > &x, sal_Int32 length) override
virtual void SAL_CALL updateTime(sal_Int32 columnIndex, const css::util::Time &x) override
virtual void SAL_CALL updateNull(sal_Int32 columnIndex) override
virtual void SAL_CALL updateBytes(sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 > &x) override
Any value
float x
#define SAL_INFO(area, stream)
RttiCompleteObjectLocator col
@ table
class SAL_NO_VTABLE XPropertySet
OOO_DLLPUBLIC_DBTOOLS OUString toTimeString(const css::util::Time &rTime)
OOO_DLLPUBLIC_DBTOOLS OUString toDateString(const css::util::Date &rDate)
OOO_DLLPUBLIC_DBTOOLS OUString toDateTimeString(const css::util::DateTime &_rDateTime)
int i
index
void bufferQuoteConstant(OUStringBuffer &buf, std::u16string_view value, ConnectionSettings *settings)
Definition: pq_tools.cxx:138
Statics & getStatics()
Definition: pq_statics.cxx:112
void bufferQuoteQualifiedIdentifier(OUStringBuffer &buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings)
Definition: pq_tools.cxx:181
std::vector< UpdateableField > UpdateableFieldVector
void bufferQuoteAnyConstant(OUStringBuffer &buf, const Any &val, ConnectionSettings *settings)
Definition: pq_tools.cxx:143
Reference< XConnection > extractConnectionFromStatement(const Reference< XInterface > &stmt)
Definition: pq_tools.cxx:248
void bufferQuoteIdentifier(OUStringBuffer &buf, std::u16string_view toQuote, ConnectionSettings *settings)
Definition: pq_tools.cxx:175
OUString name
Definition: pq_statics.cxx:74
static const rtl_TextEncoding encoding
std::mutex mutex
unsigned char sal_Bool
signed char sal_Int8
Any result