LibreOffice Module connectivity (master) 1
pq_statement.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: 2000 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 "pq_statement.hxx"
41#include "pq_tools.hxx"
42#include "pq_statics.hxx"
43
44#include <osl/time.h>
45
46#include <rtl/ustrbuf.hxx>
47
49
50#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
51#include <com/sun/star/sdbc/ResultSetType.hpp>
52#include <com/sun/star/sdbc/SQLException.hpp>
53#include <com/sun/star/sdbc/XParameters.hpp>
54
55#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
56#include <com/sun/star/sdbcx/KeyType.hpp>
57#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
58
59#include <com/sun/star/container/XIndexAccess.hpp>
60#include <com/sun/star/container/XEnumerationAccess.hpp>
61
62#include <cstddef>
63#include <string.h>
64#include <string_view>
65
66using osl::MutexGuard;
67
68
69using com::sun::star::uno::Any;
70using com::sun::star::uno::Type;
73using com::sun::star::uno::XInterface;
74using com::sun::star::uno::UNO_QUERY;
75
76using com::sun::star::lang::IllegalArgumentException;
77
78using com::sun::star::sdbc::XCloseable;
79using com::sun::star::sdbc::XStatement;
80using com::sun::star::sdbc::XPreparedStatement;
81using com::sun::star::sdbc::XParameters;
82using com::sun::star::sdbc::XRow;
83using com::sun::star::sdbc::XResultSet;
84using com::sun::star::sdbc::XConnection;
85using com::sun::star::sdbc::SQLException;
86
87using com::sun::star::sdbcx::XColumnsSupplier;
88using com::sun::star::sdbcx::XKeysSupplier;
89
90using com::sun::star::beans::Property;
91using com::sun::star::beans::XPropertySetInfo;
93
94using com::sun::star::container::XNameAccess;
95using com::sun::star::container::XEnumerationAccess;
96using com::sun::star::container::XEnumeration;
97using com::sun::star::container::XIndexAccess;
98
99namespace pq_sdbc_driver
100{
101static ::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper()
102{
103 static ::cppu::OPropertyArrayHelper arrayHelper(
105 Property(
106 "CursorName", 0,
108 Property(
109 "EscapeProcessing", 1,
111 Property(
112 "FetchDirection", 2,
114 Property(
115 "FetchSize", 3,
117 Property(
118 "MaxFieldSize", 4,
120 Property(
121 "MaxRows", 5,
123 Property(
124 "QueryTimeOut", 6,
126 Property(
127 "ResultSetConcurrency", 7,
129 Property(
130 "ResultSetType", 8,
132 true );
133
134 return arrayHelper;
135}
136
137Statement::Statement( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex,
138 const Reference< XConnection > & conn,
139 struct ConnectionSettings *pSettings )
140 : Statement_BASE( refMutex->GetMutex() )
141 , OPropertySetHelper( Statement_BASE::rBHelper )
142 , m_connection( conn )
143 , m_pSettings( pSettings )
144 , m_xMutex( refMutex )
145 , m_multipleResultAvailable(false)
146 , m_multipleResultUpdateCount(0)
147 , m_lastOidInserted(InvalidOid)
148{
149 m_props[STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0);
150 m_props[STATEMENT_MAX_ROWS] <<= sal_Int32(0);
152 css::sdbc::ResultSetConcurrency::READ_ONLY;
154 css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
155}
156
158{
159}
160
162{
164 throw SQLException(
165 "pq_driver: Statement or connection has already been closed !",
166 *this, OUString(),1,Any());
167}
168
170{
171 Any aRet = Statement_BASE::queryInterface(rType);
172 return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
173}
174
175
177{
178 static Sequence< Type > collection(
179 ::comphelper::concatSequences(
180 OPropertySetHelper::getTypes(),
181 Statement_BASE::getTypes()));
182
183 return collection;
184}
185
187{
188 return css::uno::Sequence<sal_Int8>();
189}
190
192{
193 // let the connection die without acquired mutex !
195 Reference< XCloseable > resultSet;
196 {
197 MutexGuard guard( m_xMutex->GetMutex() );
198 m_pSettings = nullptr;
199 r = m_connection;
200 m_connection.clear();
201
202 resultSet = m_lastResultset;
203 m_lastResultset.clear();
204 }
205 if( resultSet.is() )
206 {
207 resultSet->close();
208 }
209
210}
211
213 std::u16string_view sql, const char * errorMsg )
214{
215 OUString error = "pq_driver: "
216 + OUString( errorMsg, strlen(errorMsg), ConnectionSettings::encoding )
217 + " (caused by statement '" + sql + "')";
218 SAL_WARN("connectivity.postgresql", error);
219 throw SQLException( error, *this, OUString(), 1, Any() );
220}
221
223{
224 if( ! execute( sql ) )
225 {
226 raiseSQLException( sql, "not a query" );
227 }
228 return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
229}
230
231sal_Int32 Statement::executeUpdate( const OUString& sql )
232{
233 if( execute( sql ) )
234 {
235 raiseSQLException( sql, "not a command" );
236 }
238}
239
242 const Reference< XInterface> & owner,
243 std::string_view sql,
244 const char * errorMsg,
245 const char *errorType = nullptr )
246{
247 OUStringBuffer buf(128);
248 buf.append( "pq_driver: ");
249 if( errorType )
250 {
251 buf.append( "[" );
252 buf.appendAscii( errorType );
253 buf.append( "]" );
254 }
255 buf.append(
256 OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding )
257 + " (caused by statement '"
258 + OStringToOUString( sql, ConnectionSettings::encoding )
259 + "')" );
260 OUString error = buf.makeStringAndClear();
261 SAL_WARN("connectivity.postgresql", error);
262 throw SQLException( error, owner, OUString(), 1, Any() );
263}
264
265
266// returns the elements of the primary key of the given table
267// static Sequence< Reference< css::beans::XPropertySet > > lookupKeys(
268static std::vector< OUString > lookupKeys(
270 const OUString & table,
271 OUString *pSchema,
272 OUString *pTable)
273{
274 std::vector< OUString > ret;
275 Reference< XKeysSupplier > keySupplier;
276 Statics & st = getStatics();
277
278 if( tables->hasByName( table ) )
279 tables->getByName( table ) >>= keySupplier;
280 else if( -1 == table.indexOf( '.' ) )
281 {
282 // it wasn't a fully qualified name. Now need to skip through all tables.
283 Reference< XEnumerationAccess > enumerationAccess( tables, UNO_QUERY );
284
286 enumerationAccess->createEnumeration();
287 while( enumeration->hasMoreElements() )
288 {
290 enumeration->nextElement() >>= set;
291 OUString name;
292// OUString schema;
293
294 if( set->getPropertyValue( st.NAME ) >>= name )
295 {
296// printf( "searching %s %s\n",
297// OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(),
298// OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
299 if( name == table )
300 {
301
302 if( keySupplier.is() )
303 {
304 // is ambiguous, as I don't know postgresql searchpath,
305 // I can't continue here, as I may write to a different table
306 keySupplier.clear();
307 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity");
308 break;
309 }
310 keySupplier.set( set, UNO_QUERY );
311 }
312 }
313 }
314 }
315 else
316 {
317 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " is unknown)");
318 }
319
320 if( keySupplier.is() )
321 {
322 Reference< XPropertySet > set( keySupplier, UNO_QUERY );
323 set->getPropertyValue( getStatics().NAME ) >>= *pTable;
324 set->getPropertyValue( getStatics().SCHEMA_NAME ) >>= *pSchema;
325 set.clear();
326
327 Reference< XEnumerationAccess > keys ( keySupplier->getKeys(), UNO_QUERY );
328 Reference< XEnumeration > enumeration = keys->createEnumeration();
329 while( enumeration->hasMoreElements() )
330 {
331 enumeration->nextElement() >>= set;
332 sal_Int32 keyType = 0;
333 if( (set->getPropertyValue( st.TYPE ) >>= keyType ) &&
334 keyType == css::sdbcx::KeyType::PRIMARY )
335 {
336 Reference< XColumnsSupplier > columns( set, UNO_QUERY );
337 Reference< XIndexAccess > indexAccess( columns->getColumns(), UNO_QUERY );
338
339 int length = indexAccess->getCount();
340 ret.resize( length );
341// printf( "primary key for Table %s is ",
342// OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() );
343 for( int i = 0 ; i < length ; i ++ )
344 {
345 indexAccess->getByIndex( i ) >>= set;
346 OUString name;
347 set->getPropertyValue( st.NAME ) >>= name;
348 ret[i] = name;
349// printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() );
350 }
351// printf( "\n" );
352 }
353 }
354 if( ret.empty() )
355 {
356 SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)");
357 }
358 }
359 return ret;
360}
361
362bool executePostgresCommand( const OString & cmd, struct CommandData *data )
363{
364 ConnectionSettings *pSettings = *(data->ppSettings);
365
366 sal_Int32 duration = osl_getGlobalTimer();
367 PGresult *result = PQexec( pSettings->pConnection, cmd.getStr() );
368 duration = osl_getGlobalTimer() - duration;
369 if( ! result )
371 data->owner, cmd, PQerrorMessage( pSettings->pConnection ) );
372
373 ExecStatusType state = PQresultStatus( result );
374 *(data->pLastOidInserted) = 0;
375 data->pLastTableInserted->clear();
376 *(data->pLastQuery) = cmd;
377
378 bool ret = false;
379 switch( state )
380 {
381 case PGRES_COMMAND_OK:
382 {
383 *(data->pMultipleResultUpdateCount) = atoi( PQcmdTuples( result ) );
384 *(data->pMultipleResultAvailable) = false;
385
386 // in case an oid value is available, we retrieve it
387 *(data->pLastOidInserted) = PQoidValue( result );
388
389 // in case it was a single insert, extract the name of the table,
390 // otherwise the table name is empty
391 *(data->pLastTableInserted) =
392 extractTableFromInsert( OStringToOUString( cmd, ConnectionSettings::encoding ) );
393
394 OString strMain = "executed command '" + cmd + "' successfully ('" + OString::number(*( data->pMultipleResultUpdateCount ))
395 + "), duration=" + OString::number(duration) + "ms";
396
397 OString strOption;
398 if( *(data->pLastOidInserted) )
399 {
400 strOption += ", usedOid=" + OString::number( *(data->pLastOidInserted) ) + ", diagnosedTable="
402 }
403 SAL_INFO("connectivity.postgresql", strMain + strOption);
404 PQclear( result );
405 break;
406 }
407 case PGRES_TUPLES_OK: // success
408 {
409 // In case it is a single table, it has a primary key and all columns
410 // belonging to the primary key are in the result set, allow updateable result sets
411 // otherwise, don't
412 OUString table, schema;
413 std::vector< OString > vec;
414 tokenizeSQL( cmd, vec );
415 OUString sourceTable =
416 OStringToOUString(
418
419 if( data->concurrency ==
420 css::sdbc::ResultSetConcurrency::UPDATABLE )
421 {
422 OString aReason;
423 if( sourceTable.getLength() )
424 {
425 std::vector< OUString > sourceTableKeys = lookupKeys(
426 pSettings->tables.is() ?
427 pSettings->tables : data->tableSupplier->getTables() ,
428 sourceTable,
429 &schema,
430 &table);
431
432 // check, whether the columns are in the result set (required !)
433 std::size_t i;
434 for( i = 0 ; i < sourceTableKeys.size() ; i ++ )
435 {
436 if( -1 == PQfnumber(
437 result,
438 OUStringToOString( sourceTableKeys[i] ,
439 ConnectionSettings::encoding ).getStr()) )
440 {
441 break;
442 }
443 }
444
445 if( !sourceTableKeys.empty() && i == sourceTableKeys.size() )
446 {
447 *(data->pLastResultset) =
449 data->refMutex, data->owner, data->ppSettings, result,
450 schema, table, std::move(sourceTableKeys) );
451 }
452 else if( ! table.getLength() )
453 {
454 aReason = "can't support updateable resultset, because a single table in the "
455 "WHERE part of the statement could not be identified (" + cmd + ".";
456 }
457 else if( !sourceTableKeys.empty() )
458 {
459 aReason = "can't support updateable resultset for table "
462 + ", because resultset does not contain a part of the primary key ( column "
464 + " is missing )";
465 }
466 else
467 {
468
469 aReason = "can't support updateable resultset for table "
472 + ", because resultset table does not have a primary key ";
473 }
474 }
475 else
476 {
477 SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd << ")");
478 }
479 if( ! (*(data->pLastResultset)).is() )
480 {
481 SAL_WARN("connectivity.postgresql", aReason);
482
483 // TODO: How to react here correctly ?
484 // remove this piece of code
485 *(data->pLastResultset) =
487 data->refMutex, data->owner,
488 data->ppSettings,result, schema, table,
489 OStringToOUString( aReason, ConnectionSettings::encoding) );
490 }
491
492 }
493 else if( sourceTable.getLength() > 0)
494 {
495 splitConcatenatedIdentifier( sourceTable, &schema, &table );
496 }
497
498 sal_Int32 returnedRows = PQntuples( result );
499 if( ! data->pLastResultset->is() )
500 *(data->pLastResultset) =
502 new ResultSet(
503 data->refMutex, data->owner,
504 data->ppSettings,result, schema, table ) );
505 *(data->pMultipleResultAvailable) = true;
506 ret = true;
507 SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << ".");
508 break;
509 }
510 case PGRES_EMPTY_QUERY:
511 case PGRES_COPY_OUT:
512 case PGRES_COPY_IN:
513 case PGRES_BAD_RESPONSE:
514 case PGRES_NONFATAL_ERROR:
515 case PGRES_FATAL_ERROR:
516 default:
518 data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) );
519 }
520 return ret;
521
522}
523
525 const Reference< XConnection > & connection, const OUString &schemaName, const OUString &tableName )
526{
528
529 Int2StringMap mapIndex2Name;
530 fillAttnum2attnameMap( mapIndex2Name, connection, schemaName, tableName );
531
532 // retrieve the primary key ...
533 Reference< XPreparedStatement > stmt = connection->prepareStatement(
534 "SELECT conkey " // 7
535 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
536 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
537 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
538 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
539 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" );
540 DisposeGuard guard( stmt );
541 Reference< XParameters > paras( stmt, UNO_QUERY );
542 paras->setString( 1 , tableName );
543 paras->setString( 2 , schemaName );
544 Reference< XResultSet > rs = stmt->executeQuery();
545 Reference< XRow > xRow( rs , UNO_QUERY );
546
547 if( rs->next() )
548 {
549 ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) );
550 }
551 return ret;
552}
553
554static void getAutoValues(
555 String2StringMap & result,
556 const Reference< XConnection > & connection,
557 const OUString &schemaName,
558 const OUString & tableName,
559 const ConnectionSettings *pConnectionSettings )
560{
561 OUString strDefaultValue = getColExprForDefaultSettingVal(pConnectionSettings);
562 Reference< XPreparedStatement > stmt = connection->prepareStatement(
563 "SELECT pg_attribute.attname, " + strDefaultValue +
564 "FROM pg_class, pg_namespace, pg_attribute "
565 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
566 "pg_attribute.attnum = pg_attrdef.adnum "
567 "WHERE pg_attribute.attrelid = pg_class.oid AND "
568 "pg_class.relnamespace = pg_namespace.oid AND "
569 "pg_namespace.nspname = ? AND "
570 // LEM TODO: this is weird; why "LIKE" and not "="?
571 // Most probably gives problems if tableName contains '%'
572 "pg_class.relname LIKE ? AND "
573 + strDefaultValue + " != ''"
574 );
575 DisposeGuard guard( stmt );
576 Reference< XParameters > paras( stmt, UNO_QUERY );
577 paras->setString( 1 , schemaName );
578 paras->setString( 2 , tableName );
579 Reference< XResultSet > rs = stmt->executeQuery();
580 Reference< XRow > xRow( rs , UNO_QUERY );
581
582 while( rs->next() )
583 {
584 result[ OUStringToOString( xRow->getString( 1 ), RTL_TEXTENCODING_ASCII_US) ] =
585 OUStringToOString( xRow->getString(2), RTL_TEXTENCODING_ASCII_US );
586 }
587}
588
590 ConnectionSettings *pConnectionSettings,
591 const Reference< XConnection > &connection,
592 sal_Int32 nLastOid,
593 std::u16string_view lastTableInserted,
594 const OString & lastQuery )
595{
597 OUString query;
598 OUString schemaName, tableName;
600 lastTableInserted, &schemaName, &tableName );
601
602 if( nLastOid && lastTableInserted.size() )
603 {
604 OUStringBuffer buf( 128 );
605 buf.append( "SELECT * FROM " );
606 if( schemaName.getLength() )
607 bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings );
608 else
609 bufferQuoteIdentifier( buf, lastTableInserted, pConnectionSettings );
610 buf.append( " WHERE oid = " + OUString::number(nLastOid) );
611 query = buf.makeStringAndClear();
612 }
613 else if ( lastTableInserted.size() && lastQuery.getLength() )
614 {
615 // extract nameValue Pairs
616 String2StringMap namedValues;
617 extractNameValuePairsFromInsert( namedValues, lastQuery );
618
619 // debug ...
620// OStringBuffer buf( 128);
621// buf.append( "extracting name/value from '" );
622// buf.append( lastQuery.getStr() );
623// buf.append( "' to [" );
624// for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii )
625// {
626// buf.append( ii->first.getStr() );
627// buf.append( "=" );
628// buf.append( ii->second.getStr() );
629// buf.append( "," );
630// }
631// buf.append( "]\n" );
632// printf( "%s", buf.makeStringAndClear() );
633
634 // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path
635 // in postgresql doc
636
637 const Sequence< OUString > keyColumnNames = getPrimaryKeyColumnNames( connection, schemaName, tableName );
638 if( keyColumnNames.hasElements() )
639 {
640 OUStringBuffer buf( 128 );
641 buf.append( "SELECT * FROM " );
642 bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings );
643 buf.append( " WHERE " );
644 bool bAdditionalCondition = false;
645 String2StringMap autoValues;
646 for( OUString const & columnNameUnicode : keyColumnNames )
647 {
648 OUString value;
649 OString columnName = OUStringToOString( columnNameUnicode, ConnectionSettings::encoding );
650 bool bColumnMatchNamedValue = false;
651 for (auto const& namedValue : namedValues)
652 {
653 if( columnName.equalsIgnoreAsciiCase( namedValue.first ) )
654 {
655 value = OStringToOUString( namedValue.second , ConnectionSettings::encoding );
656 bColumnMatchNamedValue = true;
657 break;
658 }
659 }
660
661 // check, if a column of the primary key was not inserted explicitly,
662 if( !bColumnMatchNamedValue )
663 {
664 if( autoValues.empty() )
665 {
666 getAutoValues( autoValues, connection, schemaName, tableName, pConnectionSettings );
667 }
668 // this could mean, that the column is a default or auto value, check this ...
669 bool bColumnMatchAutoValue = false;
670 for (auto const& autoValue : autoValues)
671 {
672 if( columnName.equalsIgnoreAsciiCase( autoValue.first ) )
673 {
674 // it is indeed an auto value.
675 value = OStringToOUString(autoValue.second, RTL_TEXTENCODING_ASCII_US );
676 // check, whether it is a sequence
677
678 if( autoValue.second.startsWith("nextval(") )
679 {
680 // retrieve current sequence value:
681 OUStringBuffer myBuf(128 );
682 myBuf.append( "SELECT currval(" );
683 myBuf.appendAscii( &(autoValue.second.getStr()[8]));
684 value = querySingleValue( connection, myBuf.makeStringAndClear() );
685 }
686 bColumnMatchAutoValue = true;
687 break;
688 }
689 }
690 if( !bColumnMatchAutoValue )
691 {
692 // it even was no autovalue, no sense to continue as we can't query the
693 // inserted row
694 buf.truncate();
695 break;
696 }
697 }
698
699 if( bAdditionalCondition )
700 buf.append( " AND " );
701 bufferQuoteIdentifier( buf, columnNameUnicode, pConnectionSettings );
702 buf.append( " = " + value );
703 bAdditionalCondition = true;
704 }
705 query = buf.makeStringAndClear();
706 }
707 }
708
709 if( query.getLength() )
710 {
711 Reference< css::sdbc::XStatement > stmt = connection->createStatement();
712 ret = stmt->executeQuery( query );
713 }
714
715 return ret;
716
717}
718
720{
721 osl::MutexGuard guard( m_xMutex->GetMutex() );
722 checkClosed();
723 OString cmd = OUStringToOString( sql, m_pSettings );
724
725 Reference< XCloseable > lastResultSetHolder = m_lastResultset;
726 if( lastResultSetHolder.is() )
727 lastResultSetHolder->close();
728
729 m_lastResultset.clear();
730 m_lastTableInserted.clear();
731
732 struct CommandData data;
733 data.refMutex = m_xMutex;
734 data.ppSettings = &m_pSettings;
736 data.pLastQuery = &m_lastQuery;
741 data.owner = *this;
742 data.tableSupplier.set( m_connection, UNO_QUERY );
743 data.concurrency =
744 extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY );
745 return executePostgresCommand( cmd , &data );
746}
747
749{
751 {
752 MutexGuard guard( m_xMutex->GetMutex() );
753 checkClosed();
754 ret = m_connection;
755 }
756 return ret;
757}
758
759
761{
762 return Any();
763}
764
766{
767}
768
770{
773 if( supplier.is() )
774 ret = supplier->getMetaData();
775 return ret;
776}
777
778
780{
782}
783
784
786 Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
787{
788 rOldValue = m_props[nHandle];
789 bool bRet;
790 switch( nHandle )
791 {
793 {
794 OUString val;
795 bRet = ( rValue >>= val );
796 rConvertedValue <<= val;
797 break;
798 }
800 {
801 bool val(false);
802 bRet = ( rValue >>= val );
803 rConvertedValue <<= val;
804 break;
805 }
813 {
814 sal_Int32 val;
815 bRet = ( rValue >>= val );
816 rConvertedValue <<= val;
817 break;
818 }
819 default:
820 {
821 throw IllegalArgumentException(
822 "pq_statement: Invalid property handle ("
823 + OUString::number( nHandle ) + ")",
824 *this, 2 );
825 }
826 }
827 return bRet;
828}
829
830
832 sal_Int32 nHandle,const Any& rValue )
833{
834 m_props[nHandle] = rValue;
835}
836
837void Statement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
838{
839 rValue = m_props[nHandle];
840}
841
843{
844 return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() );
845}
846
847
849{
850 return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY );
851}
852
854{
856}
857
859{
860 // The PostgreSQL C interface always returns a single result,
861 // so we will never have multiple ones.
862 // Implicitly close the open resultset (if any) as per spec,
863 // and setup to signal "no more result, neither as resultset,
864 // nor as update count".
865 Reference< XCloseable > lastResultSetHolder = m_lastResultset;
866 if( lastResultSetHolder.is() )
867 lastResultSetHolder->close();
869 return false;
870}
871
872
874{
875 close();
876}
877
879{
880 osl::MutexGuard guard( m_xMutex->GetMutex() );
883}
884
885}
886
887/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
NAME
necessary to avoid crashes in OOo, when an updateable result set is requested, but cannot be delivere...
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet() override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &reqType) override
virtual void SAL_CALL close() override
sal_Int32 m_multipleResultUpdateCount
virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData() override
css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
css::uno::Reference< css::sdbc::XCloseable > m_lastResultset
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual void SAL_CALL disposing() override
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
ConnectionSettings * m_pSettings
virtual ~Statement() override
::rtl::Reference< comphelper::RefCountedMutex > m_xMutex
Statement(const rtl::Reference< comphelper::RefCountedMutex > &refMutex, const css::uno::Reference< css::sdbc::XConnection > &con, struct ConnectionSettings *pSettings)
virtual void SAL_CALL clearWarnings() override
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues() override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
virtual sal_Int32 SAL_CALL getUpdateCount() override
virtual sal_Bool SAL_CALL execute(const OUString &sql) override
css::uno::Any m_props[STATEMENT_SIZE]
virtual cppu::IPropertyArrayHelper &SAL_CALL getInfoHelper() override
virtual css::uno::Any SAL_CALL getWarnings() override
virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any &rConvertedValue, css::uno::Any &rOldValue, sal_Int32 nHandle, const css::uno::Any &rValue) override
void raiseSQLException(std::u16string_view sql, const char *errorMsg)
virtual sal_Int32 SAL_CALL executeUpdate(const OUString &sql) override
void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery(const OUString &sql) override
virtual sal_Bool SAL_CALL getMoreResults() override
css::uno::Reference< css::sdbc::XConnection > m_connection
virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection() 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)
Any value
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
@ table
void set(css::uno::UnoInterfaceReference const &value)
class SAL_NO_VTABLE XPropertySet
Type
int i
OString extractSingleTableFromSelect(const std::vector< OString > &vec)
Definition: pq_tools.cxx:732
const sal_Int32 STATEMENT_RESULT_SET_TYPE
Statics & getStatics()
Definition: pq_statics.cxx:112
const sal_Int32 STATEMENT_FETCH_SIZE
void bufferQuoteQualifiedIdentifier(OUStringBuffer &buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings)
Definition: pq_tools.cxx:181
OUString extractTableFromInsert(std::u16string_view sql)
Definition: pq_tools.cxx:318
static void getAutoValues(String2StringMap &result, const Reference< XConnection > &connection, const OUString &schemaName, const OUString &tableName, const ConnectionSettings *pConnectionSettings)
sal_Int32 extractIntProperty(const Reference< XPropertySet > &descriptor, const OUString &name)
Definition: pq_tools.cxx:220
const sal_Int32 STATEMENT_CURSOR_NAME
css::uno::Sequence< sal_Int32 > string2intarray(const OUString &str)
Definition: pq_tools.cxx:843
::cppu::WeakComponentImplHelper< css::sdbc::XStatement, css::sdbc::XCloseable, css::sdbc::XWarningsSupplier, css::sdbc::XMultipleResults, css::sdbc::XGeneratedResultSet, css::sdbc::XResultSetMetaDataSupplier > Statement_BASE
void tokenizeSQL(const OString &sql, std::vector< OString > &vec)
Definition: pq_tools.cxx:464
::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper()
const sal_Int32 STATEMENT_RESULT_SET_CONCURRENCY
static void raiseSQLException(const Reference< XInterface > &owner, std::string_view sql, const char *errorMsg, const char *errorType=nullptr)
const sal_Int32 STATEMENT_MAX_FIELD_SIZE
void extractNameValuePairsFromInsert(String2StringMap &map, const OString &lastQuery)
Definition: pq_tools.cxx:1080
OUString querySingleValue(const css::uno::Reference< css::sdbc::XConnection > &connection, const OUString &query)
Definition: pq_tools.cxx:1141
std::unordered_map< OString, OString > String2StringMap
Definition: pq_tools.hxx:139
void splitConcatenatedIdentifier(std::u16string_view source, OUString *first, OUString *second)
Definition: pq_tools.cxx:548
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
Definition: pq_tools.cxx:100
OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
Definition: pq_tools.cxx:836
static Sequence< OUString > getPrimaryKeyColumnNames(const Reference< XConnection > &connection, const OUString &schemaName, const OUString &tableName)
const sal_Int32 STATEMENT_ESCAPE_PROCESSING
static std::vector< OUString > lookupKeys(const Reference< css::container::XNameAccess > &tables, const OUString &table, OUString *pSchema, OUString *pTable)
Sequence< OUString > convertMappedIntArray2StringArray(const Int2StringMap &map, const Sequence< sal_Int32 > &intArray)
Definition: pq_tools.cxx:917
void bufferQuoteIdentifier(OUStringBuffer &buf, std::u16string_view toQuote, ConnectionSettings *settings)
Definition: pq_tools.cxx:175
const sal_Int32 STATEMENT_FETCH_DIRECTION
Reference< XResultSet > getGeneratedValuesFromLastInsert(ConnectionSettings *pConnectionSettings, const Reference< XConnection > &connection, sal_Int32 nLastOid, std::u16string_view lastTableInserted, const OString &lastQuery)
bool executePostgresCommand(const OString &cmd, struct CommandData *data)
std::unordered_map< sal_Int32, OUString > Int2StringMap
const sal_Int32 STATEMENT_QUERY_TIME_OUT
const sal_Int32 STATEMENT_MAX_ROWS
void fillAttnum2attnameMap(Int2StringMap &map, const Reference< css::sdbc::XConnection > &conn, const OUString &schema, const OUString &table)
Definition: pq_tools.cxx:707
store_handle_type *SAL_CALL query(OStoreObject *pHandle, store_handle_type *)
const char * columnName
Definition: pq_statics.cxx:56
OUString name
Definition: pq_statics.cxx:74
const char * tableName
Definition: pq_statics.cxx:57
sal_Int32 nHandle
css::uno::Reference< css::uno::XInterface > owner
sal_Int32 * pMultipleResultUpdateCount
css::uno::Reference< css::sdbc::XCloseable > * pLastResultset
::rtl::Reference< comphelper::RefCountedMutex > refMutex
ConnectionSettings ** ppSettings
css::uno::Reference< css::sdbcx::XTablesSupplier > tableSupplier
css::uno::Reference< css::container::XNameAccess > tables
static const rtl_TextEncoding encoding
unsigned char sal_Bool
Any result